Verhoeff algorithm: Difference between revisions

Added FreeBASIC
(Added 11l)
(Added FreeBASIC)
 
(18 intermediate revisions by 6 users not shown)
Line 23:
{{trans|Python}}
 
<langsyntaxhighlight 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],
Line 77:
(Int64(1234567890120), 1B, 0B, 0B),
(Int64(1234567890129), 1B, 0B, 0B)]
verhoeffchecksum(n, va, t, ve)</langsyntaxhighlight>
 
{{out}}
Line 83:
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
Line 147:
}
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 228:
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#}}==
<langsyntaxhighlight 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|]
Line 253 ⟶ 417:
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>
</lang>
{{out}}
<pre>
Line 325 ⟶ 489:
The assertion that 1234567890129 is valid is false
</pre>
 
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 404 ⟶ 569:
}
}
}</langsyntaxhighlight>
 
{{out}}
<pre>
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>
 
Line 415 ⟶ 743:
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<langsyntaxhighlight lang="jq">def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
 
def d: [
Line 488 ⟶ 816:
"\nThe validation for '\($stc)' is \($v).\n" );
task</langsyntaxhighlight>
{{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 547 ⟶ 875:
verhoeffchecksum(args...)
end
</langsyntaxhighlight>{{out}}Same as Wren example.
 
=={{header|Nim}}==
<langsyntaxhighlight Nimlang="nim">import strformat
 
const
Line 631 ⟶ 959:
discard verhoeff(10 * n + 9, true)
except ValueError:
echo getCurrentExceptionMsg()</langsyntaxhighlight>
 
{{out}}
Line 693 ⟶ 1,021:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # https://rosettacode.org/wiki/Verhoeff_algorithm
Line 755 ⟶ 1,083:
}
print "\n";
}</langsyntaxhighlight>
{{out}}
<pre>
Line 789 ⟶ 1,117:
=={{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 851 ⟶ 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 922 ⟶ 1,250:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">MULTIPLICATION_TABLE = [
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
(1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
Line 981 ⟶ 1,309:
(1234567890129, True, False, False)]:
verhoeffchecksum(n, va, t, ve)
</langsyntaxhighlight>{{out}}Output same as Wren example.
 
 
Line 987 ⟶ 1,315:
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 1,033 ⟶ 1,361:
validate $check, :verbose( $int.chars < 8 );
validate +($check.chop ~ 9), :verbose( $int.chars < 8 );
}</langsyntaxhighlight>
{{out}}
<pre>Checkdigit calculation for 236:
Line 1,097 ⟶ 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 1,155 ⟶ 1,566:
System.print("\nThe validation for '%(stc)' is %(v ? "correct" : "incorrect").\n")
}
}</langsyntaxhighlight>
 
{{out}}
2,136

edits