Jump to content

Damm algorithm

From Rosetta Code
Task
Damm algorithm
You are encouraged to solve this task according to the task description, using any language you may know.

The Damm algorithm is a checksum algorithm which detects all single digit errors and adjacent transposition errors.


The algorithm is named after H. Michael Damm.


Task

Verify the checksum, stored as last digit of an input.



Translation of: Python
V matrix = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]
]

F damm(Int num) -> Bool
   V row = 0
   L(digit) String(num)
      row = :matrix[row][Int(digit)]
   R row == 0

L(test) [5724, 5727, 112946]
   print(test"\t Validates as: "damm(test))
Output:
5724     Validates as: 1B
5727     Validates as: 0B
112946   Validates as: 1B


	org	100h
	jmp	demo
	;;;	Given an 0-terminated ASCII string containing digits in [DE],
	;;;	see if it matches its check digit. Returns with zero flag set
	;;;	if the string matches.
damm:	mvi	c,0	; Interim digit in C, starts off at 0.
	ldax	d	; Get current byte from string
	inx	d 	; Advance the pointer
	ana	a	; Is the byte zero?
	jnz	$+5	; If not, go look up interim digit
	cmp	c	; But if so, see if the interim digit is also zero
	ret		; And return whether this was the case
	sui	'0'	; Subtract ASCII 0
	mov	b,a	; Keep digit to be processed in B
	mov	a,c	; Calculate C*10 (interim digit row index)
	add	a	; * 2
	add	a	; * 4
	add	c	; * 5
	add	a	; * 10
	add	b	; Add column index
	lxi	h,dammit
	add	l	; Table lookup (assuming H doesn't change, i.e. it
	mov	l,a	; doesn't cross a page boundary).
	mov	c,m	; Get new interim digit from table
	jmp	damm+2	; And check next character
	;;;	Table of interim digits
	;;;	NOTE: must not cross page boundary
dammit:	db	0,3,1,7,5,9,8,6,4,2
	db	7,0,9,2,1,5,4,8,6,3
	db	4,2,0,6,8,7,1,3,5,9
	db	1,7,5,0,9,8,3,4,2,6
	db	6,1,2,3,0,4,5,9,7,8
	db	3,6,7,4,2,0,9,5,8,1
	db	5,8,6,9,7,2,0,1,3,4
	db	8,9,4,5,3,6,2,0,1,7
	db	9,4,3,8,6,1,7,2,0,5
	db	2,5,8,1,4,3,6,7,9,0
	;;;	Demo code: see if the argument on the CP/M command line
	;;;	matches its input.
demo:	lxi	h,80h	; Zero-terminate input
	mov	e,m
	mvi	d,0
	inx	d
	dad	d
	mov	m,d
	lxi	d,82h	; Command line argument, skipping first space
	call	damm	; See if it validates
	mvi	c,9
	lxi	d,ok	; Print OK...
	jz	5	; ...if the checksum matches,
	lxi	d,no	; Print NOT OK otherwise.
	jmp	5
no:	db	'NOT '
ok:	db	'OK$'
Output:
A>damm 5724
OK
A>damm 5727
NOT OK
A>damm 112946
OK
A>damm 112949
NOT OK
	cpu	8086
	bits	16
section	.text
	org	100h
	jmp	demo
	;;;	Given a 0-terminated ASCII string containing digits in
	;;;	[DS:SI], see if the check digit matches. Returns with zero flag
	;;;	set if it matches.
damm:	xor	cl,cl	; Interim digit starts out at 0
	mov	bx,.tab	; Index for table lookup
.dgt:	lodsb		; Get next string byte
	test	al,al	; If it is zero, we're done
	jz	.out
	sub	al,'0'	; Make ASCII digit
	mov	ah,cl	; Table lookup, AH = interim digit
	aad		; AL += AH * 10 (such handy instructions the 8086 has)
	cs 	xlatb	; AL = CS:table[AL]
	mov	cl,al	; CL = new interim digit
	jmp	.dgt	; Get next string
.out:	test	cl,cl	; Interim digit should be zero at the end
	ret
.tab:	db	0,3,1,7,5,9,8,6,4,2	; Table can be stored as part of the
	db	7,0,9,2,1,5,4,8,6,3	; code
	db	4,2,0,6,8,7,1,3,5,9
	db	1,7,5,0,9,8,3,4,2,6
	db	6,1,2,3,0,4,5,9,7,8
	db	3,6,7,4,2,0,9,5,8,1
	db	5,8,6,9,7,2,0,1,3,4
	db	8,9,4,5,3,6,2,0,1,7
	db	9,4,3,8,6,1,7,2,0,5
	db	2,5,8,1,4,3,6,7,9,0
	;;;	Demo: see if the argument on the MS-DOS command line is valid
demo:	xor	bh,bh	; Zero-terminate the input
	mov	bl,[80h]
	mov	[bx+81h],bh
	mov	si,82h	; Start of input skipping first space
	call	damm	; Is it valid?
	mov	dx,ok	; If so, print OK
	jz	.print
	mov	dx,no 	; Otherwise, print NOT OK
.print:	mov	ah,9
	int	21h
	ret
section	.data
no:	db	'NOT '
ok: 	db	'OK$'
Output:
C:\>damm86 5724
OK
C:\>damm86 5725
NOT OK
C:\>damm86 112946
OK
C:\>damm86 112949
NOT OK


BYTE FUNC Damm(CHAR ARRAY a)
  BYTE ARRAY table=[
    0 3 1 7 5 9 8 6 4 2
    7 0 9 2 1 5 4 8 6 3
    4 2 0 6 8 7 1 3 5 9
    1 7 5 0 9 8 3 4 2 6
    6 1 2 3 0 4 5 9 7 8
    3 6 7 4 2 0 9 5 8 1
    5 8 6 9 7 2 0 1 3 4
    8 9 4 5 3 6 2 0 1 7
    9 4 3 8 6 1 7 2 0 5
    2 5 8 1 4 3 6 7 9 0]
  BYTE i,x,c

  x=0
  FOR i=1 TO a(0)
  DO
    c=a(i)
    IF c<'0 OR c>'9 THEN
      RETURN (0)
    FI
    c==-'0
    x=table(x*10+c)
  OD
  IF x=0 THEN
    RETURN (1)
  FI
RETURN (0)

PROC Test(CHAR ARRAY a)
  BYTE i

  Print(a) Print(" -> ")
  IF Damm(a)=1 THEN
    PrintE("valid")
  ELSE
    PrintE("invalid")
  FI
RETURN

PROC Main()
  Test("5724")
  Test("5727")
  Test("112946")
  Test("112949")
RETURN
Output:

Screenshot from Atari 8-bit computer

5724 -> valid
5727 -> invalid
112946 -> valid
112949 -> invalid
with Ada.Text_IO;

procedure Damm_Algorithm is

   function Damm (Input : in String) return Boolean
   is
      subtype Digit is Character range '0' .. '9';

      Table : constant array (Digit, Digit) of Digit :=
        (('0', '3', '1', '7', '5', '9', '8', '6', '4', '2'),
         ('7', '0', '9', '2', '1', '5', '4', '8', '6', '3'),
         ('4', '2', '0', '6', '8', '7', '1', '3', '5', '9'),
         ('1', '7', '5', '0', '9', '8', '3', '4', '2', '6'),
         ('6', '1', '2', '3', '0', '4', '5', '9', '7', '8'),
         ('3', '6', '7', '4', '2', '0', '9', '5', '8', '1'),
         ('5', '8', '6', '9', '7', '2', '0', '1', '3', '4'),
         ('8', '9', '4', '5', '3', '6', '2', '0', '1', '7'),
         ('9', '4', '3', '8', '6', '1', '7', '2', '0', '5'),
         ('2', '5', '8', '1', '4', '3', '6', '7', '9', '0'));
      Intern : Digit := '0';
   begin
      for D of Input loop
         Intern := Table (Intern, D);
      end loop;
      return Intern = '0';
   end Damm;

   procedure Put_Damm (Input : in String) is
      use Ada.Text_IO;
   begin
      Put_Line ("Damm of " & Input & " validates as " & Damm (Input)'Image);
   end Put_Damm;

begin
   Put_Damm ("5724");
   Put_Damm ("5727");
   Put_Damm ("112946");
   Put_Damm ("112949");
end Damm_Algorithm;
Output:
Damm of 5724 validates as TRUE
Damm of 5727 validates as FALSE
Damm of 112946 validates as TRUE
Damm of 112949 validates as FALSE
Translation of: ALGOL 68 – via Pluto
scope # Damm Algorithm

    # returns true  if the check digit of s is correct according to the Damm algorithm,
    #         false otherwise #
    local proc hasValidDammCheckDigit( s :: string ) :: boolean

        local constant operationTable
            := seq( (/ 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 \) # as per wikipedia example
                  , (/ 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 \)
                  , (/ 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 \)
                  , (/ 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 \)
                  , (/ 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 \)
                  , (/ 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 \)
                  , (/ 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 \)
                  , (/ 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 \)
                  , (/ 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 \)
                  , (/ 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 \)
                  );
        local interimDigit := 0;
        for sPos to size s do
            local constant nextDigit := abs s[ sPos ] - abs "0";
            if 0 <= nextDigit and nextDigit <= 9 then
                interimDigit := operationTable[ interimDigit + 1, nextDigit + 1 ]
            else
                error( "Invalid Damm digit: [" & s[ sPos ] & "]" )
            fi
        od;
        return interimDigit = 0
    end;
 
    local proc testDammAlgorithm( s :: string, expectedResult :: boolean )
        local constant isValid := hasValidDammCheckDigit( s );
        printf( "check digit of %s is %s%s\n", s
              , if isValid then "valid" else "invalid" fi
              , if isValid == expectedResult then "" else " *** NOT AS EXPECTED" fi
              )
    end;

    # test cases
    testDammAlgorithm( "5724",   true  );
    testDammAlgorithm( "5727",   false );
    testDammAlgorithm( "112946", true  )
end
Output:

Same as Algol 68 and Pluto.

BEGIN
    # returns TRUE if the check digit of s is correct according to the Damm algorithm, #
    # FALSE otherwise #
    PROC has valid damm check digit = ( STRING s )BOOL:
         BEGIN
            # operation table - as per wikipedia example #
            [,]INT operation table = ( ( 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 )
                                     , ( 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 )
                                     , ( 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 )
                                     , ( 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 )
                                     , ( 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 )
                                     , ( 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 )
                                     , ( 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 )
                                     , ( 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 )
                                     , ( 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 )
                                     , ( 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 )
                                     );
            INT interim digit := 0;
            FOR s pos FROM LWB s TO UPB s DO
                INT next digit = ABS s[ s pos ] - ABS "0";
                IF next digit < 0 OR next digit > 9 THEN
                    # invalid digit #
                    print( ( "Invalid damm digit: ", s[ s pos ], newline ) );
                    stop
                ELSE
                    # have a valid digit #
                    interim digit := operation table[ interim digit + 1, next digit + 1 ]
                FI
            OD;
            interim digit = 0
         END # has valid damm check digit # ;
 
    # test the damm algorithm #
    PROC test damm algorithm = ( STRING s, BOOL expected )VOID:
         BEGIN
            BOOL valid = has valid damm check digit( s );
            print( ( "check digit of ", s, " is "
                   , IF valid THEN "valid" ELSE "invalid" FI
                   , IF valid = expected THEN "" ELSE " *** NOT AS EXPECTED" FI
                   , newline
                   )
                 )
         END # test damm algorithm # ;
    # test cases #
    test damm algorithm( "5724",   TRUE  );
    test damm algorithm( "5727",   FALSE );
    test damm algorithm( "112946", TRUE  )
END
Output:
check digit of 5724 is valid
check digit of 5727 is invalid
check digit of 112946 is valid
Works with: Dyalog APL

This is a function that takes a vector of digits and returns a boolean.

 damm{⎕IO0
    tbl⍉⍪0 3 1 7 5 9 8 6 4 2
    tbl 7 0 9 2 1 5 4 8 6 3
    tbl 4 2 0 6 8 7 1 3 5 9
    tbl 1 7 5 0 9 8 3 7 2 6
    tbl 6 1 2 3 0 4 5 9 7 8
    tbl 3 6 7 4 2 0 9 5 8 1
    tbl 5 8 6 9 7 2 0 1 3 4
    tbl 8 9 4 5 3 6 2 0 1 7
    tbl 9 4 3 8 6 1 7 2 0 5
    tbl 2 5 8 1 4 3 6 7 9 0
    0={tbl[;]}/0,
 }
Output:
      damm 5 7 2 4
1
      damm 5 7 2 5
0
      damm 1 1 2 9 4 6
1
      damm 1 1 2 9 4 9
0
-- Return a check digit value for the given integer value or numeric string.
-- The result is 0 if the input's last digit is already a valid check digit for it.
on damm(n)
    set digits to {n mod 10}
    set n to n div 10
    repeat until (n is 0)
        set beginning of digits to n mod 10
        set n to n div 10
    end repeat
    
    script o
        property table : {0, 3, 1, 7, 5, 9, 8, 6, 4, 2, ¬
            7, 0, 9, 2, 1, 5, 4, 8, 6, 3, ¬
            4, 2, 0, 6, 8, 7, 1, 3, 5, 9, ¬
            1, 7, 5, 0, 9, 8, 3, 4, 2, 6, ¬
            6, 1, 2, 3, 0, 4, 5, 9, 7, 8, ¬
            3, 6, 7, 4, 2, 0, 9, 5, 8, 1, ¬
            5, 8, 6, 9, 7, 2, 0, 1, 3, 4, ¬
            8, 9, 4, 5, 3, 6, 2, 0, 1, 7, ¬
            9, 4, 3, 8, 6, 1, 7, 2, 0, 5, ¬
            2, 5, 8, 1, 4, 3, 6, 7, 9, 0}
    end script
    set interim to 0
    repeat with d in digits
        set interim to item (interim * 10 + d + 1) of o's table -- AppleScript indices are 1-based.
    end repeat
    
    return interim
end damm

-- Task code:
local testNumbers, possibilities, output, n
set testNumbers to {5724, 57240, 572400, 87591, 100}
-- Include a number with a check digit actually generated by the handler.
tell (random number 1000000) to set end of testNumbers to it * 10 + (my damm(it))
set possibilities to {" is invalid", " is valid"}
set output to {}
repeat with n in testNumbers
    set end of output to (n as text) & item (((damm(n) is 0) as integer) + 1) of possibilities
end repeat
return output
Output:
{"5724 is valid", "57240 is valid", "572400 is valid", "87591 is invalid", "100 is invalid", "3922446 is valid"}
.text
.global	_start
	@@@	Check if the zero-terminated ASCII string in [r0],
	@@@	which should contain a decimal number, has a
	@@@	matching check digit. Zero flag set if true,
	@@@	check digit returned in r0.
damm:	mov	r1,#0		@ R1 = interim digit
	ldr	r2,=3f		@ R2 = table base address
1:	ldrb	r3,[r0],#1	@ Load byte
	tst	r3,r3		@ Zero yet?
	beq	2f		@ If so, stop
	sub	r3,r3,#'0	@ Subtract ASCII 0
	lsl	r1,r1,#1	@ Table lookup 
	add	r1,r1,r1,lsl#2	@ R3 = R1*10 + R3
	add	r3,r1,r3
	ldrb	r1,[r2,r3]	@ R1 = new interim digit
	b	1b		@ Next value
2:	movs	r0,r1		@ Set flag according to r0.
	bx	lr
3:	.byte	0,3,1,7,5,9,8,6,4,2	@ Since the table is constant,
	.byte	7,0,9,2,1,5,4,8,6,3	@ it can be stored as part of
	.byte	4,2,0,6,8,7,1,3,5,9	@ the subroutine.
	.byte	1,7,5,0,9,8,3,4,2,6	@ This way the OS will even mark
	.byte	6,1,2,3,0,4,5,9,7,8	@ it as read-only, so we can
	.byte	3,6,7,4,2,0,9,5,8,1	@ be sure nothing changes it.
	.byte	5,8,6,9,7,2,0,1,3,4
	.byte	8,9,4,5,3,6,2,0,1,7
	.byte	9,4,3,8,6,1,7,2,0,5
	.byte	2,5,8,1,4,3,6,7,9,0
.align	4			@ Instructions must be word-aligned
	@@@	Grab the argument from the command line, and see
	@@@	if it matches.
_start:	pop	{r0}		@ Is there even an argument?
	cmp 	r0,#2
	movne	r7,#1		@ If not, exit immediately
	swine	#0
	add	sp,sp,#4	@ Discard program name
	pop	{r0}		@ Grab argument
	bl	damm		@ Check if it matches
	ldreq	r1,=pass	@ If yes, say 'pass'
	ldrne	r1,=fail	@ If not, say 'fail'
	mov	r0,#1		@ Print string to stdout
	mov	r2,#5		@ Both are 5 characters
	mov	r7,#4		@ Write syscall = 4
	swi	#0
	mov	r0,#0		@ Exit
	mov	r7,#1
	swi	#0 
pass:	.ascii	"Pass\n"
fail:	.ascii	"Fail\n"
Output:
$ for x in 5724 5725 112946 112949; do echo -n $x:; ./damm $x; done
5724:Pass
5725:Fail
112946:Pass
112949:Fail
; by @Krenium

table: [
    [0 3 1 7 5 9 8 6 4 2]
    [7 0 9 2 1 5 4 8 6 3]
    [4 2 0 6 8 7 1 3 5 9]
    [1 7 5 0 9 8 3 4 2 6]
    [6 1 2 3 0 4 5 9 7 8]
    [3 6 7 4 2 0 9 5 8 1]
    [5 8 6 9 7 2 0 1 3 4]
    [8 9 4 5 3 6 2 0 1 7]
    [9 4 3 8 6 1 7 2 0 5]
    [2 5 8 1 4 3 6 7 9 0]
]

damm?: function [z][zero? fold digits to :integer z .seed: 0 [x y]-> table\[x]\[y] ]

; Or, being more explicit:
digits2: function [str][
    chars: split str
    result: map chars 'ch -> to :integer ch
    return result
]

damm2?: function [str][
    d: digits2 str
    r: fold d .seed: 0 [x y] -> get get table x y
    return r = 0
]

test: function [str][
    result: switch damm? str -> "valid"
                             -> "invalid"
    print [str "is" result]
]

loop ["5724" "5727" "112946" "112949"] => test
Output:
5724 is valid 
5727 is invalid 
112946 is valid 
112949 is invalid
Damm(num){
	row := 1, Damm := [[0,3,1,7,5,9,8,6,4,2]
			  ,[7,0,9,2,1,5,4,8,6,3]
			  ,[4,2,0,6,8,7,1,3,5,9]
			  ,[1,7,5,0,9,8,3,4,2,6]
			  ,[6,1,2,3,0,4,5,9,7,8]
			  ,[3,6,7,4,2,0,9,5,8,1]
			  ,[5,8,6,9,7,2,0,1,3,4]
			  ,[8,9,4,5,3,6,2,0,1,7]
			  ,[9,4,3,8,6,1,7,2,0,5]
			  ,[2,5,8,1,4,3,6,7,9,0]]
	for i, v in StrSplit(SubStr(num, 1, -1)){
		++row := Damm[row, v+1]
	}
	return (SubStr(num, 0)=row-1 && !Damm[row, row])
}

Examples:

result := ""
for i, num in [5724, 5727, 112946, 112949]
	result .= num "`tis " (Damm(num) ? "valid" : "not valid") "`n"
MsgBox % result

Outputs:

5724	is valid
5727	is not valid
112946	is valid
112949	is not valid
# syntax: GAWK -f DAMM_ALGORITHM.AWK
BEGIN {
    damm_init()
    leng = split("5724,5727,112946",arr,",") # test cases
    for (i=1; i<=leng; i++) {
      n = arr[i]
      printf("%s %s\n",damm_check(n),n)
    }
    exit(0)
}
function damm_check(n,  a,i) {
    a = 0
    for (i=1; i<=length(n); i++) {
      a = substr(damm[a],substr(n,i,1)+1,1)
    }
    return(a == 0 ? "T" : "F")
}
function damm_init() {
#              0123456789
    damm[0] = "0317598642"
    damm[1] = "7092154863"
    damm[2] = "4206871359"
    damm[3] = "1750983426"
    damm[4] = "6123045978"
    damm[5] = "3674209581"
    damm[6] = "5869720134"
    damm[7] = "8945362017"
    damm[8] = "9438617205"
    damm[9] = "2581436790"
}
Output:
T 5724
F 5727
T 112946
Translation of: GW-BASIC
Works with: Decimal BASIC
100 REM Damm algorithm
110 OPTION BASE 0
120 DIM DT(9, 9)
130 FOR Y = 0 TO 9
140    FOR X = 0 TO 9
150       READ DT(X, Y)
160    NEXT X
170 NEXT Y
180 INPUT N$
190 DO WHILE N$ <> ""
200    LET D = 0
210    FOR I = 1 TO LEN(N$)
220       LET D = DT(VAL(MID$(N$, I, 1)), D)
230    NEXT I
240    IF D <> 0 THEN PRINT "FAIL" ELSE PRINT "PASS"
250    INPUT N$
260 LOOP
270 DATA 0, 3, 1, 7, 5, 9, 8, 6, 4, 2
280 DATA 7, 0, 9, 2, 1, 5, 4, 8, 6, 3
290 DATA 4, 2, 0, 6, 8, 7, 1, 3, 5, 9
300 DATA 1, 7, 5, 0, 9, 8, 3, 4, 2, 6
310 DATA 6, 1, 2, 3, 0, 4, 5, 9, 7, 8
320 DATA 3, 6, 7, 4, 2, 0, 9, 5, 8, 1
330 DATA 5, 8, 6, 9, 7, 2, 0, 1, 3, 4
340 DATA 8, 9, 4, 5, 3, 6, 2, 0, 1, 7
350 DATA 9, 4, 3, 8, 6, 1, 7, 2, 0, 5
360 DATA 2, 5, 8, 1, 4, 3, 6, 7, 9, 0
370 END
Output:
? 5724
PASS
? 5727
FAIL
? 112946
PASS
? 112949
FAIL
? 
arraybase 1
global matrix
matrix = {{0, 3, 1, 7, 5, 9, 8, 6, 4, 2}, {7, 0, 9, 2, 1, 5, 4, 8, 6, 3}, {4, 2, 0, 6, 8, 7, 1, 3, 5, 9}, {1, 7, 5, 0, 9, 8, 3, 4, 2, 6}, {6, 1, 2, 3, 0, 4, 5, 9, 7, 8}, {3, 6, 7, 4, 2, 0, 9, 5, 8, 1}, {5, 8, 6, 9, 7, 2, 0, 1, 3, 4}, {8, 9, 4, 5, 3, 6, 2, 0, 1, 7}, {9, 4, 3, 8, 6, 1, 7, 2, 0, 5}, {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}}
test = {5724, 5727, 112946}

for i = 1 to 3
	print "Checksum test: "; rjust(string(test[i]),8); encode(test[i])
next i
end

function encode(n)
	cad = string(n)
	check = 0
	for d = 1 to length(cad)
		check = matrix[int(mid(cad, d, 1)), d]
	next d
	if check = 0 then
		return " is valid"
	else
		return " is invalid"
	end if
end function
Output:
Similar to FreeBASIC entry.
' version 04-07-2018
' compile with: fbc -s console

Function Damm(digit_str As String) As UInteger

    Dim As UInteger table(10,10) => { { 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 } , _
   { 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 } , { 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 } , _
   { 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 } , { 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 } , _
   { 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 } , { 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 } , _
   { 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 } , { 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 } , _
   { 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 } }

    Dim As UInteger i, col_i, old_row_i, new_row_i

    For i = 0 To Len(digit_str) -1
        col_i = digit_str[i] - Asc("0")
        new_row_i = table(old_row_i, col_i)
        old_row_i = new_row_i
    Next

    Return new_row_i

End Function

' ------=< MAIN >=------

Data "5724", "5727", "112946", ""

Dim As UInteger checksum, t
Dim As String test_string

Do

    Read test_string
    If test_string = "" Then Exit Do
    Print "Checksum test: ";test_string;

    checksum = Damm(test_string)
    If checksum = 0 Then
        Print " is valid"
    Else
        Print " is invalid"
    End If

Loop

' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
Output:
Checksum test: 5724 is valid
Checksum test: 5727 is invalid
Checksum test: 112946 is valid
Works with: BASICA
10 DEFINT D,I,X,Y: DIM DT(9,9)
20 FOR Y=0 TO 9: FOR X=0 TO 9: READ DT(X,Y): NEXT X,Y
30 INPUT N$: IF N$="" THEN END
40 D=0
50 FOR I=1 TO LEN(N$): D=DT(VAL(MID$(N$,I,1)),D): NEXT I
60 IF D THEN PRINT "FAIL" ELSE PRINT "PASS"
70 GOTO 30
100 DATA 0,3,1,7,5,9,8,6,4,2
110 DATA 7,0,9,2,1,5,4,8,6,3
120 DATA 4,2,0,6,8,7,1,3,5,9
130 DATA 1,7,5,0,9,8,3,4,2,6
140 DATA 6,1,2,3,0,4,5,9,7,8
150 DATA 3,6,7,4,2,0,9,5,8,1
160 DATA 5,8,6,9,7,2,0,1,3,4
170 DATA 8,9,4,5,3,6,2,0,1,7
180 DATA 9,4,3,8,6,1,7,2,0,5
190 DATA 2,5,8,1,4,3,6,7,9,0
Output:
? 5724
PASS
? 5727
FAIL
? 112946
PASS
? 112949
FAIL
Works with: Just BASIC
Dim DT(9, 9)

For y = 0 To 9
    For x = 0 To 9
        Read val
        DT(x, y) = val
    Next x
Next y

Input check$
While (check$ <> "")
    D = 0
    For i = 1 To Len(check$)
        D = DT(Val(Mid$(check$, i, 1)), D)
    Next i
    If D Then
        Print "Invalid"
    Else
        Print "Valid"
    End If
    Input check$
Wend
End

DATA 0,3,1,7,5,9,8,6,4,2
DATA 7,0,9,2,1,5,4,8,6,3
DATA 4,2,0,6,8,7,1,3,5,9
DATA 1,7,5,0,9,8,3,4,2,6
DATA 6,1,2,3,0,4,5,9,7,8
DATA 3,6,7,4,2,0,9,5,8,1
DATA 5,8,6,9,7,2,0,1,3,4
DATA 8,9,4,5,3,6,2,0,1,7
DATA 9,4,3,8,6,1,7,2,0,5
DATA 2,5,8,1,4,3,6,7,9,0
Output:
?5724
Valid
?5727
Invalid
?112946
Valid
?112949
Invalid
Translation of: GW-BASIC
Works with: Nascom ROM BASIC version 4.7
10 REM Damm algorithm
20 DIM DT(9,9)
30 FOR Y=0 TO 9:FOR X=0 TO 9
40 READ DT(X,Y)
50 NEXT X:NEXT Y
60 N$="":INPUT N$:IF N$="" THEN 130
70 D=0
80 FOR I=1 TO LEN(N$)
90 D=DT(VAL(MID$(N$,I,1)),D)
100 NEXT I
110 IF D THEN PRINT "FAIL":GOTO 60 
120 PRINT "PASS":GOTO 60
130 END
140 DATA 0,3,1,7,5,9,8,6,4,2
150 DATA 7,0,9,2,1,5,4,8,6,3
160 DATA 4,2,0,6,8,7,1,3,5,9
170 DATA 1,7,5,0,9,8,3,4,2,6
180 DATA 6,1,2,3,0,4,5,9,7,8
190 DATA 3,6,7,4,2,0,9,5,8,1
200 DATA 5,8,6,9,7,2,0,1,3,4
210 DATA 8,9,4,5,3,6,2,0,1,7
220 DATA 9,4,3,8,6,1,7,2,0,5
230 DATA 2,5,8,1,4,3,6,7,9,0
Output:
? 5724
PASS
? 5727
FAIL
? 112946
PASS
? 112949
FAIL
? 
DataSection
  DT_Start:
        Data.b	0,3,1,7,5,9,8,6,4,2	
	Data.b	7,0,9,2,1,5,4,8,6,3	
	Data.b	4,2,0,6,8,7,1,3,5,9
	Data.b	1,7,5,0,9,8,3,4,2,6
	Data.b	6,1,2,3,0,4,5,9,7,8
	Data.b	3,6,7,4,2,0,9,5,8,1
	Data.b	5,8,6,9,7,2,0,1,3,4
	Data.b	8,9,4,5,3,6,2,0,1,7
	Data.b	9,4,3,8,6,1,7,2,0,5
	Data.b	2,5,8,1,4,3,6,7,9,0  	
EndDataSection

Procedure.i Adr(Row,Col) : ProcedureReturn ?DT_Start+Row+10*Col : EndProcedure

Procedure.b CheckDamm(Value.s)
  *ipc.Character=@Value : it=0  
  While *ipc\c
    it=PeekB(Adr(*ipc\c-'0',it)) : *ipc+SizeOf(Character)
  Wend
  ProcedureReturn Bool(it)
EndProcedure

If OpenConsole()
  Repeat
    Print("Check Damm: ") : i$=Input()
    If CheckDamm(i$) : PrintN(Space(12)+"FALSE") : Else : PrintN(Space(12)+"TRUE") : EndIf
  Until i$=""
EndIf
End
Output:
Check Damm: 5724
            TRUE
Check Damm: 5727
            FALSE
Check Damm: 112946
            TRUE
Check Damm: 112949
            FALSE
Check Damm: 
Translation of: Visual Basic .NET
Works with: v3.64
Push 0, 3, 1, 7, 5, 9, 8, 6, 4, 2: i = FUNC(_Data(0))
Push 7, 0, 9, 2, 1, 5, 4, 8, 6, 3: i = FUNC(_Data(i))
Push 4, 2, 0, 6, 8, 7, 1, 3, 5, 9: i = FUNC(_Data(i))
Push 1, 7, 5, 0, 9, 8, 3, 4, 2, 6: i = FUNC(_Data(i))
Push 6, 1, 2, 3, 0, 4, 5, 9, 7, 8: i = FUNC(_Data(i))
Push 3, 6, 7, 4, 2, 0, 9, 5, 8, 1: i = FUNC(_Data(i))
Push 5, 8, 6, 9, 7, 2, 0, 1, 3, 4: i = FUNC(_Data(i))
Push 8, 9, 4, 5, 3, 6, 2, 0, 1, 7: i = FUNC(_Data(i))
Push 9, 4, 3, 8, 6, 1, 7, 2, 0, 5: i = FUNC(_Data(i))
Push 2, 5, 8, 1, 4, 3, 6, 7, 9, 0: i = FUNC(_Data(i))
                                       ' Read the table
Push 112949, 112946, 5727, 5724        ' Put numbers on the stack

For i = 1 To Used()                    ' Read up to the number of stack items
  Print Using "______"; Tos();" is ";  ' Print the header
  If FUNC(_Damm (Str(Pop()))) Then Print "in";
  Print "valid"                        ' invalid only if Damm() returns TRUE
Next                                   ' Next stack item

End

_Data Param (1)                        ' Reads data in reverse order,
  Local (2)                            ' starting with A@
  
  c@ = a@ + Used()                     ' Calculate next offset

  For b@ = c@-1 To a@ Step -1          ' Now place the elements 
    @(b@) = Pop()                      ' that are retrieved from the stack
  Next b@                              ' Next item

Return (c@)                            ' Return new offset


_Damm Param (1)                        ' Perform the Damm algorithm
  Local (2)                            

  c@ = 0                               ' Reset the flag
  For b@ = 0 To Len(a@) - 1            ' Check all characters in the string
    c@ = @(c@*10 + peek(a@, b@) - ord("0"))
  Next                                 ' Next character

Return (c@)                            ' Return Flag
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid

0 OK, 0:984

Although the output of this version is virtually identical, it uses uBasic/4tH features consistently and is consequently much shorter.

Proc _IsDamm (5724)
Proc _IsDamm (5727)
Proc _IsDamm (112946)
Proc _IsDamm (112949)

End

_Damm
   Param (1)
   Local (1)

   b@ := "0317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790"

   Do Until a@ = 0                     ' until number is consumed
     Push a@ % 10 : a@ = a@ / 10       ' extract digit and put on stack
   Loop

   Do While Used ()                    ' last number retrieved?
     a@ = Peek(b@, (a@ * 10) + Pop ()) - Ord ("0")
   Loop                                ' calculate checksum
Return (a@)                            ' return checksum

_IsDamm                                ' evaluate and print checksum
  Param (1)
  Print Using "______";a@;" is ";Show (Iif (Func (_Damm (a@)), "invalid", "valid"))
Return
Translation of: C#
Module Module1

    ReadOnly table = {
            {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
            {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
            {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
            {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
            {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
            {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
            {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
            {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
            {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
            {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}
        }

    Function Damm(s As String) As Boolean
        Dim interim = 0
        For Each c In s
            interim = table(interim, AscW(c) - AscW("0"))
        Next
        Return interim = 0
    End Function

    Sub Main()
        Dim numbers = {5724, 5727, 112946, 112949}
        For Each number In numbers
            Dim isvalid = Damm(number.ToString())
            If isvalid Then
                Console.WriteLine("{0,6} is valid", number)
            Else
                Console.WriteLine("{0,6} is invalid", number)
            End If
        Next
    End Sub

End Module
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
get "libhdr"

let Damm(ns) = valof
$(  let dt = table
        0,3,1,7,5,9,8,6,4,2,
        7,0,9,2,1,5,4,8,6,3,
        4,2,0,6,8,7,1,3,5,9,
        1,7,5,0,9,8,3,4,2,6,
        6,1,2,3,0,4,5,9,7,8,
        3,6,7,4,2,0,9,5,8,1,
        5,8,6,9,7,2,0,1,3,4,
        8,9,4,5,3,6,2,0,1,7,
        9,4,3,8,6,1,7,2,0,5,
        2,5,8,1,4,3,6,7,9,0
    let idgt = 0
    for i=1 to ns%0
        test '0' <= ns%i <= '9'
            do idgt := dt!(ns%i-'0' + 10*idgt)
            or resultis false
    resultis idgt = 0
$)

let check(ns) be
    writef("%S: %S*N", ns, damm(ns) -> "pass", "fail")
 
let start() be
$(  check("5724")
    check("5727")
    check("112946")
    check("112949")
$)
Output:
5724: pass
5727: fail
112946: pass
112949: fail

Translation of: J

table  > 0317598642
           7092154863
           4206871359
           1750983426
           6123045978
           3674209581
           5869720134
           8945362017
           9438617205
           2581436790 


Digits  10{𝕗|⌊÷𝕗(1+·𝕗1⌈⊢)}

Damm  {0=0(table˜)˜´⌽Digits 𝕩}

Damm¨57245727112946
⟨ 1 0 1 ⟩

Try It!

C

#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>

bool damm(unsigned char *input, size_t length) {
    static const unsigned char table[10][10] = {
        {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
        {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
        {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
        {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
        {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
        {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
        {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
        {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
        {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
        {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
    };
    
    unsigned char interim = 0;
    for (size_t i = 0; i < length; i++) {
        interim = table[interim][input[i]];
    }
    return interim == 0;
}

int main() {
    unsigned char input[4] = {5, 7, 2, 4};
    puts(damm(input, 4) ? "Checksum correct" : "Checksum incorrect");
    return 0;
}
Output:
Checksum correct
Translation of: Java
using System;

namespace DammAlgorithm {
    class Program {
        static int[,] table = {
            {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
            {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
            {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
            {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
            {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
            {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
            {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
            {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
            {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
            {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
        };

        static bool Damm(string s) {
            int interim = 0;
            foreach (char c in s) {
                interim = table[interim, c - '0'];
            }
            return interim == 0;
        }

        static void Main(string[] args) {
            int[] numbers = { 5724, 5727, 112946, 112949 };
            foreach (int number in numbers) {
                bool isValid = Damm(number.ToString());
                if (isValid) {
                    Console.WriteLine("{0,6} is valid", number);
                }
                else {
                    Console.WriteLine("{0,6} is invalid", number);
                }
            }
        }
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid

Version 1

Translation of: C# – C sharp
#include <string>

#include <cstdio>

inline constexper int TABLE[][10] = {
	{0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
	{7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
	{4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
	{1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
	{6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
	{3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
	{5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
	{8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
	{9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
	{2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
};

[[nodiscard]] bool damm(std::string s) noexcept {
	int interim = 0;
	for (const auto c : s) {
		interim = TABLE[interim][c - '0'];
	}
	return interim == 0;
}

int main() {
	for (const auto num : { 5724, 5727, 112946, 112949 }) {
		if (damm(std::to_string(num))) {
	 	 	std::printf("%6d is valid\n", num);
		}	
		else std::printf("%6d is invalid\n", num);
	}
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid

Version 2

// Compile with:
// g++ -std=c++20 -Wall -Wextra -pedantic damm.cpp -o damm

#include <iostream>
#include <array> // for std::array
#include <string> // for std::string, std::to_string and std::string::find

const std::array<std::array<int, 10>, 10> table = {{ // Operation table
    {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
    {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
    {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
    {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
    {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
    {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
    {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
    {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
    {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
    {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}
}};

bool damm(int input) {
    int interim = 0; // initialise to 0
    const std::string digit = "0123456789";
    for (const auto c : std::to_string(input))
        interim = table[interim][digit.find(c)];
    // Process the number digit by digit:
    //   1. The column index = number's digit
    //   2. The row index = interim digit
    //   3. Replace interim digit with table entry (table[<interim digit>][<number's digit>])
    return interim == 0; // Is interim digit equals zero? If so, the input is valid, invalid otherwise.
}

int main() {
    for (const auto num : {5724, 5727, 112946, 112949})
        std::cout << num << "\t" << "Checksum is " << (damm(num) ? "valid" : "invalid") << std::endl;
    return 0;
}
Output:
5724	Checksum is valid
5727	Checksum is invalid
112946	Checksum is valid
112949	Checksum is invalid
Class Utils.Check [ Abstract ]
{

ClassMethod Damm(num As %Integer, mode As %Integer = 1) As %Integer
{
	TRY {
		I mode=0 RETURN ..Damm(num,2)=0
		S res=0, str=num
		S table=[
			[0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
			[7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
			[4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
			[1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
			[6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
			[3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
			[5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
			[8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
			[9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
			[2, 5, 8, 1, 4, 3, 6, 7, 9, 0]
		]
		F i=1:1:$L(str) S res=table.%Get(res).%Get($E(str,i))
		I mode=1 S res=num_res
	} CATCH {
		S res=""
	}
	Q res
}

}
Examples:
USER>For  { Read n Quit:n=""  Write ": "_##class(Utils.Check).Damm(n, 0), ! }
5724: 1
5727: 0
112946: 1
112949: 0

USER>w ##class(Utils.Check).Damm(11294)
112946
USER>
(def tbl [[0 3 1 7 5 9 8 6 4 2]
          [7 0 9 2 1 5 4 8 6 3]
          [4 2 0 6 8 7 1 3 5 9]
          [1 7 5 0 9 8 3 4 2 6]
          [6 1 2 3 0 4 5 9 7 8]
          [3 6 7 4 2 0 9 5 8 1]
          [5 8 6 9 7 2 0 1 3 4]
          [8 9 4 5 3 6 2 0 1 7]
          [9 4 3 8 6 1 7 2 0 5]
          [2 5 8 1 4 3 6 7 9 0]])

(defn damm? [digits]
  (= 0 (reduce #(nth (nth tbl %1) %2) 0 
    (map #(Character/getNumericValue %) (seq digits)))))
Output:
=> (damm? "5724")
true
=> (damm? "5727")
false
=> (damm? "112946")
true
% Verify that the Damm check digit of a string of digits is correct.
% Signals 'bad_format' if the string contains non-digits.
damm = proc (s: string) returns (bool) signals (bad_format)
    ai = array[int]
    aai = array[ai]
    own damm_table: aai := aai$[0: 
        ai$[0: 0,3,1,7,5,9,8,6,4,2],
        ai$[0: 7,0,9,2,1,5,4,8,6,3],
        ai$[0: 4,2,0,6,8,7,1,3,5,9],
        ai$[0: 1,7,5,0,9,8,3,4,2,6],
        ai$[0: 6,1,2,3,0,4,5,9,7,8],
        ai$[0: 3,6,7,4,2,0,9,5,8,1],
        ai$[0: 5,8,6,9,7,2,0,1,3,4],
        ai$[0: 8,9,4,5,3,6,2,0,1,7],
        ai$[0: 9,4,3,8,6,1,7,2,0,5],
        ai$[0: 2,5,8,1,4,3,6,7,9,0]
    ]
    
    interim: int := 0
    for c: char in string$chars(s) do
        d: int := int$parse(string$c2s(c)) resignal bad_format
        interim := damm_table[interim][d]
    end
    
    return(interim = 0)
end damm

% Checks
start_up = proc ()
    po: stream := stream$primary_output()
    tests: sequence[string] := sequence[string]$[
        "5724", "5727", "112946", "112949"
    ]
    
    for test: string in sequence[string]$elements(tests) do
        stream$puts(po, test || ": ")
        if damm(test) then
            stream$putl(po, "pass")
        else
            stream$putl(po, "fail")
        end
    end
end start_up
Output:
5724: pass
5727: fail
112946: pass
112949: fail
include "cowgol.coh";

# Damm test on number given as ASCII string
# Returns check digit
sub damm(num: [uint8]): (chk: uint8) is
    var table: uint8[] := {
        0,3,1,7,5,9,8,6,4,2,
        7,0,9,2,1,5,4,8,6,3,
        4,2,0,6,8,7,1,3,5,9,
        1,7,5,0,9,8,3,4,2,6,
        6,1,2,3,0,4,5,9,7,8,
        3,6,7,4,2,0,9,5,8,1,
        5,8,6,9,7,2,0,1,3,4,
        8,9,4,5,3,6,2,0,1,7,
        9,4,3,8,6,1,7,2,0,5,
        2,5,8,1,4,3,6,7,9,0
    };
    
    chk := 0;
    while [num] != 0 loop
        chk := table[(chk<<1) + (chk<<3) + ([num] - '0')];
        num := @next num;
    end loop;
end sub;

# Test and print
sub test(num: [uint8]) is
    print(num);
    print(":");
    if damm(num) == 0 then
        print("Pass\n");
    else
        print("Fail\n");
    end if;
end sub;

test("5724");
test("5727");
test("112946");
test("112949");
Output:
5724:Pass
5727:Fail
112946:Pass
112949:Fail

D

import std.stdio;

auto table = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
];

bool damm(string s) {
    int interim = 0;
    foreach (c; s) {
        interim = table[interim][c - '0'];
    }
    return interim == 0;
}

void main() {
    import std.conv : to;
    auto numbers = [5724, 5727, 112946, 112949];
    foreach (number; numbers) {
        bool isValid = damm(number.to!string());
        writef("%6d is ", number);
        if (isValid) {
            writeln("valid");
        } else {
            writeln("invalid");
        }
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid

See Pascal.

let table = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]
]

func damm(s) {
    var interim = 0
    for c in s {
        interim = table[interim][Integer(c)]
    }
    return interim == 0;
}

let numbers = [5724, 5727, 112946, 112949]
for number in numbers {
    let isValid = damm(number.ToString())
    if isValid {
        print("\(number) is valid")
    } else {
        print("\(number) is invalid")
    }
}
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
proc damm(*char str) bool:
    [10][10]byte dammtbl = (
        (0,3,1,7,5,9,8,6,4,2),
        (7,0,9,2,1,5,4,8,6,3),
        (4,2,0,6,8,7,1,3,5,9),
        (1,7,5,0,9,8,3,4,2,6),
        (6,1,2,3,0,4,5,9,7,8),
        (3,6,7,4,2,0,9,5,8,1),
        (5,8,6,9,7,2,0,1,3,4),
        (8,9,4,5,3,6,2,0,1,7),
        (9,4,3,8,6,1,7,2,0,5),
        (2,5,8,1,4,3,6,7,9,0)
    );
    byte interim;
    char c;
    channel input text ch;
    
    interim := 0;
    open(ch, str);
    while read(ch; c) do
        interim := dammtbl[interim][c-'0']
    od;
    close(ch);
    interim = 0
corp

proc check(*char str) void:
    writeln(str, ": ", if damm(str) then "pass" else "fail" fi)
corp

proc main() void:
    check("5724");
    check("5727");
    check("112946");
    check("112949");
corp
Output:
5724: pass
5727: fail
112946: pass
112949: fail
Translation of: Java
func damm inp$ .
   table[][] = [ [ 0 3 1 7 5 9 8 6 4 2 ] [ 7 0 9 2 1 5 4 8 6 3 ] [ 4 2 0 6 8 7 1 3 5 9 ] [ 1 7 5 0 9 8 3 4 2 6 ] [ 6 1 2 3 0 4 5 9 7 8 ] [ 3 6 7 4 2 0 9 5 8 1 ] [ 5 8 6 9 7 2 0 1 3 4 ] [ 8 9 4 5 3 6 2 0 1 7 ] [ 9 4 3 8 6 1 7 2 0 5 ] [ 2 5 8 1 4 3 6 7 9 0 ] ]
   inp[] = number strchars inp$
   for v in inp[]
      inter = table[inter + 1][v + 1]
   .
   return if inter = 0
.
nums[] = [ 5724 5727 112946 112949 ]
for v in nums[]
   write v & " is "
   if damm v = 1
      print "valid"
   else
      print "invalid"
   .
.

Place your number in A1 and the formula at any cell.

=REDUCE(0,MID(A1,SEQUENCE(1,LEN(A1)),1),LAMBDA(i,j,INDEX({0,3,1,7,5,9,8,6,4,2;7,0,9,2,1,5,4,8,6,3;4,2,0,6,8,7,1,3,5,9;1,7,5,0,9,8,3,4,2,6;6,1,2,3,0,4,5,9,7,8;3,6,7,4,2,0,9,5,8,1;5,8,6,9,7,2,0,1,3,4;8,9,4,5,3,6,2,0,1,7;9,4,3,8,6,1,7,2,0,5;2,5,8,1,4,3,6,7,9,0},i+1,j+1)))

For Google Sheets, you need to use arrayformula

=REDUCE(0,arrayformula(MID(A1,SEQUENCE(1,LEN(A1)),1)),lambda(i,j,INDEX({0,3,1,7,5,9,8,6,4,2;7,0,9,2,1,5,4,8,6,3;4,2,0,6,8,7,1,3,5,9;1,7,5,0,9,8,3,4,2,6;6,1,2,3,0,4,5,9,7,8;3,6,7,4,2,0,9,5,8,1;5,8,6,9,7,2,0,1,3,4;8,9,4,5,3,6,2,0,1,7;9,4,3,8,6,1,7,2,0,5;2,5,8,1,4,3,6,7,9,0},i+1,j+1)))

For countries that uses comma as a decimal divisor, use:

=REDUCE(0;MID(A2;SEQUENCE(1;LEN(A2));1);lambda(i;j;INDEX({0\3\1\7\5\9\8\6\4\2;7\0\9\2\1\5\4\8\6\3;4\2\0\6\8\7\1\3\5\9;1\7\5\0\9\8\3\4\2\6;6\1\2\3\0\4\5\9\7\8;3\6\7\4\2\0\9\5\8\1;5\8\6\9\7\2\0\1\3\4;8\9\4\5\3\6\2\0\1\7;9\4\3\8\6\1\7\2\0\5;2\5\8\1\4\3\6\7\9\0};i+1;j+1)))
open System

let TABLE = [|
    [|0; 3; 1; 7; 5; 9; 8; 6; 4; 2|];
    [|7; 0; 9; 2; 1; 5; 4; 8; 6; 3|];
    [|4; 2; 0; 6; 8; 7; 1; 3; 5; 9|];
    [|1; 7; 5; 0; 9; 8; 3; 4; 2; 6|];
    [|6; 1; 2; 3; 0; 4; 5; 9; 7; 8|];
    [|3; 6; 7; 4; 2; 0; 9; 5; 8; 1|];
    [|5; 8; 6; 9; 7; 2; 0; 1; 3; 4|];
    [|8; 9; 4; 5; 3; 6; 2; 0; 1; 7|];
    [|9; 4; 3; 8; 6; 1; 7; 2; 0; 5|];
    [|2; 5; 8; 1; 4; 3; 6; 7; 9; 0|];
|]

let damm str =
    let rec helper (v:string) interim =
        if v.Length = 0 then 0 = interim
        else helper (v.Substring(1)) (TABLE.[interim].[(int (v.[0])) - (int '0')])
    helper str 0
 
[<EntryPoint>]
let main _ = 
    let numbers = [|5724; 5727; 112946; 112949|]
    for number in numbers do
        let isValid = damm (number.ToString())
        if isValid then
            printfn "%6d is valid" number
        else
            printfn "%6d is invalid" number

    0 // return an integer exit code
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
USING: interpolate kernel math math.parser qw sequences ;

CONSTANT: table
{
    { 0 3 1 7 5 9 8 6 4 2 }
    { 7 0 9 2 1 5 4 8 6 3 }
    { 4 2 0 6 8 7 1 3 5 9 }
    { 1 7 5 0 9 8 3 4 2 6 }
    { 6 1 2 3 0 4 5 9 7 8 }
    { 3 6 7 4 2 0 9 5 8 1 }
    { 5 8 6 9 7 2 0 1 3 4 }
    { 8 9 4 5 3 6 2 0 1 7 }
    { 9 4 3 8 6 1 7 2 0 5 }
    { 2 5 8 1 4 3 6 7 9 0 }
}

: damm? ( str -- ? )
    0 [ digit> swap table nth nth ] reduce zero? ;

qw{ 5724 5727 112946 112949 }
[ dup damm? "" "in" ? [I ${} is ${}validI] nl ] each
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid


Works with: gforth version 0.7.3
: newdigit ( col row -- u ) 10 * + C" 0317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790" 1+ + c@ 48 - ;
: nextdigit ( addr -- addr+1 u ) dup c@ 48 - swap 1+ swap ;

: damm ( c u -- u )
0 rot rot
0 do
  nextdigit
  rot newdigit swap
loop drop
;

: isdamm? damm 0= if ." yes" else ." no" then ;

: .damm
2dup damm
rot rot type 48 + emit
;
Output:
s" 5724" isdamm? yes ok
s" 5727" isdamm? no ok
s" 572" .damm 5724 ok
module damm_algorithm
   implicit none
   private
   public :: damm_check  ! Expose only the damm_check function to external code

contains

   !---------------------------------------------------------------------
   ! Function: damm_check
   ! Purpose : Validates a digit string using the Damm algorithm
   ! Input   : digit - a character string of numeric digits ('0' to '9')
   ! Output  : is_valid - .TRUE. if the check digit validates, .FALSE. otherwise
   !---------------------------------------------------------------------
   function damm_check(digit) result(is_valid)
      use iso_fortran_env, only: int8  ! Use portable 8-bit integer type
      character(len=*), intent(in) :: digit
      logical :: is_valid
      integer(kind=int8) :: i, d, id

      !------------------------------------------------------------------
      ! Damm operation table: a 10x10 quasigroup matrix used for validation
      ! Note: Fortran stores arrays in column-major order, meaning that
      !       array constructors fill columns first, not rows.
      !       To preserve the intended row-wise layout of the table,
      !       we use TRANSPOSE(RESHAPE(...)) to correct the orientation.
      !------------------------------------------------------------------
      integer(kind=int8), parameter :: optable(0:9, 0:9) = transpose(reshape( &
         [integer(kind=int8) :: &
            0, 3, 1, 7, 5, 9, 8, 6, 4, 2, &  ! Row 0
            7, 0, 9, 2, 1, 5, 4, 8, 6, 3, &  ! Row 1
            4, 2, 0, 6, 8, 7, 1, 3, 5, 9, &  ! Row 2
            1, 7, 5, 0, 9, 8, 3, 4, 2, 6, &  ! Row 3
            6, 1, 2, 3, 0, 4, 5, 9, 7, 8, &  ! Row 4
            3, 6, 7, 4, 2, 0, 9, 5, 8, 1, &  ! Row 5
            5, 8, 6, 9, 7, 2, 0, 1, 3, 4, &  ! Row 6
            8, 9, 4, 5, 3, 6, 2, 0, 1, 7, &  ! Row 7
            9, 4, 3, 8, 6, 1, 7, 2, 0, 5, &  ! Row 8
            2, 5, 8, 1, 4, 3, 6, 7, 9, 0 ], & ! Row 9
         shape=[10, 10]))  ! Reshape into 10x10, then transpose to fix layout

      ! Initialize the interim digit to zero
      id = 0

      ! Loop over each character in the input string
      do i = 1, len(digit)
         ! Convert character to integer digit (ASCII math)
         d = iachar(digit(i:i)) - iachar('0')

         ! Validate that the character is a digit
         if (d < 0 .or. d > 9) then
            error stop 'Invalid input: Not a digit in string'
         end if

         ! Apply Damm algorithm step: lookup in the operation table
         id = optable(id, d)
      end do

      ! Final check: if result is zero, the input is valid
      is_valid = (id == 0)
   end function damm_check

end module damm_algorithm

program test_damm
   use damm_algorithm
   implicit none

   write(*, '(A,L1,A)') 'Damm check for "5724": ', damm_check('5724'), ' (should be .TRUE.)'
   write(*, '(A,L1,A)') 'Damm check for "5727": ', damm_check('5727'), ' (should be .FALSE.)'
   write(*, '(A,L1,A)') 'Damm check for "112946": ', damm_check('112946'), ' (should be .TRUE.)'
   write(*, '(A,L1,A)') 'Damm check for "112949": ', damm_check('112949'), ' (should be .FALSE.)'
end program test_damm
      END

Output:

Damm check for "5724": T (should be .TRUE.)
Damm check for "5727": F (should be .FALSE.)
Damm check for "112946": T (should be .TRUE.)
Damm check for "112949": F (should be .FALSE.)
Translation of: FreeBASIC
NSUInteger local fn Damm( string as CFStringRef )
  mda(0,0) = {{0,3,1,7,5,9,8,6,4,2},
  {7,0,9,2,1,5,4,8,6,3},{4,2,0,6,8,7,1,3,5,9},
  {1,7,5,0,9,8,3,4,2,6},{6,1,2,3,0,4,5,9,7,8},
  {3,6,7,4,2,0,9,5,8,1},{5,8,6,9,7,2,0,1,3,4},
  {8,9,4,5,3,6,2,0,1,7},{9,4,3,8,6,1,7,2,0,5},
  {2,5,8,1,4,3,6,7,9,0}}
  
  NSUInteger i, colI, oldRowI = 0, newRowI
  for i = 0 to len(string) - 1
    colI = intval(string[i])
    newRowI = mda(oldRowI,colI)
    oldRowI = newRowI
  next
end fn = newRowI

void local fn DoIt
  CFArrayRef dta = @[@"5724",@"5727",@"112946",@"112949"]
  for CFStringRef string in dta
    print string;
    if ( fn Damm( string ) == 0 )
      print @" is valid"
    else
      print @" is invalid"
    end if
  next
end fn

fn DoIt

HandleEvents
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

Test cases

package main

import "fmt"

var table = [10][10]byte{
    {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
    {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
    {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
    {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
    {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
    {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
    {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
    {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
    {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
    {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
}

func damm(input string) bool {
    var interim byte
    for _, c := range []byte(input) {
        interim = table[interim][c-'0']
    }
    return interim == 0
}

func main() {
    for _, s := range []string{"5724", "5727", "112946", "112949"} {
        fmt.Printf("%6s  %t\n", s, damm(s))
    }
}
Output:
  5724  true
  5727  false
112946  true
112949  false
Translation of: Java
class DammAlgorithm {
    private static final int[][] TABLE = [
        [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
        [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
        [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
        [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
        [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
        [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
        [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
        [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
        [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
        [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
    ]

    private static boolean damm(String s) {
        int interim = 0
        for (char c : s.toCharArray()) interim = TABLE[interim][c - ('0' as Character)]
        return interim == 0
    }

    static void main(String[] args) {
        int[] numbers = [5724, 5727, 112946, 112949]
        for (Integer number : numbers) {
            boolean isValid = damm(number.toString())
            if (isValid) {
                System.out.printf("%6d is valid\n", number)
            } else {
                System.out.printf("%6d is invalid\n", number)
            }
        }
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
import Data.Char   (digitToInt)
import Text.Printf (printf)

damm :: String -> Bool
damm = (==0) . foldl (\r -> (table !! r !!) . digitToInt) 0
  where
    table =
      [ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2]
      , [7, 0, 9, 2, 1, 5, 4, 8, 6, 3]
      , [4, 2, 0, 6, 8, 7, 1, 3, 5, 9]
      , [1, 7, 5, 0, 9, 8, 3, 4, 2, 6]
      , [6, 1, 2, 3, 0, 4, 5, 9, 7, 8]
      , [3, 6, 7, 4, 2, 0, 9, 5, 8, 1]
      , [5, 8, 6, 9, 7, 2, 0, 1, 3, 4]
      , [8, 9, 4, 5, 3, 6, 2, 0, 1, 7]
      , [9, 4, 3, 8, 6, 1, 7, 2, 0, 5]
      , [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ]

main :: IO ()
main = mapM_ (uncurry(printf "%6s is valid: %s\n") . ((,) <*> show . damm) . show)
  [5724, 5727, 112946, 112949]
Output:
  5724 is valid: True
  5727 is valid: False
112946 is valid: True
112949 is valid: False

The following works in both Icon and Unicon

procedure main(A)
   \A | stop("You must give one or more numeric values")
   every n := !A do write(n," is ",(damm(n),"valid")|"not valid")
end

procedure damm(n)
   static grid
   initial grid := [[0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
                    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
                    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
                    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
                    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
                    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
                    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
                    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
                    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
                    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]]
    interim := 0
    every d := !n do interim := grid[interim+1][d+1]
    return 0 = interim
end

Sample run:

->damm 5724 5727 112946 112949
5724 is valid
5727 is not valid
112946 is valid
112949 is not valid
->

J

Solution:

OpTbl=: _99 ". ];._2 noun define
0 3 1 7 5 9 8 6 4 2
7 0 9 2 1 5 4 8 6 3
4 2 0 6 8 7 1 3 5 9
1 7 5 0 9 8 3 4 2 6
6 1 2 3 0 4 5 9 7 8
3 6 7 4 2 0 9 5 8 1
5 8 6 9 7 2 0 1 3 4
8 9 4 5 3 6 2 0 1 7
9 4 3 8 6 1 7 2 0 5
2 5 8 1 4 3 6 7 9 0
)

getdigits=: 10&#.inv

getDamm=: verb define
  row=. 0
  for_digit. getdigits y do.
    row=. OpTbl {~ <row,digit    
  end.   
)

checkDamm=: 0 = getDamm

Example Usage:

   checkDamm&> 5724 5727 112946
1 0 1

Or,

checkdamm=: {{0=((".;._2{{)n
0 7 4 1 6 3 5 8 9 2
3 0 2 7 1 6 8 9 4 5
1 9 0 5 2 7 6 4 3 8
7 2 6 0 3 4 9 5 8 1
5 1 8 9 0 2 7 3 6 4
9 5 7 8 4 0 2 6 1 3
8 4 1 3 5 9 0 2 7 6
6 8 3 4 9 5 1 0 2 7
4 6 5 2 7 8 3 1 0 9
2 3 9 6 8 1 4 7 5 0
}}){~<@,)/|.0,10#.inv y}}"0
   checkdamm 5724 5727 112946
1 0 1

We could probably replace that embedded table with something more concise if the description of the math behind the algorithm on the wikipedia page was more complete. (See talk page.)

Translation of: Kotlin
public class DammAlgorithm {
    private static final int[][] table = {
        {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
        {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
        {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
        {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
        {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
        {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
        {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
        {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
        {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
        {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
    };

    private static boolean damm(String s) {
        int interim = 0;
        for (char c : s.toCharArray()) interim = table[interim][c - '0'];
        return interim == 0;
    }

    public static void main(String[] args) {
        int[] numbers = {5724, 5727, 112946, 112949};
        for (Integer number : numbers) {
            boolean isValid = damm(number.toString());
            if (isValid) {
                System.out.printf("%6d is valid\n", number);
            } else {
                System.out.printf("%6d is invalid\n", number);
            }
        }
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
const table = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
 ];

const lookup = (p, c) => table[p][parseInt(c, 10)]
const damm = input => [...input].reduce(lookup, 0) === 0;

// ----------------------------------------------------------[ Tests ]----
const test = () => ["5724", "5727", "112946", "112949"].forEach(e =>
    console.log(`${e} => ${damm(e) ? 'Pass' : 'Fail'}`)
);
test();
Output:
5724 => Pass
5727 => Fail
112946 => Pass
112949 => Fail
def checkdigit:
       [[0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
        [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
        [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
        [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
        [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
        [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
        [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
        [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
        [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
        [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]]
      as $m
    | tostring | explode
      # "0" is 48
    | 0 == reduce (.[] - 48) as $d (0; $m[.][$d] );
	
# The task:
5724, 5727, 112946, 112949
| checkdigit as $d
| [., $d]
Output:
[5724,true]
[5727,false]
[112946,true]
[112949,false]
function checkdigit(n)
    matrix = (
        (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
        (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
        (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
        (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
        (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
        (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
        (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
        (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
        (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
        (2, 5, 8, 1, 4, 3, 6, 7, 9, 0))
    row = 0
    for d in string(n)
        row = matrix[row + 1][d - '0' + 1]
    end
    return row
end

foreach(i -> println("$i validates as: ", checkdigit(string(i)) == 0), [5724, 5727, 112946])
Output:
5724 validates as: true
5727 validates as: false
112946 validates as: true
// version 1.1.2

val table = arrayOf(
    intArrayOf(0, 3, 1,	7, 5, 9, 8, 6, 4, 2),
    intArrayOf(7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    intArrayOf(4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    intArrayOf(1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    intArrayOf(6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    intArrayOf(3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    intArrayOf(5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    intArrayOf(8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    intArrayOf(9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    intArrayOf(2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
) 

fun damm(s: String): Boolean {
    var interim = 0
    for (c in s) interim = table[interim][c - '0']
    return interim == 0
}

fun main(args: Array<String>) {
    val numbers = intArrayOf(5724, 5727, 112946, 112949)
    for (number in numbers) {
        val isValid = damm(number.toString())
        println("${"%6d".format(number)} is ${if (isValid) "valid" else "invalid"}")
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
local tab = {
    {0,3,1,7,5,9,8,6,4,2}, {7,0,9,2,1,5,4,8,6,3},
    {4,2,0,6,8,7,1,3,5,9}, {1,7,5,0,9,8,3,4,2,6},
    {6,1,2,3,0,4,5,9,7,8}, {3,6,7,4,2,0,9,5,8,1},
    {5,8,6,9,7,2,0,1,3,4}, {8,9,4,5,3,6,2,0,1,7},
    {9,4,3,8,6,1,7,2,0,5}, {2,5,8,1,4,3,6,7,9,0}
}
function check( n )
    local idx, a = 0, tonumber( n:sub( 1, 1 ) )
    for i = 1, #n do
        a = tonumber( n:sub( i, i ) )
        if a == nil then return false end
        idx = tab[idx + 1][a + 1]
    end
    return idx == 0
end
local n, r
while( true ) do
    io.write( "Enter the number to check: " )
    n = io.read(); if n == "0" then break end
    r = check( n ); io.write( n, " is " )
    if not r then io.write( "in" ) end
    io.write( "valid!\n" )
end
Output:
Enter the number to check: 5724
5724 is valid!
Enter the number to check: 5727
5727 is invalid!
Enter the number to check: 112946
112946 is valid!
Enter the number to check: 0
Module Damm_Algorithm{
	Function Prepare {
		function OperationTable {
			data    (0, 3, 1, 7, 5, 9, 8, 6, 4, 2)
			data    (7, 0, 9, 2, 1, 5, 4, 8, 6, 3)
			data    (4, 2, 0, 6, 8, 7, 1, 3, 5, 9)
			data    (1, 7, 5, 0, 9, 8, 3, 4, 2, 6)
			data    (6, 1, 2, 3, 0, 4, 5, 9, 7, 8)
			data    (3, 6, 7, 4, 2, 0, 9, 5, 8, 1)
			data    (5, 8, 6, 9, 7, 2, 0, 1, 3, 4)
			data    (8, 9, 4, 5, 3, 6, 2, 0, 1, 7)
			data    (9, 4, 3, 8, 6, 1, 7, 2, 0, 5)
			data    (2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
			=array([])
		}
		Digits= Lambda (d) ->{
			d$=str$(d,"")
			for i=1 to len(d$)
				data val(mid$(d$,i,1))
			next
			=Array([])
		}
		=Lambda a()=OperationTable(), Digits  (N) -> {
			dim b()
			b()=Digits(N)
			m=0
			for i=0 to len(b())-1
				m=a(m)(b(i))
			next i
			=m
		}
	}
	Damm=Prepare()
	Data 5724, 5727, 112946, 112940
	while not empty
		over  ' double the top of stack
		over
		Print number, Damm(number),  Damm(number)=0
	End While
}
Damm_Algorithm
Output:
  5724     0   True
  5727     9  False
112946     0   True
112940     5  False
        .TITLE  DAMMAL
        .MCALL  .GTLIN,.PRINT,.EXIT
DAMMAL::JMP     DEMO

        ; VALIDATE DAMM STRING IN R0; ZERO FLAG SET IF VALID
DAMM:   CLR     R2              ; INTERIM DIGIT
        BR      2$
1$:     SUB     #60,R1          ; DIGIT?
        BCS     3$              ; IF NOT, NOT VALID
        CMP     R1,#^D9
        BGT     3$
        MOV     R2,R3           ; CALCULATE DAMM TABLE INDEX
        ASL     R3
        ASL     R3
        ADD     R2,R3
        ASL     R3
        ADD     R1,R3
        MOVB    4$(R3),R2       ; GET NEW INTERIM DIGIT FROM TABLE
2$:     MOVB    (R0)+,R1        ; NEXT CHAR
        BNE     1$              ; END OF STRING?
        TST     R2              ; IF SO, CHECK IF INTERIM DIGIT IS 0
3$:     RTS     PC
4$:     .BYTE   ^D0,^D3,^D1,^D7,^D5,^D9,^D8,^D6,^D4,^D2
        .BYTE   ^D7,^D0,^D9,^D2,^D1,^D5,^D4,^D8,^D6,^D3
        .BYTE   ^D4,^D2,^D0,^D6,^D8,^D7,^D1,^D3,^D5,^D9
        .BYTE   ^D1,^D7,^D5,^D0,^D9,^D8,^D3,^D4,^D2,^D6
        .BYTE   ^D6,^D1,^D2,^D3,^D0,^D4,^D5,^D9,^D7,^D8
        .BYTE   ^D3,^D6,^D7,^D4,^D2,^D0,^D9,^D5,^D8,^D1
        .BYTE   ^D5,^D8,^D6,^D9,^D7,^D2,^D0,^D1,^D3,^D4
        .BYTE   ^D8,^D9,^D4,^D5,^D3,^D6,^D2,^D0,^D1,^D7
        .BYTE   ^D9,^D4,^D4,^D8,^D6,^D1,^D7,^D2,^D0,^D5
        .BYTE   ^D2,^D5,^D8,^D1,^D4,^D3,^D6,^D7,^D9,^D0

DEMO:   .GTLIN  #5$             ; READ LINE
        MOV     #5$,R0
        TSTB    (R0)            ; EMPTY LINE?
        BNE     1$
        .EXIT                   ; IF SO, STOP
1$:     JSR     PC,DAMM         ; TEST LINE
        BNE     2$              ; FAIL?
        .PRINT  #3$
        BR      DEMO
2$:     .PRINT  #4$             ; PASS?
        BR      DEMO
3$:     .ASCIZ  /PASS/
4$:     .ASCIZ  /FAIL/
5$:     .BLKB   200
        .END    DAMMAL
Output:
5724
PASS
5727
FAIL
112946
PASS
112949
FAIL
            NORMAL MODE IS INTEGER

          R VERIFY DAMM CHECKSUM OF NUMBER
            INTERNAL FUNCTION(CKNUM)
            VECTOR VALUES DAMMIT = 
          0        0,3,1,7,5,9,8,6,4,2
          1     ,  7,0,9,2,1,5,4,8,6,3
          2     ,  4,2,0,6,8,7,1,3,5,9
          3     ,  1,7,5,0,9,8,3,4,2,6
          4     ,  6,1,2,3,0,4,5,9,7,8
          5     ,  3,6,7,4,2,0,9,5,8,1
          6     ,  5,8,6,9,7,2,0,1,3,4
          7     ,  8,9,4,5,3,6,2,0,1,7
          8     ,  9,4,3,8,6,1,7,2,0,5
          9     ,  2,5,8,1,4,3,6,7,9,0           
            DIMENSION DAMDGT(10)
            ENTRY TO DAMM.
            TMP=CKNUM
            THROUGH GETDGT, FOR NDGT=0, 1, TMP.E.0
            DAMDGT(NDGT) = TMP-TMP/10*10
GETDGT      TMP = TMP/10
            INTRM = 0
            THROUGH CKDGT, FOR NDGT=NDGT, -1, NDGT.L.0
CKDGT       INTRM = DAMMIT(INTRM*10 + DAMDGT(NDGT))
            FUNCTION RETURN INTRM.E.0
            END OF FUNCTION
            
          R TEST SOME NUMBERS
            THROUGH TEST, FOR VALUES OF N = 5724,5727,112946,112949
            WHENEVER DAMM.(N)
                PRINT FORMAT VALID,N
            OTHERWISE
                PRINT FORMAT INVAL,N
TEST        END OF CONDITIONAL
            
            VECTOR VALUES VALID = $I9,S1,5HVALID*$
            VECTOR VALUES INVAL = $I9,S1,7HINVALID*$
            END OF PROGRAM
Output:
     5724 VALID
     5727 INVALID
   112946 VALID
   112949 INVALID
matrix = {{0, 3, 1, 7, 5, 9, 8, 6, 4, 2}, {7, 0, 9, 2, 1, 5, 4, 8, 6, 
    3}, {4, 2, 0, 6, 8, 7, 1, 3, 5, 9}, {1, 7, 5, 0, 9, 8, 3, 4, 2, 
    6}, {6, 1, 2, 3, 0, 4, 5, 9, 7, 8}, {3, 6, 7, 4, 2, 0, 9, 5, 8, 
    1}, {5, 8, 6, 9, 7, 2, 0, 1, 3, 4}, {8, 9, 4, 5, 3, 6, 2, 0, 1, 
    7}, {9, 4, 3, 8, 6, 1, 7, 2, 0, 5}, {2, 5, 8, 1, 4, 3, 6, 7, 9, 
    0}};
Damm[num_Integer] := Module[{row},
  row = 0;
  Do[
   row = matrix[[row + 1, d + 1]]
   ,
   {d, IntegerDigits[num]}
   ];
  row == 0
  ]
Damm /@ {5724, 5727, 112946}
Output:
{True, False, True}
Translation of: Julia
clear all;close all;clc;

% Test the function with the provided numbers
numbers = [5724, 5727, 112946];
for i = 1:length(numbers)
    if checkdigit(numbers(i))
        fprintf('%d validates as: true\n', numbers(i));
    else
        fprintf('%d validates as: false\n', numbers(i));
    end
end

function isValid = checkdigit(n)
    matrix = [
        0, 3, 1, 7, 5, 9, 8, 6, 4, 2;
        7, 0, 9, 2, 1, 5, 4, 8, 6, 3;
        4, 2, 0, 6, 8, 7, 1, 3, 5, 9;
        1, 7, 5, 0, 9, 8, 3, 4, 2, 6;
        6, 1, 2, 3, 0, 4, 5, 9, 7, 8;
        3, 6, 7, 4, 2, 0, 9, 5, 8, 1;
        5, 8, 6, 9, 7, 2, 0, 1, 3, 4;
        8, 9, 4, 5, 3, 6, 2, 0, 1, 7;
        9, 4, 3, 8, 6, 1, 7, 2, 0, 5;
        2, 5, 8, 1, 4, 3, 6, 7, 9, 0
    ];

    row = 0;
    nString = num2str(n);
    for i = 1:length(nString)
        d = str2double(nString(i));
        row = matrix(row+1, d + 1);
    end
    isValid = (row == 0);
end
Output:
5724 validates as: true
5727 validates as: false
112946 validates as: true
This example does not show the output mentioned in the task description on this page (or a page linked to from here). Please ensure that it meets all task requirements and remove this message.
Note that phrases in task descriptions such as "print and display" and "print and show" for example, indicate that (reasonable length) output be a part of a language's solution.


MODULE DammAlgorithm;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

TYPE TA = ARRAY[0..9],[0..9] OF INTEGER;
CONST table = TA{
        {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
        {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
        {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
        {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
        {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
        {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
        {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
        {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
        {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
        {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}
    };

PROCEDURE Damm(s : ARRAY OF CHAR) : BOOLEAN;
VAR interim,i : INTEGER;
BEGIN
    interim := 0;

    i := 0;
    WHILE s[i] # 0C DO
        interim := table[interim,INT(s[i])-INT('0')];
        INC(i);
    END;
    RETURN interim=0;
END Damm;

PROCEDURE Print(number : INTEGER);
VAR
    isValid : BOOLEAN;
    buf : ARRAY[0..16] OF CHAR;
BEGIN
    FormatString("%i", buf, number);
    isValid := Damm(buf);
    WriteString(buf);
    IF isValid THEN
        WriteString(" is valid");
    ELSE
        WriteString(" is invalid");
    END;
    WriteLn;
END Print;

BEGIN
    Print(5724);
    Print(5727);
    Print(112946);
    Print(112949);

    ReadChar;
END DammAlgorithm.
MODULE DammAlgorithm EXPORTS Main;

IMPORT IO, Text;

VAR
  Numbers:ARRAY[0..3] OF TEXT := ARRAY OF TEXT{"5724", "5727", "112946", "112949"};
  
PROCEDURE Damm(READONLY Str:TEXT):BOOLEAN =
  TYPE
    TTable = ARRAY[0..9],[0..9] OF INTEGER;
  VAR
    Table := TTable
    {ARRAY OF INTEGER{0,3,1,7,5,9,8,6,4,2},
     ARRAY OF INTEGER{7,0,9,2,1,5,4,8,6,3},
     ARRAY OF INTEGER{4,2,0,6,8,7,1,3,5,9},
     ARRAY OF INTEGER{1,7,5,0,9,8,3,4,2,6},
     ARRAY OF INTEGER{6,1,2,3,0,4,5,9,7,8},
     ARRAY OF INTEGER{3,6,7,4,2,0,9,5,8,1},
     ARRAY OF INTEGER{5,8,6,9,7,2,0,1,3,4},
     ARRAY OF INTEGER{8,9,4,5,3,6,2,0,1,7},
     ARRAY OF INTEGER{9,4,3,8,6,1,7,2,0,5},
     ARRAY OF INTEGER{2,5,8,1,4,3,6,7,9,0}};
    Interim,I:INTEGER := 0;
  BEGIN
    WHILE I <= Text.Length(Str)-1 DO
      Interim := Table[Interim, ORD(Text.GetChar(Str, I)) - ORD('0')];
      INC(I);
    END;
    RETURN Interim = 0;
  END Damm;

BEGIN
  FOR I := FIRST(Numbers) TO LAST(Numbers) DO
    IF Damm(Numbers[I]) THEN
      IO.Put(Numbers[I] & " is valid\n");
    ELSE
      IO.Put(Numbers[I] & " is invalid\n");
    END;
  END;
END DammAlgorithm.
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
from algorithm import reverse

const Table = [[0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
               [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
               [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
               [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
               [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
               [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
               [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
               [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
               [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
               [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]]

type Digit = range[0..9]

func isValid(digits: openArray[Digit]): bool =
  ## Apply Damm algorithm to check validity of a digit sequence.
  var interim = 0
  for d in digits:
    interim = Table[interim][d]
  result = interim == 0

proc toDigits(n: int): seq[Digit] =
  ## Return the digits of a number.
  var n = n
  while true:
    result.add(n mod 10)
    n = n div 10
    if n == 0:
      break
  result.reverse()

proc checkData(digits: openArray[Digit]) =
  ## Check if a digit sequence if valid.
  if isValid(digits):
    echo "Sequence ", digits, " is valid."
  else:
    echo "Sequence ", digits, " is invalid."

checkData(5724.toDigits)
checkData(5727.toDigits)
checkData([Digit 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 1])
checkData([Digit 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 8])
Output:
Sequence [5, 7, 2, 4] is valid.
Sequence [5, 7, 2, 7] is invalid.
Sequence [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 1] is valid.
Sequence [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 8] is invalid.
Translation of: C#
class DammAlgorithm  {
  @table : static : Int[,];

  function : Main(args : String[]) ~ Nil {
    @table := [
      [0, 3, 1, 7, 5, 9, 8, 6, 4, 2]
      [7, 0, 9, 2, 1, 5, 4, 8, 6, 3]
      [4, 2, 0, 6, 8, 7, 1, 3, 5, 9]
      [1, 7, 5, 0, 9, 8, 3, 4, 2, 6]
      [6, 1, 2, 3, 0, 4, 5, 9, 7, 8]
      [3, 6, 7, 4, 2, 0, 9, 5, 8, 1]
      [5, 8, 6, 9, 7, 2, 0, 1, 3, 4]
      [8, 9, 4, 5, 3, 6, 2, 0, 1, 7]
      [9, 4, 3, 8, 6, 1, 7, 2, 0, 5]
      [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]];

    numbers := [ 5724, 5727, 112946, 112949 ];
    each (i : numbers) {
      number := numbers[i];
      isValid := Damm(number->ToString());
      if (isValid) {
        "{$number} is valid"->PrintLine();
      }
      else {
        "{$number} is invalid"->PrintLine();
      };
    };
  }

  function : Damm(s : String) ~ Bool {
    interim := 0;
    each (i : s) {
      interim := @table[interim, s->Get(i) - '0'];
    };
    return interim = 0;
  }
}
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
Works with: Free Pascal
Translation of: Modula-2

nearly copy&paste

program DammAlgorithm;
uses
  sysutils;

TYPE TA = ARRAY[0..9,0..9] OF UInt8;
CONST table : TA =
                ((0,3,1,7,5,9,8,6,4,2),
                 (7,0,9,2,1,5,4,8,6,3),
                 (4,2,0,6,8,7,1,3,5,9),
                 (1,7,5,0,9,8,3,4,2,6),
                 (6,1,2,3,0,4,5,9,7,8),
                 (3,6,7,4,2,0,9,5,8,1),
                 (5,8,6,9,7,2,0,1,3,4),
                 (8,9,4,5,3,6,2,0,1,7),
                 (9,4,3,8,6,1,7,2,0,5),
                 (2,5,8,1,4,3,6,7,9,0));

function Damm(s : string) : BOOLEAN;
VAR
  interim,i : UInt8;
BEGIN
  interim := 0;
  i := 1;
  WHILE i <= length(s) DO
  Begin
    interim := table[interim,ORD(s[i])-ORD('0')];
    INC(i);
  END;
  Damm := interim=0;
END;

PROCEDURE Print(number : Uint32);
VAR
    isValid : BOOLEAN;
    buf :string;
BEGIN
    buf := IntToStr(number);
    isValid := Damm(buf);
    Write(buf);
    IF isValid THEN
      Write(' is valid')
    ELSE
      Write(' is invalid');
    WriteLn;
END;

BEGIN
    Print(5724);
    Print(5727);
    Print(112946);
    Print(112949);
    Readln;
END.
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
var table := Matr(
  |0, 3, 1, 7, 5, 9, 8, 6, 4, 2|,
  |7, 0, 9, 2, 1, 5, 4, 8, 6, 3|,
  |4, 2, 0, 6, 8, 7, 1, 3, 5, 9|,
  |1, 7, 5, 0, 9, 8, 3, 4, 2, 6|,
  |6, 1, 2, 3, 0, 4, 5, 9, 7, 8|,
  |3, 6, 7, 4, 2, 0, 9, 5, 8, 1|,
  |5, 8, 6, 9, 7, 2, 0, 1, 3, 4|,
  |8, 9, 4, 5, 3, 6, 2, 0, 1, 7|,
  |9, 4, 3, 8, 6, 1, 7, 2, 0, 5|,
  |2, 5, 8, 1, 4, 3, 6, 7, 9, 0|
);

function Damn(s: string): boolean;
begin
  var interim := 0;
  foreach var c in s do
    interim := table[interim, c.ToDigit];
  Result := interim = 0;
end;

begin
  var numbers := Arr(5724, 5727, 112946, 112949);
  foreach var num in numbers do
    if Damn(num.ToString) then
      Println(num, 'is valid')
    else Println(num, 'is invalid')
end.
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
sub damm {
    my(@digits) = split '', @_[0];
    my @tbl =([< 0 3 1 7 5 9 8 6 4 2 >],
              [< 7 0 9 2 1 5 4 8 6 3 >],
              [< 4 2 0 6 8 7 1 3 5 9 >],
              [< 1 7 5 0 9 8 3 4 2 6 >],
              [< 6 1 2 3 0 4 5 9 7 8 >],
              [< 3 6 7 4 2 0 9 5 8 1 >],
              [< 5 8 6 9 7 2 0 1 3 4 >],
              [< 8 9 4 5 3 6 2 0 1 7 >],
              [< 9 4 3 8 6 1 7 2 0 5 >],
              [< 2 5 8 1 4 3 6 7 9 0 >]
              );
    my $row = 0;
    for my $col (@digits) { $row = $tbl[$row][$col] }
    not $row
}

for (5724, 5727, 112946) {
    print "$_:\tChecksum digit @{[damm($_) ? '' : 'in']}correct.\n"
}
Output:
5724:	Checksum digit correct.
5727:	Checksum digit incorrect.
112946:	Checksum digit correct.

As phix uses 1-based indexes, 1 must be added to the operation table, and validity is given by ending on one, rather than zero.

constant tbl = sq_add(1,{{0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
                         {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
                         {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
                         {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
                         {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
                         {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
                         {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
                         {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
                         {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
                         {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}})
 
function damm(string s)
    integer interim = 1
    for i=1 to length(s) do
        integer nxt = s[i]-'0'+1
        if nxt<1 or nxt>10 then return 0 end if
        interim = tbl[interim][nxt]
    end for
    return interim == 1
end function
 
constant tests = {"5724", "5727", "112946", "112949"}
for i=1 to length(tests) do
    string ti = tests[i]
    printf(1,"%7s is %svalid\n",{ti,iff(damm(ti)?"":"in")})
end for
Output:
   5724 is valid
   5727 is invalid
 112946 is valid
 112949 is invalid
<?php
function lookup($r,$c) {
    $table = array(
        array(0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
        array(7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
        array(4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
        array(1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
        array(6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
        array(3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
        array(5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
        array(8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
        array(9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
        array(2, 5, 8, 1, 4, 3, 6, 7, 9, 0),
    );
    return $table[$r][$c];
}

function isDammValid($input) {
    return array_reduce(str_split($input), "lookup", 0) == 0;
}

foreach(array("5724", "5727", "112946", "112949") as $i) {
    echo "{$i} is ".(isDammValid($i) ? "valid" : "invalid")."<br>";
}
?>
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
(setq *D                                                                                                                                
   (quote                                                                                                                               
      (0 3 1 7 5 9 8 6 4 2)                                                                                                             
      (7 0 9 2 1 5 4 8 6 3)                                                                                                             
      (4 2 0 6 8 7 1 3 5 9)                                                                                                             
      (1 7 5 0 9 8 3 4 2 6)                                                                                                             
      (6 1 2 3 0 4 5 9 7 8)                                                                                                             
      (3 6 7 4 2 0 9 5 8 1)                                                                                                             
      (5 8 6 9 7 2 0 1 3 4)                                                                                                             
      (8 9 4 5 3 6 2 0 1 7)                                                                                                             
      (9 4 3 8 6 1 7 2 0 5)                                                                                                             
      (2 5 8 1 4 3 6 7 9 0) ) )                                                                                                         
(de damm? (N)                                                                                                                           
   (let R 1                                                                                                                             
      (for N (mapcar format (chop N))                                                                                                   
         (setq R (inc (get *D R (inc N)))) )                                                                                            
      (= 1 R) ) )                                                                                                                       
(println (damm? 5724))                                                                                                                  
(println (damm? 5727))                                                                                                                  
(println (damm? 112946))                                                                                                                
(println (damm? 112940))
Output:
T
NIL
T
NIL
100H:

/* DAMM CHECKSUM FOR DECIMAL NUMBER IN GIVEN STRING */
CHECK$DAMM: PROCEDURE (PTR) BYTE;
    DECLARE PTR ADDRESS, CH BASED PTR BYTE;
    DECLARE DAMM DATA
        ( 0,3,1,7,5,9,8,6,4,2,
          7,0,9,2,1,5,4,8,6,3,
          4,2,0,6,8,7,1,3,5,9,
          1,7,5,0,9,8,3,4,2,6,
          6,1,2,3,0,4,5,9,7,8,
          3,6,7,4,2,0,9,5,8,1,
          5,8,6,9,7,2,0,1,3,4,
          8,9,4,5,3,6,2,0,1,7,
          9,4,3,8,6,1,7,2,0,5,
          2,5,8,1,4,3,6,7,9,0 );
    DECLARE I BYTE;
    I = 0;
    DO WHILE CH <> '$';
        I = DAMM((I*10) + (CH-'0'));
        PTR = PTR + 1;
    END;
    RETURN I = 0;
END CHECK$DAMM;

/* CP/M BDOS CALLS */
BDOS: PROCEDURE (FN, ARG);
    DECLARE FN BYTE, ARG ADDRESS;
    GO TO 5;
END BDOS;

PRINT: PROCEDURE (STR);
    DECLARE STR ADDRESS;
    CALL BDOS(9, STR);
END PRINT;

/* TESTS */
DECLARE TEST (4) ADDRESS;
TEST(0) = .'5724$';
TEST(1) = .'5727$';
TEST(2) = .'112946$';
TEST(3) = .'112949$';

DECLARE N BYTE;
DO N = 0 TO LAST(TEST);
    CALL PRINT(TEST(N));
    CALL PRINT(.': $');
    IF CHECK$DAMM(TEST(N)) THEN
        CALL PRINT(.'PASS$');
    ELSE
        CALL PRINT(.'FAIL$');
    CALL PRINT(.(13,10,'$'));
END;

CALL BDOS(0,0);
EOF
Output:
5724: PASS
5727: FAIL
112946: PASS
112949: FAIL
Translation of: ALGOL 68
do  -- Damm Algorithm

    -- returns true  if the check digit of s is correct according to the Damm algorithm,
    --         false otherwise #
    local function hasValidDammCheckDigit( s : string ) : boolean

        local operationTable <const> = { { 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 } -- as per wikipedia example
                                       , { 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 }
                                       , { 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 }
                                       , { 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 }
                                       , { 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 }
                                       , { 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 }
                                       , { 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 }
                                       , { 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 }
                                       , { 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 }
                                       , { 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 }
                                       }
        local interimDigit = 0
        for sPos = 1, # s do
            local nextDigit <const> = string.byte( s[ sPos ] ) - string.byte( "0" )
            if 0 <= nextDigit <= 9 then
                interimDigit = operationTable[ interimDigit + 1 ][ nextDigit + 1 ]
            else
                error( $"Invalid Damm digit: [{s[ sPos ]}]" )
            end
        end
        return interimDigit == 0
    end
 
    local function testDammAlgorithm( s : string, expectedResult : boolean ) : void
        local isValid <const> = hasValidDammCheckDigit( s )
        print(  $"check digit of {s} is "
             .. if isValid then "valid" else "invalid" end
             .. if isValid == expectedResult then "" else " *** NOT AS EXPECTED" end
             )
    end

    -- test cases
    testDammAlgorithm( "5724",   true  )
    testDammAlgorithm( "5727",   false )
    testDammAlgorithm( "112946", true  )
end
Output:

Same as Algol 68.

Translation of: C#
$table = (
    (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
    (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    (2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
)

function Test-Damm([string]$s) {
    $interim = 0
    foreach ($c in $s.ToCharArray()) {
        $interim = $table[$interim][[int]$c - [int][char]'0']
    }
    return $interim -eq 0
}

foreach ($number in 5724, 5727, 112946, 112949) {
    $validity = if (Test-Damm $number) {'valid'} else {'invalid'}
    '{0,6} is {1}' -f $number, $validity
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid
112949 is invalid
%!  damm_algorithm(+Number) is semidet.
%   Succeeds if the number is valid according to the Damm algorithm.
damm_algorithm(Number) :-
    Matrix = [
        [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
        [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
        [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
        [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
        [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
        [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
        [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
        [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
        [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
        [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]
    ],
    number_codes(Number, Codes),
    foldl(damm_algorithm(Matrix), Codes, 0, 0).

damm_algorithm(Matrix, Code, N0, N) :-
    Digit is Code - 48,
    nth0(N0, Matrix, Row),
    nth0(Digit, Row, N).

:- foreach(member(Number, [5724, 5727, 112946, 112949]), (
    ( damm_algorithm(Number) -> write(Number is valid) ; write(Number is invalid) ),
    nl
)).
Output:
5724 is valid
5727 is invalid
112946 is valid
112949 is invalid
def damm(num: int) -> bool:
    row = 0
    for digit in str(num):
        row = _matrix[row][int(digit)] 
    return row == 0

_matrix = (
    (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
    (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    (2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
)

if __name__ == '__main__':
    for test in [5724, 5727, 112946]:
        print(f'{test}\t Validates as: {damm(test)}')
Output:
5724     Validates as: True
5727     Validates as: False
112946   Validates as: True
  [ 0 swap witheach
      [ char 0 - dip
          [ table
            [ 0 3 1 7 5 9 8 6 4 2 ]
            [ 7 0 9 2 1 5 4 8 6 3 ]
            [ 4 2 0 6 8 7 1 3 5 9 ]
            [ 1 7 5 0 9 8 3 4 2 6 ]
            [ 6 1 2 3 0 4 5 9 7 8 ]
            [ 3 6 7 4 2 0 9 5 8 1 ]
            [ 5 8 6 9 7 2 0 1 3 4 ]
            [ 8 9 4 5 3 6 2 0 1 7 ]
            [ 9 4 3 8 6 1 7 2 0 5 ]
            [ 2 5 8 1 4 3 6 7 9 0 ] ]
        peek ] ]                      is damm      ( $ --> n )

  [ damm 0 = ]                        is dammvalid ( $ --> b )

  [ dup echo$ say " is "
    dammvalid not if [ say "not " ]
    say "valid." cr ]                 is validate  ( & -->   )

  $ "5724 5725 112946 112949"
  nest$ witheach validate
Output:
5724 is valid.
5725 is not valid.
112946 is valid.
112949 is not valid.

R

Damm_algo <- function(number){
  row_i = 0
  
  iterable = strsplit(toString(number), "")[[1]]
  
  validation_matrix = 
    matrix(
      c(
        0, 3, 1, 7, 5, 9, 8, 6, 4, 2,
        7, 0, 9, 2, 1, 5, 4, 8, 6, 3,
        4, 2, 0, 6, 8, 7, 1, 3, 5, 9,
        1, 7, 5, 0, 9, 8, 3, 4, 2, 6,
        6, 1, 2, 3, 0, 4, 5, 9, 7, 8,
        3, 6, 7, 4, 2, 0, 9, 5, 8, 1,
        5, 8, 6, 9, 7, 2, 0, 1, 3, 4,
        8, 9, 4, 5, 3, 6, 2, 0, 1, 7,
        9, 4, 3, 8, 6, 1, 7, 2, 0, 5,
        2, 5, 8, 1, 4, 3, 6, 7, 9, 0),
      nrow = 10, ncol = 10, byrow = T
    )
  
  for(digit in as.integer(iterable)){
    row_i = validation_matrix[row_i + 1, digit + 1]    #in R indexes start from 1 and not from zero
  }
  
  test <- ifelse(row_i == 0, "VALID", "NOT VALID")
  message(paste("Number", number, "is", test))
}

for(number in c(5724, 5727, 112946, 112949)){
Damm_algo(number)
  }
Output:
Number 5724 is VALID
Number 5727 is NOT VALID
Number 112946 is VALID
Number 112949 is NOT VALID
#lang racket/base
(require racket/match)

(define operation-table
  #(#(0 3 1 7 5 9 8 6 4 2)
    #(7 0 9 2 1 5 4 8 6 3)
    #(4 2 0 6 8 7 1 3 5 9)
    #(1 7 5 0 9 8 3 4 2 6)
    #(6 1 2 3 0 4 5 9 7 8)
    #(3 6 7 4 2 0 9 5 8 1)
    #(5 8 6 9 7 2 0 1 3 4)
    #(8 9 4 5 3 6 2 0 1 7)
    #(9 4 3 8 6 1 7 2 0 5)
    #(2 5 8 1 4 3 6 7 9 0)))

(define (integer->digit-list n)
  (let loop ((n n) (a null))
    (if (zero? n) a (let-values (([q r] (quotient/remainder n 10))) (loop q (cons r a))))))

(define/match (check-digit n)
  [((list ds ...))
   (foldl
    (λ (d interim)
      (vector-ref (vector-ref operation-table interim) d))
    0 ds)]
  [((? integer? i))
   (check-digit (integer->digit-list i))])

(define/match (valid-number? n)
  [((? integer? i))
   (valid-number? (integer->digit-list i))]
  [((list ds ...))
   (zero? (check-digit ds))])

(module+ test
  (require rackunit)
  (check-equal? (integer->digit-list 572) '(5 7 2))
  (check-equal? (check-digit 572) 4)
  (check-equal? (check-digit '(5 7 2)) 4)
  (check-true (valid-number? 5724))
  (check-false (valid-number? 5274))
  (check-true (valid-number? 112946)))

No output from checks means that all tests passed.


(formerly Perl 6)

Works with: Rakudo version 2017.05
sub damm ( *@digits ) {
    my @tbl = [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
              [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
              [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
              [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
              [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
              [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
              [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
              [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
              [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
              [2, 5, 8, 1, 4, 3, 6, 7, 9, 0];
    my $row = 0;
    for @digits -> $col { $row = @tbl[$row][$col] }
    not $row
}

# Testing
for 5724, 5727, 112946 {
    say "$_:\tChecksum digit { damm( $_.comb ) ?? '' !! 'in' }correct."
}
Output:
5724:	Checksum digit correct.
5727:	Checksum digit incorrect.
112946:	Checksum digit correct.
$ENTRY Go {
    = <Test '5724'>
      <Test '5727'>
      <Test '112946'>
      <Test '112949'>;
};

Test {
    e.Ds = <Prout e.Ds ': ' <Damm e.Ds>>;
};

Damm {
    ('0') = Pass;
    (s.Int) = Fail;
    (s.Int) s.D e.Ds,
        <Item <Numb s.Int> <DammTable>>: (e.Row),
        <Item <Numb s.D> e.Row>: s.Next
        = <Damm (s.Next) e.Ds>;
    e.Ds = <Damm ('0') e.Ds>;
};

DammTable {
    = ('0317598642')
      ('7092154863')
      ('4206871359')
      ('1750983426')
      ('6123045978')
      ('3674209581')
      ('5869720134')
      ('8945362017')
      ('9438617205')
      ('2581436790')
};

Item {
    0   t.I e.X = t.I;
    s.N t.I e.X = <Item <- s.N 1> e.X>;
};
Output:
5724: Pass
5727: Fail
112946: Pass
112949: Fail

manufactured table

/* REXX */
Call init
Call test 5724
Call test 5727
Call test 112946
Call test 112940
Exit

test:
Parse Arg number
int_digit=0
Do p=1 To length(number)
  d=substr(number,p,1)
  int_digit=grid.int_digit.d
  If p<length(number) Then cd=int_digit
  End
If int_digit=0 Then
  Say number 'is ok'
Else
  Say number 'is not ok, check-digit should be' cd '(instead of' d')'
Return

init:
i=-2
Call setup '* 0 1 2 3 4 5 6 7 8 9'
Call setup '0 0 3 1 7 5 9 8 6 4 2'
Call setup '1 7 0 9 2 1 5 4 8 6 3'
Call setup '2 4 2 0 6 8 7 1 3 5 9'
Call setup '3 1 7 5 0 9 8 3 4 2 6'
Call setup '4 6 1 2 3 0 4 5 9 7 8'
Call setup '5 3 6 7 4 2 0 9 5 8 1'
Call setup '6 5 8 6 9 7 2 0 1 3 4'
Call setup '7 8 9 4 5 3 6 2 0 1 7'
Call setup '8 9 4 3 8 6 1 7 2 0 5'
Call setup '9 2 5 8 1 4 3 6 7 9 0'
Return
setup:
  Parse Arg list
  i=i+1
  Do col=-1 To 9
    grid.i.col=word(list,col+2)
    End
  Return
Output:
5724 is ok
5727 is not ok, check-digit should be 4 (instead of 7)
112946 is ok
112940 is not ok, check-digit should be 6 (instead of 0)

static table

Using a static table is over four times faster than manufacturing it.

/*REXX pgm uses H. Michael Damm's algorithm to validate numbers with suffixed check sum. digit*/
 a.0= 0317598642; a.1= 7092154863; a.2= 4206871359; a.3= 1750983426; a.4= 6123045978
 a.5= 3674209581; a.6= 5869720134; a.7= 8945362017; a.8= 9438617205; a.9= 2581436790
Call Damm 5724, 5727, 112946, 112940         /*invoke Damm's algorithm To some #'s.*/
Exit                                         /*stick a Tok in it,  we're all Done. */
/*---------------------------------------------------------------------------------*/
Damm:
  Do j=1 To arg()                            /* loop over numbers          */
    x=arg(j)
    d=0
    Do p=1 To length(x)-1                  /* compute the checksum digit */
      d=substr(a.d,substr(x,p,1)+1,1)
      end   /*p*/
    z=right(x,1)                             /* the given digit            */
    If z=d Then Say '   valid checksum digit '  z  " for "  x
    Else Say ' invalid checksum digit '  z  " for "  x    '   (should be'  d")"
    End   /*j*/
  Return
output   when using the (internal) default inputs:
  
   valid checksum digit  4  for  5724
 invalid checksum digit  7  for  5727    (should be 4)
   valid checksum digit  6  for  112946
 invalid checksum digit  0  for  112940    (should be 6)
# Project : Damm algorithm

matrix = [[0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
               [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
               [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
               [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
               [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
               [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
               [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
               [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
               [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
               [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]]

see "5724" + encode(5724 ) + nl
see "5727" + encode(5727 ) + nl
see "112946" + encode(112946) + nl

func encode(n)
       check = 0
       for d in string(n)
           check = matrix[check+1][d-'0'+1]
       next
       if check = 0
          return " is valid"
       else
          return " is invalid"
       ok

Output:

5724 is valid
5727 is invalid
112946 is valid
Translation of: Python

Array version

≪ →STR
   [[ 0 3 1 7 5 9 8 6 4 2 ]
    [ 7 0 9 2 1 5 4 8 6 3 ]
    [ 4 2 0 6 8 7 1 3 5 9 ]
    [ 1 7 5 0 9 8 3 4 2 6 ]
    [ 6 1 2 3 0 4 5 9 7 8 ]
    [ 3 6 7 4 2 0 9 5 8 1 ]
    [ 5 8 6 9 7 2 0 1 3 4 ]
    [ 8 9 4 5 3 6 2 0 1 7 ]
    [ 9 4 3 8 6 1 7 2 0 5 ]
    [ 2 5 8 1 4 3 6 7 9 0 ]]
    → num table
   ≪ 0 
      1 num SIZE FOR d
         1 + num d DUP SUB STR→ 1 + 
         2 →LIST table SWAP GET 
      NEXT
      NOT
≫ ≫ 'DAMM?' STO

String version

Program flow is quite the same, but storing the table needs only 210 nibbles of RAM, instead of 1625 with a 2-dimensional array.

≪ →STR "0317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790"
   → num table
   ≪ 0 
     1 num SIZE FOR d
        10 * num d DUP SUB STR→ 1 + + 
        table SWAP DUP SUB STR→ 
     NEXT
     NOT
≫ ≫ 'DAMM?' STO
≪ { 5724 5727 112946 } { }
   1 3 PICK SIZE FOR j 
      OVER j GET 'DAMM?' STO "True" "False" IFTE NEXT
≫ EVAL
Output:
2: { 5724 5727 112946 }
1: { "True" "False" True" }
TABLE = [
    [0,3,1,7,5,9,8,6,4,2], [7,0,9,2,1,5,4,8,6,3],
    [4,2,0,6,8,7,1,3,5,9], [1,7,5,0,9,8,3,4,2,6],
    [6,1,2,3,0,4,5,9,7,8], [3,6,7,4,2,0,9,5,8,1],
    [5,8,6,9,7,2,0,1,3,4], [8,9,4,5,3,6,2,0,1,7],
    [9,4,3,8,6,1,7,2,0,5], [2,5,8,1,4,3,6,7,9,0]
]

def damm_valid?(n) = n.digits.reverse.inject(0){|idx, a| TABLE[idx][a] } == 0

[5724, 5727, 112946].each{|n| puts "#{n}: #{damm_valid?(n) ? "" : "in"}valid"}
Output:
5724: valid

5727: invalid 112946: valid

fn damm(number: &str) -> u8 {
    static TABLE: [[u8; 10]; 10] = [
        [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
        [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
        [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
        [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
        [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
        [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
        [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
        [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
        [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
        [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
    ];

    number.chars().fold(0, |row, digit| {
        let digit = digit.to_digit(10).unwrap();
        TABLE[row as usize][digit as usize]
    })
}

fn damm_validate(number: &str) -> bool {
    damm(number) == 0
}

fn main() {
    let numbers = &["5724", "5727", "112946"];
    for number in numbers {
        let is_valid = damm_validate(number);
        if is_valid {
            println!("{:>6} is valid", number);
        } else {
            println!("{:>6} is invalid", number);
        }
    }
}
Output:
  5724 is valid
  5727 is invalid
112946 is valid

Functional, (tail) recursive, concise and clean

import scala.annotation.tailrec

object DammAlgorithm extends App {

  private val numbers = Seq(5724, 5727, 112946, 112949)

  @tailrec
  private def damm(s: String, interim: Int): String = {
    def table =
      Vector(
        Vector(0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
        Vector(7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
        Vector(4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
        Vector(1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
        Vector(6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
        Vector(3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
        Vector(5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
        Vector(8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
        Vector(9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
        Vector(2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
      )

    if (s.isEmpty) if (interim == 0) "✔" else "✘"
    else damm(s.tail, table(interim)(s.head - '0'))
  }

  for (number <- numbers) println(f"$number%6d is ${damm(number.toString, 0)}.")

}
Output:

See it running in your browser by ScalaFiddle (JavaScript, non JVM) or by Scastie (remote JVM).

program damm_algorithm;
    tests := [5724, 5727, 112946, 112949];

    loop for test in tests do
        print(str test + ': ' + if damm test then 'Pass' else 'Fail' end);
    end loop;

    op damm(n);
        dt := [[0,3,1,7,5,9,8,6,4,2],
               [7,0,9,2,1,5,4,8,6,3],
               [4,2,0,6,8,7,1,3,5,9],
               [1,7,5,0,9,8,3,4,2,6],
               [6,1,2,3,0,4,5,9,7,8],
               [3,6,7,3,2,0,9,5,8,1],
               [5,8,6,9,7,2,0,1,3,4],
               [8,9,4,5,3,6,2,0,1,7],
               [9,4,3,8,6,1,7,2,0,5],
               [2,5,8,1,4,3,6,7,9,0]];

        i := 0;
        loop for d in str n do
            i := dt(i+1)(val d+1);
        end loop;
        return i=0;
    end op;
end program;
Output:
5724: Pass
5727: Fail
112946: Pass
112949: Fail
func damm(digits) {
    static tbl = [
          [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
          [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
          [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
          [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
          [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
          [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
          [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
          [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
          [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
          [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
    ]

    !digits.flip.reduce({|row,col| tbl[row][col] }, 0)
}

for n in [5724, 5727, 112946] {
    say "#{n}:\tChecksum digit #{ damm(n.digits) ? '' : 'in'}correct."
}
Output:
5724:	Checksum digit correct.
5727:	Checksum digit incorrect.
112946:	Checksum digit correct.
Translation of: Perl
proc damm {number} {
    set digits [split $number ""]
    set tbl {
        {0 3 1 7 5 9 8 6 4 2}
        {7 0 9 2 1 5 4 8 6 3}
        {4 2 0 6 8 7 1 3 5 9}
        {1 7 5 0 9 8 3 4 2 6}
        {6 1 2 3 0 4 5 9 7 8}
        {3 6 7 4 2 0 9 5 8 1}
        {5 8 6 9 7 2 0 1 3 4}
        {8 9 4 5 3 6 2 0 1 7}
        {9 4 3 8 6 1 7 2 0 5}
        {2 5 8 1 4 3 6 7 9 0}
    }

    set row 0
    foreach col $digits {
        set row [lindex $tbl $row $col]
    }
    return [expr {$row == 0 ? 1 : 0}]
}

foreach number {5724 5727 112946} {
    set correct [damm $number]
    puts "$number:\tChecksum digit [expr {$correct ? "" : "in"}]correct."
}
Output:
5724:	Checksum digit correct.
5727:	Checksum digit incorrect.
112946:	Checksum digit correct.
Works with: Uiua version 0.15.0-dev.2
Table ← [
  [0 3 1 7 5 9 8 6 4 2]
  [7 0 9 2 1 5 4 8 6 3]
  [4 2 0 6 8 7 1 3 5 9]
  [1 7 5 0 9 8 3 4 2 6]
  [6 1 2 3 0 4 5 9 7 8]
  [3 6 7 4 2 0 9 5 8 1]
  [5 8 6 9 7 2 0 1 3 4]
  [8 9 4 5 3 6 2 0 1 7]
  [9 4 3 8 6 1 7 2 0 5]
  [2 5 8 1 4 3 6 7 9 0]
]

Damm ← =0⬚0/(˜⊡Table⊟)-@0°⋕

┌─╴test
  ⍤⤙≍ 1 Damm 5724
  ⍤⤙≍ 0 Damm 5727
  ⍤⤙≍ 1 Damm 112946
  ⍤⤙≍ 0 Damm 112949
└─╴
Output:
All 4 tests passed
#!/bin/sh

damm() {
    out=0
    t="0317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790"

	for i in $(printf "$1" | fold -b1); do
		out=$(expr substr "$t" $((out*10+i+1)) 1)
    done

    printf "$out"
}

validate() {
	[ "$1" = "${1%?}$(damm ${1%?})" ] && res="Pass" || res="Fail"
	printf "%s: %s\n" "$1" "$res"
}

validate 5724
validate 5727
validate 112946
validate 112949
Output:
5724: Pass
5727: Fail
112946: Pass
112949: Fail
Translation of: Go
const table = [
    [u8(0), 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [u8(7), 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [u8(4), 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [u8(1), 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [u8(6), 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [u8(3), 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [u8(5), 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [u8(8), 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [u8(9), 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [u8(2), 5, 8, 1, 4, 3, 6, 7, 9, 0],
]
 
fn damm(input string) bool {
    mut interim := u8(0)
    for c in input.bytes() {
        interim = table[interim][c-'0'[0]]
    }
    return interim == 0
}
 
fn main() {
    for s in ["5724", "5727", "112946", "112949"] {
        println("${s:6}  ${damm(s)}")
    }
}
Output:
  5724  true
  5727  false
112946  true
112949  false
Translation of: Go
Library: Wren-fmt
import "./fmt" for Fmt

var table = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0]
]

var damm = Fn.new { |input|
    var interim = 0
    for (c in input.bytes) interim = table[interim][c-48]
    return interim == 0
}

for (s in ["5724", "5727", "112946", "112949"]) {
    Fmt.print("$6s  $s", s, damm.call(s))
}
Output:
  5724  true
  5727  false
112946  true
112949  false
string  0;              \use zero-terminated strings

func Damm(Input);       \Return 'true' if checksum is correct
char Input;
int  Interim, Table;
[Table:= [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ];
Interim:= 0;
while Input(0) do
    [Interim:= Table(Interim, Input(0)-^0);
    Input:= Input+1;
    ];
return Interim = 0;
];

int String, I;
[String:= ["5724", "5727", "112946", "112949"];
for I:= 0 to 4-1 do
    [Text(0, String(I));  ChOut(0, 9\tab\);
    Text(0, if Damm(String(I)) then "true" else "false");
    CrLf(0);
    ];
]
Output:
5724    true
5727    false
112946  true
112949  false
fcn damm(digits){  // digits is something that supports an iterator of integers 
   var [const]  tbl=Data(0,Int,		// 10x10 byte bucket
      0, 3, 1, 7, 5, 9, 8, 6, 4, 2,
      7, 0, 9, 2, 1, 5, 4, 8, 6, 3,
      4, 2, 0, 6, 8, 7, 1, 3, 5, 9,
      1, 7, 5, 0, 9, 8, 3, 4, 2, 6,
      6, 1, 2, 3, 0, 4, 5, 9, 7, 8,
      3, 6, 7, 4, 2, 0, 9, 5, 8, 1,
      5, 8, 6, 9, 7, 2, 0, 1, 3, 4,
      8, 9, 4, 5, 3, 6, 2, 0, 1, 7,
      9, 4, 3, 8, 6, 1, 7, 2, 0, 5,
      2, 5, 8, 1, 4, 3, 6, 7, 9, 0);
   0 == digits.reduce(fcn(interim,digit){ tbl[interim*10 + digit]  },0)
}
damm(List(5,7,2,4)).println();		// True
damm(Data(0,Int,5,7,2,7).howza(0)).println();	// stream bytes, False
damm((112946).split()).println();	// True
Output:
True
False
True
Cookies help us deliver our services. By using our services, you agree to our use of cookies.