Verhoeff algorithm: Difference between revisions

Added FreeBASIC
(Added FreeBASIC)
 
(26 intermediate revisions by 12 users not shown)
Line 1:
{{draft task}}
;Description
The [https://en.wikipedia.org/wiki/Verhoeff_algorithm 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.
Line 19:
*   [[Damm algorithm]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">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)</syntaxhighlight>
 
{{out}}
The same as in Python.
 
=={{header|C}}==
<syntaxhighlight lang="c">#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
 
static const int d[][10] = {
{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},
};
 
static const int inv[] = {0, 4, 3, 2, 1, 5, 6, 7, 8, 9};
 
static const int p[][10] = {
{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},
};
 
int verhoeff(const char* s, bool validate, bool verbose) {
if (verbose) {
const char* t = validate ? "Validation" : "Check digit";
printf("%s calculations for '%s':\n\n", t, s);
puts(u8" i n\xE1\xB5\xA2 p[i,n\xE1\xB5\xA2] c");
puts("------------------");
}
int len = strlen(s);
if (validate)
--len;
int c = 0;
for (int i = len; i >= 0; --i) {
int ni = (i == len && !validate) ? 0 : s[i] - '0';
assert(ni >= 0 && ni < 10);
int pi = p[(len - i) % 8][ni];
c = d[c][pi];
if (verbose)
printf("%2d %d %d %d\n", len - i, ni, pi, c);
}
if (verbose && !validate)
printf("\ninv[%d] = %d\n", c, inv[c]);
return validate ? c == 0 : inv[c];
}
 
int main() {
const char* ss[3] = {"236", "12345", "123456789012"};
for (int i = 0; i < 3; ++i) {
const char* s = ss[i];
bool verbose = i < 2;
int c = verhoeff(s, false, verbose);
printf("\nThe check digit for '%s' is '%d'.\n", s, c);
int len = strlen(s);
char sc[len + 2];
strncpy(sc, s, len + 2);
for (int j = 0; j < 2; ++j) {
sc[len] = (j == 0) ? c + '0' : '9';
int v = verhoeff(sc, true, verbose);
printf("\nThe validation for '%s' is %s.\n", sc,
v ? "correct" : "incorrect");
}
}
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
Check digit calculations for '236':
 
i nᵢ p[i,nᵢ] c
------------------
0 0 0 0
1 6 3 3
2 3 3 1
3 2 1 2
 
inv[2] = 3
 
The check digit for '236' is '3'.
Validation calculations for '2363':
 
i nᵢ p[i,nᵢ] c
------------------
0 3 3 3
1 6 3 1
2 3 3 4
3 2 1 0
 
The validation for '2363' is correct.
Validation calculations for '2369':
 
i nᵢ p[i,nᵢ] c
------------------
0 9 9 9
1 6 3 6
2 3 3 8
3 2 1 7
 
The validation for '2369' is incorrect.
Check digit calculations for '12345':
 
i nᵢ p[i,nᵢ] c
------------------
0 0 0 0
1 5 8 8
2 4 7 1
3 3 6 7
4 2 5 2
5 1 2 4
 
inv[4] = 1
 
The check digit for '12345' is '1'.
Validation calculations for '123451':
 
i nᵢ p[i,nᵢ] c
------------------
0 1 1 1
1 5 8 9
2 4 7 2
3 3 6 8
4 2 5 3
5 1 2 0
 
The validation for '123451' is correct.
Validation calculations for '123459':
 
i nᵢ p[i,nᵢ] c
------------------
0 9 9 9
1 5 8 1
2 4 7 8
3 3 6 2
4 2 5 7
5 1 2 5
 
The validation for '123459' is incorrect.
 
The check digit for '123456789012' is '0'.
 
The validation for '1234567890120' is correct.
 
The validation for '1234567890129' is incorrect.
</pre>
 
=={{header|C++}}==
 
<syntaxhighlight lang="c++">
 
#include <cstdint>
#include <iostream>
#include <string>
#include <array>
#include <iomanip>
 
typedef std::pair<std::string, bool> data;
 
const std::array<const std::array<int32_t, 10>, 10> 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 }
} };
 
