#### Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Options

# Luhn or Luhn formula - also known as modulus 1 or mod 1.

Member Posts: 258
edited 2011-08-22
Hi Friends,

Does anyone worked in Luhn algorithm or Luhn formula, also known as the "modulus 10" or "mod 10" algorithm (in Navision)?

Luhn algorithm is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, barcodes etc., Also see this link: http://en.wikipedia.org/wiki/Modulus_10

Thanks,
Aravindh

• Options
Member Posts: 90
below i've put some sample code on a way to do this checksum. I've put this in a function with a text parameter(Ptxt_String) and a boolean return value.
Ltxt_resultstring is also a text, all the other variables are integers.
```clear(LInt_total);
clear(LInt_TempInt);
FOR i := 1 TO STRLEN(PTxt_String) - 1 DO BEGIN
EVALUATE(LInt_TempInt,COPYSTR(PTxt_String,i,1));
IF (i MOD 2) <> 0 THEN BEGIN
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);
END ELSE BEGIN
LInt_TempInt *= 2;
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);
END;
END;
EVALUATE(LInt_TempInt,COPYSTR(PTxt_String,STRLEN(PTxt_String),1));
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);

FOR i := 1 TO STRLEN(Ltxt_ResultString) DO BEGIN
EVALUATE(LInt_TempInt,COPYSTR(Ltxt_ResultString,i,1));
LInt_total += LInt_TempInt;
END;

EXIT((LInt_total MOD 10) = 0);
```
• Options
Member Posts: 413
geronimo wrote:
below i've put some sample code on a way to do this checksum. I've put this in a function with a text parameter(Ptxt_String) and a boolean return value.
Ltxt_resultstring is also a text, all the other variables are integers.
```clear(LInt_total);
clear(LInt_TempInt);
FOR i := 1 TO STRLEN(PTxt_String) - 1 DO BEGIN
EVALUATE(LInt_TempInt,COPYSTR(PTxt_String,i,1));
IF (i MOD 2) <> 0 THEN BEGIN
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);
END ELSE BEGIN
LInt_TempInt *= 2;
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);
END;
END;
EVALUATE(LInt_TempInt,COPYSTR(PTxt_String,STRLEN(PTxt_String),1));
Ltxt_ResultString := Ltxt_ResultString + FORMAT(LInt_TempInt);

FOR i := 1 TO STRLEN(Ltxt_ResultString) DO BEGIN
EVALUATE(LInt_TempInt,COPYSTR(Ltxt_ResultString,i,1));
LInt_total += LInt_TempInt;
END;

EXIT((LInt_total MOD 10) = 0);
```
Ever looked up the strCheckSum() function in the helpfile ?
• Options
Member Posts: 90
thanks for the hint MBerger, another new thing learned
• Options
Member Posts: 1,131
STRCHECKSUM won't work, because it sums up the weighted digits, not the cross sum thereof.

The following example is from Wikipedia
Assume an example of an account number "4992739871" that will have a check digit added, making it of the form 4992739871x:
```Account number           4  9  9  2  7  3  9  8  7  1  x
Double every other       4 18  9  4  7  6  9 16  7  2  x
Sum together all numbers 64 + x
```
To make the sum divisible by 10, we set the check digit (x) to 6, making the full account number 49927398716.
The account number 49927398716 can be validated as follows:
1. Double every second digit, from the rightmost: (1×2) = 2, (8×2) = 16, (3×2) = 6, (2×2) = 4, (9×2) = 18
2. Sum all the individual digits (digits in parentheses are the products from Step 1): 6 + (2) + 7 + (1+6) + 9 + (6) + 7 + (4) + 9 + (1+8) + 4 = 70
3. Take the sum modulo 10: 70 mod 10 = 0; the account number is probably valid.
The sum calculated by STRCHECKSUM was 82 and therefore the check digit 8. This is because STCHECKSUM includes 18 and 16 in its sum. The Lunh algorithm, however sums up their cross sum, so adds up 1+8=9 and 1+6=7 instead.

geronimo's Code assumes an odd number of digits in it's Ptxt_String parameter to work correctly.
• Options
Member Posts: 90
vaprog wrote:
geronimo's Code assumes an odd number of digits in it's Ptxt_String parameter to work correctly.
how do you mean?
• Options
Member Posts: 1,131
This is the description of the algorithm from Wikipedia as above:
1. Counting from the check digit, which is the rightmost, and moving left, double the value of every second digit.
2. Sum the digits of the products (eg, 10 = 1 + 0 = 1, 14 = 1 + 4 = 5) together with the undoubled digits from the original number.
3. If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.
Item 1 says, you need to start from the right, and double every second digit.
geronimo's code starts from the left.
Therefore it matters whether you have an even or odd number of digits to evaluate.
The code may easily be anhanced, though.
• Options
Member Posts: 90
vaprog wrote:
This is the description of the algorithm from Wikipedia as above:
1. Counting from the check digit, which is the rightmost, and moving left, double the value of every second digit.
2. Sum the digits of the products (eg, 10 = 1 + 0 = 1, 14 = 1 + 4 = 5) together with the undoubled digits from the original number.
3. If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.
Item 1 says, you need to start from the right, and double every second digit.
geronimo's code starts from the left.
Therefore it matters whether you have an even or odd number of digits to evaluate.
The code may easily be anhanced, though.

