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

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!

 

Register for SAS Innovate 2025!! The premier event for SAS users, May 6-9 in Orlando FL. Sign up now for the best deals!
febyinka
Fluorite | Level 6

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-white.png

Special offer for SAS Communities members

Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.

 

View the full agenda.

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

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