const std::array<int32_t, 10> inverse = { 0, 4, 3, 2, 1, 5, 6, 7, 8, 9 };
 
const std::array<const std::array<int32_t, 10>, 8> 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 }
} };
 
int32_t verhoeff_checksum(std::string number, const bool doValidation, const bool doDisplay) {
if ( doDisplay ) {
std::string calculationType = doValidation ? "Validation" : "Check digit";
std::cout << calculationType << " calculations for " << number << "\n" << std::endl;
std::cout << " i ni p[i, ni] c" << std::endl;
std::cout << "-------------------" << std::endl;
}
 
if ( ! doValidation ) {
number += "0";
}
 
int32_t c = 0;
const int32_t le = number.length() - 1;
for ( int32_t i = le; i >= 0; i-- ) {
const int32_t ni = number[i] - '0';
const int32_t pi = permutation_table[(le - i) % 8][ni];
c = multiplication_table[c][pi];
 
if ( doDisplay ) {
std::cout << std::setw(2) << le - i << std::setw(3) << ni
<< std::setw(8) << pi << std::setw(6) << c << "\n" << std::endl;
}
}
 
if ( doDisplay && ! doValidation ) {
std::cout << "inverse[" << c << "] = " << inverse[c] << "\n" << std::endl;;
}
 
return doValidation ? c == 0 : inverse[c];
}
 
int main( ) {
const std::array<data, 3> tests = {
std::make_pair("123", true), std::make_pair("12345", true), std::make_pair("123456789012", false) };
 
for ( const data& test : tests ) {
int32_t digit = verhoeff_checksum(test.first, false, test.second);
std::cout << "The check digit for " << test.first << " is " << digit << "\n" << std::endl;
 
std::string numbers[2] = { test.first + std::to_string(digit), test.first + "9" };
for ( const std::string& number : numbers ) {
digit = verhoeff_checksum(number, true, test.second);
std::string result = ( digit == 1 ) ? "correct" : "incorrect";
std::cout << "The validation for " << number << " is " << result << ".\n" << std::endl;
}
}
}
</syntaxhighlight>
{{ out }}
<pre>
The same as the Wren example.
</pre>
 
=={{header|FreeBASIC}}==
{{trans|Wren}}
<syntaxhighlight lang="vbnet">Dim Shared As Integer d(9, 9) = { _
{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} }
 
Dim Shared As Integer inv(9) = {0, 4, 3, 2, 1, 5, 6, 7, 8, 9}
 
Dim Shared As Integer p(7, 9) = { _
{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} }
 
Function Verhoeff(s As String, validate As Integer, table As Integer) As Integer
Dim As Integer c, le, k, ni, pi
If table Then
Print
Print Iif(validate, "Validation", "Check digit") & " calculations for '" & s & "':"
Print !"\n i ni p[i,ni] c\n------------------"
End If
If Not validate Then s = s & "0"
c = 0
le = Len(s) - 1
For k = le To 0 Step -1
ni = Asc(Mid(s, k + 1, 1)) - 48
pi = p((le - k) Mod 8, ni)
c = d(c, pi)
If table Then Print Using "## # # #"; le - k; ni; pi; c
Next k
If table And Not validate Then Print !"\ninv[" & c & "] = " & inv(c)
Return Iif(Not validate, inv(c), c = 0)
End Function
 
Type miTipo
s As String
b As Boolean
End Type
Dim sts(2) As miTipo
sts(0).s = "236" : sts(0).b = True
sts(1).s = "12345" : sts(1).b = True
sts(2).s = "123456789012" : sts(2).b = False
 
