Hi, do you guys ever work with Verhoeff check digit algorithm (https://en.wikipedia.org/wiki/Verhoeff_algorithm) with SAS? I am trying to use sas for verhoeff check digit but havent found any script to do so.
You're welcome. Only a few small changes (highlighted in bold below) to the previous code are needed to create a new function VCDVAL that returns 1 if the last digit of the argument is the correct Verhoeff check digit and 0 otherwise:
/* Validate a check digit from a digit string S according to the Verhoeff algorithm, using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */ proc fcmp outlib=work.funcs.test; function vcdval(s $); array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 2 3 4 0 6 7 8 9 5 2 3 4 0 1 7 8 9 5 6 3 4 0 1 2 8 9 5 6 7 4 0 1 2 3 9 5 6 7 8 5 9 8 7 6 0 4 3 2 1 6 5 9 8 7 1 0 4 3 2 7 6 5 9 8 2 1 0 4 3 8 7 6 5 9 3 2 1 0 4 9 8 7 6 5 4 3 2 1 0); array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9); array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 5 7 6 2 8 3 0 9 4 5 8 0 3 7 9 6 1 4 2 8 9 1 6 0 4 3 5 2 7 9 4 5 3 1 2 6 8 7 0 4 2 8 6 5 7 3 9 0 1 2 7 9 3 8 0 6 4 1 5 7 0 4 6 9 1 3 2 5 8); array n[1] /nosymbols; k=length(s); call dynamic_array(n, k); do i=1 to k; n[i]=input(char(s,k-i+1),1.); end; c=0; do i=1 to k; c=d[c+1,p[mod(i-1,8)+1,n[i]+1]+1]; end; val=(c=0); return(val); endsub; run; options cmplib=work.funcs; /* Example */ data _null_; if vcdval('2363') then put 'Check digit is correct.'; else put 'Check digit is wrong.'; run;
Having the two functions in place, it's easy to check their consistency on, say, one million random digit strings with lengths ranging from 1 to, e.g., 40:
358 data _null_; 359 call streaminit('MT64',27182818); 360 length s $40; 361 do i=1 to 1e6; 362 s=' '; 363 do j=1 to rand('integer',40); 364 substr(s,j,1)=put(rand('integer',0,9),1.); 365 end; 366 if vcdval(cats(s,vcd(s)))=0 then do; 367 put 'ER' 'ROR: Wrong check digit encountered for ' s=; 368 stop; 369 end; 370 end; 371 run; NOTE: DATA statement used (Total process time): real time 20.93 seconds cpu time 20.79 seconds
Hi @febyinka and welcome to the SAS Support Communities!
Thank your very much for sharing this interesting link.
@febyinka wrote:
I am trying to use sas for verhoeff check digit but havent found any script to do so.
In this situation I would try and write my own function using PROC FCMP, as shown below.
/* Compute a check digit from a digit string S according to the Verhoeff algorithm,
using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */
proc fcmp outlib=work.funcs.test;
function vcd(s $);
array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9
1 2 3 4 0 6 7 8 9 5
2 3 4 0 1 7 8 9 5 6
3 4 0 1 2 8 9 5 6 7
4 0 1 2 3 9 5 6 7 8
5 9 8 7 6 0 4 3 2 1
6 5 9 8 7 1 0 4 3 2
7 6 5 9 8 2 1 0 4 3
8 7 6 5 9 3 2 1 0 4
9 8 7 6 5 4 3 2 1 0);
array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9);
array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9
1 5 7 6 2 8 3 0 9 4
5 8 0 3 7 9 6 1 4 2
8 9 1 6 0 4 3 5 2 7
9 4 5 3 1 2 6 8 7 0
4 2 8 6 5 7 3 9 0 1
2 7 9 3 8 0 6 4 1 5
7 0 4 6 9 1 3 2 5 8);
array n[1] /nosymbols;
k=length(s);
call dynamic_array(n, k);
do i=1 to k;
n[i]=input(char(s,k-i+1),1.);
end;
c=0;
do i=1 to k;
c=d[c+1,p[mod(i,8)+1,n[i]+1]+1];
end;
cd=v[c+1];
return(cd);
endsub;
run;
options cmplib=work.funcs;
/* Example */
data _null_;
x=vcd('236');
put 'Check digit = ' x;
run;
Result: 3.
Excellent approach by @FreelanceReinh. It reminds me of a challenge I had years ago in validating NPI (national provider identity) numbers, which relies on the Luhn algorithm. I also created an FCMP version!
Hi Thank You it was great and working perfectly!!
You're welcome. Only a few small changes (highlighted in bold below) to the previous code are needed to create a new function VCDVAL that returns 1 if the last digit of the argument is the correct Verhoeff check digit and 0 otherwise:
/* Validate a check digit from a digit string S according to the Verhoeff algorithm, using tables and formulas from https://en.wikipedia.org/wiki/Verhoeff_algorithm (2024-05-17) */ proc fcmp outlib=work.funcs.test; function vcdval(s $); array d[10,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 2 3 4 0 6 7 8 9 5 2 3 4 0 1 7 8 9 5 6 3 4 0 1 2 8 9 5 6 7 4 0 1 2 3 9 5 6 7 8 5 9 8 7 6 0 4 3 2 1 6 5 9 8 7 1 0 4 3 2 7 6 5 9 8 2 1 0 4 3 8 7 6 5 9 3 2 1 0 4 9 8 7 6 5 4 3 2 1 0); array v[10] /nosymbols (0 4 3 2 1 5 6 7 8 9); array p[8,10] /nosymbols (0 1 2 3 4 5 6 7 8 9 1 5 7 6 2 8 3 0 9 4 5 8 0 3 7 9 6 1 4 2 8 9 1 6 0 4 3 5 2 7 9 4 5 3 1 2 6 8 7 0 4 2 8 6 5 7 3 9 0 1 2 7 9 3 8 0 6 4 1 5 7 0 4 6 9 1 3 2 5 8); array n[1] /nosymbols; k=length(s); call dynamic_array(n, k); do i=1 to k; n[i]=input(char(s,k-i+1),1.); end; c=0; do i=1 to k; c=d[c+1,p[mod(i-1,8)+1,n[i]+1]+1]; end; val=(c=0); return(val); endsub; run; options cmplib=work.funcs; /* Example */ data _null_; if vcdval('2363') then put 'Check digit is correct.'; else put 'Check digit is wrong.'; run;
Having the two functions in place, it's easy to check their consistency on, say, one million random digit strings with lengths ranging from 1 to, e.g., 40:
358 data _null_; 359 call streaminit('MT64',27182818); 360 length s $40; 361 do i=1 to 1e6; 362 s=' '; 363 do j=1 to rand('integer',40); 364 substr(s,j,1)=put(rand('integer',0,9),1.); 365 end; 366 if vcdval(cats(s,vcd(s)))=0 then do; 367 put 'ER' 'ROR: Wrong check digit encountered for ' s=; 368 stop; 369 end; 370 end; 371 run; NOTE: DATA statement used (Total process time): real time 20.93 seconds cpu time 20.79 seconds
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.