Description
The Verhoeff algorithm is a checksum formula for error detection developed by the Dutch mathematician Jacobus Verhoeff and first published in 1969. It was the first decimal check digit algorithm which detects all single-digit errors, and all transposition errors involving two adjacent digits, which was at the time thought impossible with such a code.

As the workings of the algorithm are clearly described in the linked Wikipedia article they will not be repeated here.

Task

Write routines, methods, procedures etc. in your language to generate a Verhoeff checksum digit for non-negative integers of any length and to validate the result. A combined routine is also acceptable.

The more mathematically minded may prefer to generate the 3 tables required from the description provided rather than to hard-code them.

Write your routines in such a way that they can optionally display digit by digit calculations as in the Wikipedia example.

Use your routines to calculate check digits for the integers: 236, 12345 and 123456789012 and then validate them. Also attempt to validate the same integers if the check digits in all cases were 9 rather than what they actually are.

Display digit by digit calculations for the first two integers but not for the third.

Related task

   Damm algorithm


V MULTIPLICATION_TABLE = [[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]]
 
V INV = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9]
 
V PERMUTATION_TABLE = [[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]]
 
F verhoeffchecksum(n, validate = 1B, terse = 1B, verbose = 0B)
   ‘
    Calculate the Verhoeff checksum over `n`.
    Terse mode or with single argument: return True if valid (last digit is a correct check digit).
    If checksum mode, return the expected correct checksum digit.
    If validation mode, return True if last digit checks correctly.
   ’
   I verbose
      print(("\n"(I validate {‘Validation’} E ‘Check digit’))‘ ’(‘calculations for ’n":\n\n i  ni  p[i,ni] c\n------------------"))
   V (c, dig) = (0, Array(String(I validate {n} E 10 * n)))
   L(ni) reversed(dig)
      V i = L.index
      V p = :PERMUTATION_TABLE[i % 8][Int(ni)]
      c = :MULTIPLICATION_TABLE[c][p]
      I verbose
         print(f:‘{i:2}  {ni}      {p}    {c}’)
 
   I verbose & !validate
      print("\ninv("c‘) = ’:INV[c])
   I !terse
      print(I validate {"\nThe validation for '"n‘' is ’(I c == 0 {‘correct’} E ‘incorrect’)‘.’} E "\nThe check digit for '"n‘' is ’:INV[c]‘.’)
   R I validate {c == 0} E :INV[c]
 
L(n, va, t, ve) [(Int64(236), 0B, 0B, 1B),
                 (Int64(2363), 1B, 0B, 1B),
                 (Int64(2369), 1B, 0B, 1B),
                 (Int64(12345), 0B, 0B, 1B),
                 (Int64(123451), 1B, 0B, 1B),
                 (Int64(123459), 1B, 0B, 1B),
                 (Int64(123456789012), 0B, 0B, 0B),
                 (Int64(1234567890120), 1B, 0B, 0B),
                 (Int64(1234567890129), 1B, 0B, 0B)]
   verhoeffchecksum(n, va, t, ve)