Dim As Integer i, j, v , c
For i = 0 To 2
c = Verhoeff(sts(i).s, False, sts(i).b)
Print Using !"\nThe check digit for '&' is '&'"; sts(i).s; c
Dim stc(1) As String = {Left(sts(i).s, Len(sts(i).s)-1) & Str(c), Left(sts(i).s, Len(sts(i).s)-1) & "9"}
For j = 0 To Ubound(stc)
v = Verhoeff(stc(j), True, sts(i).b)
Print Using !"\nThe validation for '&' is "; stc(j);
Print Iif (v, "correct", "incorrect"); "."
Next j
Print
Next i
 
Sleep</syntaxhighlight>
{{out}}
<pre>Same as Wren entry.</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
// Verhoeff algorithm. Nigel Galloway: August 26th., 2021
let d,inv,p=let d=[|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|]
let p=[|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|]
let inv=[|0;4;3;2;1;5;6;7;8;9|] in (fun n g->d.[10*n+g]),(fun g->inv.[g]),(fun n g->p.[10*(n%8)+g])
let fN g=Seq.unfold(fun(i,g,l)->if i=0I then None else let ni=int(i%10I) in let l=d l (p g ni) in Some((ni,l),(i/10I,g+1,l)))(g,0,0)
let csum g=let _,g=Seq.last(fN g) in inv g
let printTable g=printfn $"Work Table for %A{g}\n i nᵢ p[i,nᵢ] c\n--------------"; fN g|>Seq.iteri(fun i (n,g)->printfn $"%d{i} %d{n} %d{p i n} %d{g}")
printTable 2360I
printfn $"\nThe CheckDigit for 236 is %d{csum 2360I}\n"
printTable 2363I
printfn $"\nThe assertion that 2363 is valid is %A{csum 2363I=0}\n"
printTable 2369I
printfn $"\nThe assertion that 2369 is valid is %A{csum 2369I=0}\n"
printTable 123450I
printfn $"\nThe CheckDigit for 12345 is %d{csum 123450I}\n"
printTable 123451I
printfn $"\nThe assertion that 123451 is valid is %A{csum 123451I=0}\n"
printTable 123459I
printfn $"\nThe assertion that 123459 is valid is %A{csum 123459I=0}"
printfn $"The CheckDigit for 123456789012 is %d{csum 1234567890120I}"
printfn $"The assertion that 1234567890120 is valid is %A{csum 1234567890120I=0}"
printfn $"The assertion that 1234567890129 is valid is %A{csum 1234567890129I=0}"
</syntaxhighlight>
{{out}}
<pre>
Work Table for 2360
i nᵢ p[i,nᵢ] c
--------------
0 0 0 0
1 6 3 3
2 3 3 1
3 2 1 2
 
The CheckDigit for 236 is 3
 
Work Table for 2363
i nᵢ p[i,nᵢ] c
--------------
0 3 3 3
1 6 3 1
2 3 3 4
3 2 1 0
 
The assertion that 2363 is valid is true
 
Work Table for 2369
i nᵢ p[i,nᵢ] c
--------------
0 9 9 9
1 6 3 6
2 3 3 8
3 2 1 7
 
The assertion that 2369 is valid is false
 
Work Table for 123450
i nᵢ p[i,nᵢ] c
--------------
0 0 0 0
1 5 8 8
2 4 7 1
3 3 6 7
4 2 5 2
5 1 2 4
 
The CheckDigit for 12345 is 1
 
Work Table for 123451
i nᵢ p[i,nᵢ] c
--------------
0 1 1 1
1 5 8 9
2 4 7 2
3 3 6 8
4 2 5 3
5 1 2 0
 
The assertion that 123451 is valid is true
 
Work Table for 123459
i nᵢ p[i,nᵢ] c
--------------
0 9 9 9
1 5 8 1
2 4 7 8
3 3 6 2
4 2 5 7
5 1 2 5
 
