BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
febyinka
Calcite | Level 5

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.

 

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

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

View solution in original post

4 REPLIES 4
FreelanceReinh
Jade | Level 19

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.

 

ChrisHemedinger
Community Manager

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!

 

Check out SAS Innovate on-demand content! Watch the main stage sessions, keynotes, and over 20 technical breakout sessions!
febyinka
Calcite | Level 5

Hi Thank You it was great and working perfectly!!

FreelanceReinh
Jade | Level 19

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

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 4 replies
  • 359 views
  • 5 likes
  • 3 in conversation