ah i must have read past that part it is indeed fairly easy to adapt the code however
• Options
Member Posts: 258
Hai all,

Thank you guys for joining in this discussion and providing solutions and your ideas. It was useful. The client had changed the logic now which is given below.

I need to find the verification digit to the following value: 3070841326319000361243033388633240620117 (Length - 39 char)

1. Sum odd positions [3, 7, 8, 1, 2, 3, 9, 0, 3, 1, 4, 0, 3, 8, 6, 3, 4, 6, 0, 1]. (SumOdd = 72)
2. Multiply SumOdd * 3. (Mult = 72 * 3 = 216)
3. Sum even positions [0, 0, 4, 3, 6, 1, 0, 0, 6, 2, 3, 3, 3, 8, 3, 2, 0, 2, 1]. (SumEven = 47)
4. Sum = Mult + SumEven, (Sum = 216 + 47 = 263)
5. Verification digit 7. (We need to add the integer value 7 to 263 so the nearest higher value which should divisible by 10 and the remainder remains 0.)

To find the lowest number (verification digit)...:
VeriDigit = 10 - (Sum - (int(Sum/10) * 10))
VeriDigit = 10 - (263 -(int(263/10) * 10))
= 10 - (263 - (26 * 10))
= 10 - (263 - 260) = 10 - 3
VeriDigit = 7

Aravindh
• Options
Member Posts: 9
Hi Friends,

Does anyone worked in Luhn algorithm or Luhn formula, also known as the "modulus 10" or "mod 10" algorithm (in Navision)?

Luhn algorithm is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, barcodes etc., Also see this link: http://en.wikipedia.org/wiki/Modulus_10

Thanks,
Aravindh

Please find my solution for NAV C/AL in the following post >> https://forum.mibuso.com/discussion/77912/luhn-algorithm-modulus-10-in-dynamics-nav-c-al-code-creating-a-check-digit/p1?new=1

This can easily be converted to work in Business Central AL code
• Options
Member Posts: 9
edited 2024-02-14
Hai all,

Thank you guys for joining in this discussion and providing solutions and your ideas. It was useful. The client had changed the logic now which is given below.

I need to find the verification digit to the following value: 3070841326319000361243033388633240620117 (Length - 39 char)

1. Sum odd positions [3, 7, 8, 1, 2, 3, 9, 0, 3, 1, 4, 0, 3, 8, 6, 3, 4, 6, 0, 1]. (SumOdd = 72)
2. Multiply SumOdd * 3. (Mult = 72 * 3 = 216)
3. Sum even positions [0, 0, 4, 3, 6, 1, 0, 0, 6, 2, 3, 3, 3, 8, 3, 2, 0, 2, 1]. (SumEven = 47)
4. Sum = Mult + SumEven, (Sum = 216 + 47 = 263)
5. Verification digit 7. (We need to add the integer value 7 to 263 so the nearest higher value which should divisible by 10 and the remainder remains 0.)

To find the lowest number (verification digit)...:
VeriDigit = 10 - (Sum - (int(Sum/10) * 10))
VeriDigit = 10 - (263 -(int(263/10) * 10))
= 10 - (263 - (26 * 10))
= 10 - (263 - 260) = 10 - 3
VeriDigit = 7

Aravindh

Hello Aravindh,

Here is my take on a solution for your problem. It is similar to the solution I posted earlier.
I was initially confused by the results but I realized I had to take the last digit out of the number before putting it into the algorithm

But I must ask why the sum of odd numbers is multiplied by 3 specifically and is it always 3?

Anyways, here is the code below:

Variables:
Name DataType Subtype Length
i Integer
LengthOfDigit Integer
CodeCharacter Code 250
Product BigInteger
SumProduct BigInteger
SingleDigit Integer
SumOfOddNumbers Integer
SumOfEvenNumbers Integer
```
OrigCode := '307084132631900036124303338863324062011';

LengthOfDigit := STRLEN(OrigCode);
CLEAR(SumOfOddNumbers);  CLEAR(Product); CLEAR(SumProduct);

FOR i := 1 TO LengthOfDigit DO BEGIN
CodeCharacter[i] := COPYSTR(OrigCode,i,1);      // Get the individual digit in that position

//Check of the position of the digit is an odd number. All odd numbers will be (i MOD 2 = 1) or more
// If Odd, the multiply by 2, else multiply by 1
//-------------------------------------------------------------
IF i MOD 2 <> 0 THEN BEGIN                        //Odd numbers
EVALUATE(SingleDigit[i],CodeCharacter[i]);   //Convert code to an integer for computation
SumOfOddNumbers :=  SumOfOddNumbers + SingleDigit[i];
END ELSE BEGIN
EVALUATE(SingleDigit[i],CodeCharacter[i]);    //Even Numbers
SumOfEvenNumbers :=  SumOfEvenNumbers + SingleDigit[i];
END;

END;

Product := SumOfOddNumbers * 3;

SumProduct := Product + SumOfEvenNumbers;

//We can use the MOD function to get the number you mentioned in your comment. This is much faster than the formula of "VeriDigit = 10 - (Sum - (int(Sum/10) * 10))"
IF SumProduct MOD 10 <> 0 THEN
VerificationDigit := 10 - (SumProduct MOD 10)
ELSE
VerificationDigit := 0;

```