The assertion that 123459 is valid is false
The CheckDigit for 123456789012 is 0
The assertion that 1234567890120 is valid is true
The assertion that 1234567890129 is valid is false
</pre>
 
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 98 ⟶ 569:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 104 ⟶ 575:
Identical to Wren example
</pre>
 
=={{header|J}}==
 
Implementation:
 
<syntaxhighlight lang="j">cyc=: | +/~@i. NB. cyclic group, order y
ac=: |(+-/~@i.) NB. anticyclic group, order y
a2n=: (+#)@ NB. add 2^n
di=: (cyc,.cyc a2n),((ac a2n),.ac)
 
D=: di 5
INV=: ,I.0=D
P=: {&(C.1 5 8 9 4 2 7 0;3 6)^:(i.8) i.10
 
verhoeff=: {{
c=. 0
for_N. |.10 #.inv y do.
c=. D{~<c,P{~<(8|N_index),N
end.
}}
 
traceverhoeff=: {{
r=. EMPTY
c=. 0
for_N. |.10 #.inv y do.
c0=. c
c=. D{~<c,p=.P{~<(j=.8|N_index),N
r=. r, c,p,j,N_index,N,c0
end.
labels=. cut 'cᵢ p[i,nᵢ] i nᵢ n cₒ'
1 1}.}:~.":labels,(<;._1"1~[:*/' '=])' ',.":r
}}
 
checkdigit=: INV {~ verhoeff@*&10
valid=: 0 = verhoeff</syntaxhighlight>
 
Task examples:
<syntaxhighlight lang="j"> checkdigit 236 12345 123456789012
3 1 0
valid 2363
1
valid 123451
1
valid 1234567890120
1
valid 2369
0
valid 123459
0
valid 1234567890129
0
traceverhoeff 2363
cᵢ│p[i,nᵢ]│i│nᵢ│n│cₒ│
──┼───────┼─┼──┼─┼──┤
3 │3 │0│0 │3│0 │
1 │3 │1│1 │6│3 │
4 │3 │2│2 │3│1 │
0 │1 │3│3 │2│4 │
traceverhoeff 123451
cᵢ│p[i,nᵢ]│i│nᵢ│n│cₒ│
──┼───────┼─┼──┼─┼──┤
1 │1 │0│0 │1│0 │
9 │8 │1│1 │5│1 │
2 │7 │2│2 │4│9 │
8 │6 │3│3 │3│2 │
3 │5 │4│4 │2│8 │
0 │2 │5│5 │1│3 │
</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.Arrays;
import java.util.List;
 
public class VerhoeffAlgorithm {
 
public static void main(String[] args) {
initialise();
 
List<List<Object>> tests = List.of(
List.of( "236", true ), List.of( "12345", true ), List.of( "123456789012", false ) );
for ( List<Object> test : tests ) {
Object object = verhoeffChecksum((String) test.get(0), false, (boolean) test.get(1));
System.out.println("The check digit for " + test.get(0) + " is " + object + "\n");
for ( String number : List.of( test.get(0) + String.valueOf(object), test.get(0) + "9" ) ) {
object = verhoeffChecksum(number, true, (boolean) test.get(1));
String result = (boolean) object ? "correct" : "incorrect";
System.out.println("The validation for " + number + " is " + result + ".\n");
}
}
}
private static Object verhoeffChecksum(String number, boolean doValidation, boolean doDisplay) {
if ( doDisplay ) {
String calculationType = doValidation ? "Validation" : "Check digit";
System.out.println(calculationType + " calculations for " + number + "\n");
System.out.println(" i ni p[i, ni] c");
System.out.println("-------------------");
}
if ( ! doValidation ) {
number += "0";
}
int c = 0;
final int le = number.length() - 1;
for ( int i = le; i >= 0; i-- ) {
final int ni = number.charAt(i) - '0';
final int pi = permutationTable.get((le - i) % 8).get(ni);
c = multiplicationTable.get(c).get(pi);
if ( doDisplay ) {
System.out.println(String.format("%2d%3d%8d%6d\n", le - i, ni, pi, c));
}
}
if ( doDisplay && ! doValidation ) {
System.out.println("inverse[" + c + "] = " + inverse.get(c) + "\n");
}
return doValidation ? c == 0 : inverse.get(c);
}
private static void initialise() {
multiplicationTable = List.of(
List.of( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ),
List.of( 1, 2, 3, 4, 0, 6, 7, 8, 9, 5 ),
List.of( 2, 3, 4, 0, 1, 7, 8, 9, 5, 6 ),
List.of( 3, 4, 0, 1, 2, 8, 9, 5, 6, 7 ),
List.of( 4, 0, 1, 2, 3, 9, 5, 6, 7, 8 ),
List.of( 5, 9, 8, 7, 6, 0, 4, 3, 2, 1 ),
List.of( 6, 5, 9, 8, 7, 1, 0, 4, 3, 2 ),
List.of( 7, 6, 5, 9, 8, 2, 1, 0, 4, 3 ),
List.of( 8, 7, 6, 5, 9, 3, 2, 1, 0, 4 ),
List.of( 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 )
);
inverse = Arrays.asList( 0, 4, 3, 2, 1, 5, 6, 7, 8, 9 );
permutationTable = List.of(
List.of( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ),
List.of( 1, 5, 7, 6, 2, 8, 3, 0, 9, 4 ),
List.of( 5, 8, 0, 3, 7, 9, 6, 1, 4, 2 ),
List.of( 8, 9, 1, 6, 0, 4, 3, 5, 2, 7 ),
List.of( 9, 4, 5, 3, 1, 2, 6, 8, 7, 0 ),
List.of( 4, 2, 8, 6, 5, 7, 3, 9, 0, 1 ),
List.of( 2, 7, 9, 3, 8, 0, 6, 4, 1, 5 ),
List.of( 7, 0, 4, 6, 9, 1, 3, 2, 5, 8 )
);
}
private static List<List<Integer>> multiplicationTable;
private static List<Integer> inverse;
private static List<List<Integer>> permutationTable;
}
</syntaxhighlight>
{{ out }}
<pre>
The same as the Wren example.
</pre>
 
=={{header|jq}}==
{{trans|Wren}}
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq">def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
 
def d: [
[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]
];
def inv: [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];
def p: [
[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]
];
 
# Output: an object: {emit, c}
def verhoeff($s; $validate; $table):
 
{emit:
(if $table then
["\(if $validate then "Validation" else "Check digit" end) calculations for '\($s)':\n",
" i nᵢ p[i,nᵢ] c",
"------------------"]
else []
end),
s: (if $validate then $s else $s + "0" end),
c: 0 }
| ((.s|length) - 1) as $le
| reduce range($le; -1; -1) as $i (.;
(.s[$i:$i+1]|explode[] - 48) as $ni
| (p[($le-$i) % 8][$ni]) as $pi
| .c = d[.c][$pi]
| if $table
then .emit += ["\($le-$i|lpad(2)) \($ni) \($pi) \(.c)"]
else .
end )
| if $table and ($validate|not)
then .emit += ["\ninv[\(.c)] = \(inv[.c])"]
else .
end
| .c = (if $validate then (.c == 0) else inv[.c] end);
def sts: [
["236", true],
["12345", true],
["123456789012", false]];
 
def task:
sts[]
| . as $st
| verhoeff($st[0]; false; $st[1]) as {c: $c, emit: $emit}
| $emit[],
"\nThe check digit for '\($st[0])' is '\($c)'\n",
( ($st[0] + ($c|tostring)), ($st[0] + "9")
| . as $stc
| verhoeff($stc; true; $st[1]) as {emit: $emit, c: $v}
| (if $v then "correct" else "incorrect" end) as $v
| $emit[],
"\nThe validation for '\($stc)' is \($v).\n" );
task</syntaxhighlight>
{{out}}
As for [[#Wren]].
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">const multiplicationtable = [
0 1 2 3 4 5 6 7 8 9;
1 2 3 4 0 6 7 8 9 5;
Line 131 ⟶ 846:
 
"""
verhoeffchecksum(n::Integer, validate=true, terse=true, verbose=false)
Calculate the Verhoeff checksum over `n`.
 
Terse mode or with single argument: return true if valid (last digit is a correct check digit).
Calculate the Verhoeff checksum over `n`.
If checksum mode, return the expected correct checksum digit.
Terse mode or with Ifsingle validation mode,argument: return true if valid (last digit checksis correctlya correct check digit).
If checksum mode, return the expected correct checksum digit.
If validation mode, return true if last digit checks correctly.
"""
function verhoeffchecksum(n::Integer, validate=true, terse=true, verbose=false)
Line 158 ⟶ 875:
verhoeffchecksum(args...)
end
</langsyntaxhighlight>{{out}}Same as Wren example.
 
=={{header|Nim}}==
<langsyntaxhighlight Nimlang="nim">import strformat
 
const
Line 242 ⟶ 959:
discard verhoeff(10 * n + 9, true)
except ValueError:
echo getCurrentExceptionMsg()</langsyntaxhighlight>
 
{{out}}
Line 302 ⟶ 1,019:
Check digit validation was successful for 1234567890120.
Check digit validation failed for 1234567890129.</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # https://rosettacode.org/wiki/Verhoeff_algorithm
use warnings;
 
my @inv = qw(0 4 3 2 1 5 6 7 8 9);
 
my @d = map [ split ], split /\n/, <<END;
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
END
 
my @p = map [ split ], split /\n/, <<END;
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
END
 
my $debug;
 
sub generate
{
local $_ = shift() . 0;
my $c = my $i = 0;
my ($n, $p);
$debug and print "i ni d(c,p(i%8,ni)) c\n";
while( length )
{
$c = $d[ $c ][ $p = $p[ $i % 8 ][ $n = chop ] ];
$debug and printf "%d%3d%7d%10d\n", $i, $n, $p, $c;
$i++;
}
return $inv[ $c ];
}
 
sub validate { shift =~ /(\d+)(\d)/ and $2 == generate($1) }
 
for ( 236, 12345, 123456789012 )
{
print "testing $_\n";
$debug = length() < 6;
my $checkdigit = generate($_);
print "check digit for $_ is $checkdigit\n";
$debug = 0;
for my $cd ( $checkdigit, 9 )
{
print "$_$cd is ", validate($_ . $cd) ? '' : 'not ', "valid\n";
}
print "\n";
}</syntaxhighlight>
{{out}}
<pre>
testing 236
i ni d(c,p(i%8,ni)) c
0 0 0 0
1 6 3 3
2 3 3 1
3 2 1 2
check digit for 236 is 3
2363 is valid
2369 is not valid
 
testing 12345
i ni d(c,p(i%8,ni)) c
0 0 0 0
1 5 8 8
2 4 7 1
3 3 6 7
4 2 5 2
5 1 2 4
check digit for 12345 is 1
123451 is valid
123459 is not valid
 
testing 123456789012
check digit for 123456789012 is 0
1234567890120 is valid
1234567890129 is not valid
 
</pre>
 
=={{header|Phix}}==
The tables were generated in case 1-based index versions of them would help, tbh, but in the end I didn't even try that, aka start with tagset(10).
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)},</span>
Line 367 ⟶ 1,179:
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">verhoeff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]&</span><span style="color: #008000;">'9'</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">,</span><span style="color: #000000;">show_workings</span><span style="color: #0000FF;">)!=</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 436 ⟶ 1,248:
The validation for `1234567890129` is incorrect
</pre>
 
=={{header|Python}}==
<syntaxhighlight lang="python">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),
]
 
INV = (0, 4, 3, 2, 1, 5, 6, 7, 8, 9)
 
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),
]
 
def verhoeffchecksum(n, validate=True, terse=True, verbose=False):
"""
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.
"""
if verbose:
print(f"\n{'Validation' if validate else 'Check digit'}",\
f"calculations for {n}:\n\n i nᵢ p[i,nᵢ] c\n------------------")
# transform number list
c, dig = 0, list(str(n if validate else 10 * n))
for i, ni in enumerate(dig[::-1]):
p = PERMUTATION_TABLE[i % 8][int(ni)]
c = MULTIPLICATION_TABLE[c][p]
if verbose:
print(f"{i:2} {ni} {p} {c}")
 
if verbose and not validate:
print(f"\ninv({c}) = {INV[c]}")
if not terse:
print(f"\nThe validation for '{n}' is {'correct' if c == 0 else 'incorrect'}."\
if validate else f"\nThe check digit for '{n}' is {INV[c]}.")
return c == 0 if validate else INV[c]
 
if __name__ == '__main__':
 
for n, va, t, ve in [
(236, False, False, True), (2363, True, False, True), (2369, True, False, True),
(12345, False, False, True), (123451, True, False, True), (123459, True, False, True),
(123456789012, False, False, False), (1234567890120, True, False, False),
(1234567890129, True, False, False)]:
verhoeffchecksum(n, va, t, ve)
</syntaxhighlight>{{out}}Output same as Wren example.
 
 
=={{header|Raku}}==
Generate the tables rather than hard coding, They're not all that complex.
 
<syntaxhighlight lang="raku" perl6line>my @d = [^10] xx 5;
@d[$_][^5].=rotate($_), @d[$_][5..*].=rotate($_) for 1..4;
push @d: [@d[$_].reverse] for flat 1..4, 0;
Line 486 ⟶ 1,361:
validate $check, :verbose( $int.chars < 8 );
validate +($check.chop ~ 9), :verbose( $int.chars < 8 );
}</langsyntaxhighlight>
{{out}}
<pre>Checkdigit calculation for 236:
Line 550 ⟶ 1,425:
Validation calculation for 1234567890129:
Checkdigit: incorrect</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="go">const d = [
[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],
]
const inv = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9]
const p = [
[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],
]
fn verhoeff(ss string, validate bool, table bool) int {
mut s:= ss
if table {
mut t := "Check digit"
if validate {
t = "Validation"
}
println("$t calculations for '$s':\n")
println(" i nᵢ p[i,nᵢ] c")
println("------------------")
}
if !validate {
s = s + "0"
}
mut c := 0
le := s.len - 1
for i := le; i >= 0; i-- {
ni := int(s[i] - 48)
pi := p[(le-i)%8][ni]
c = d[c][pi]
if table {
println("${le-i:2} $ni $pi $c")
}
}
if table && !validate {
println("\ninv[$c] = ${inv[c]}")
}
if !validate {
return inv[c]
}
return int(c == 0)
}
fn main() {
ss := ["236", "12345", "123456789012"]
ts := [true, true, false, true]
for i, s in ss {
c := verhoeff(s, false, ts[i])
println("\nThe check digit for '$s' is '$c'\n")
for sc in [s + c.str(), s + "9"] {
v := verhoeff(sc, true, ts[i])
mut ans := "correct"
if v==0 {
ans = "incorrect"
}
println("\nThe validation for '$sc' is $ans\n")
}
}
}</syntaxhighlight>
 
{{out}}
<pre>
Identical to Wren example
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-fmt}}
<langsyntaxhighlight ecmascriptlang="wren">import "./fmt" for Fmt
 
var d = [
Line 608 ⟶ 1,566:
System.print("\nThe validation for '%(stc)' is %(v ? "correct" : "incorrect").\n")
}
}</langsyntaxhighlight>
 
{{out}}
2,122

edits