# Luhn test of credit card numbers

Luhn test of credit card numbers
You are encouraged to solve this task according to the task description, using any language you may know.

The Luhn test is used by some credit card companies to distinguish valid credit card numbers from what could be a random selection of digits.

Those companies using credit card numbers that can be validated by the Luhn test have numbers that pass the following test:

1. Reverse the order of the digits in the number.
2. Take the first, third, ... and every other odd digit in the reversed digits and sum them to form the partial sum s1
3. Taking the second, fourth ... and every other even digit in the reversed digits:
1. Multiply each digit by two and sum the digits if the answer is greater than nine to form partial sums for the even digits
2. Sum the partial sums of the even digits to form s2
1. If s1 + s2 ends in zero then the original number is in the form of a valid credit card number as verified by the Luhn test.

For example, if the trial number is 49927398716:

Reverse the digits:
61789372994
Sum the odd digits:
6 + 7 + 9 + 7 + 9 + 4 = 42 = s1
The even digits:
1,  8,  3,  2,  9
Two times each even digit:
2, 16,  6,  4, 18
Sum the digits of each multiplication:
2,  7,  6,  4,  9
Sum the last:
2 + 7 + 6 + 4 + 9 = 28 = s2

s1 + s2 = 70 which ends in zero which means that 49927398716 passes the Luhn test

Task

Write a function/method/procedure/subroutine that will validate a number with the Luhn test, and
use it to validate the following numbers:

   49927398716
49927398717
1234567812345678
1234567812345670


Related tasks

## 11l

Translation of: Python
F luhn(n)
V ch = String(n)
V sum = 0
V chParity = ch.len % 2
L(i) (ch.len-1 .. 0).step(-1)
V j = Int(ch[i])
I (i + 1) % 2 != chParity
j *= 2
I j > 9
j -= 9
sum += j
R sum % 10 == 0

L(n) (49927398716,
49927398717,
1234567812345678,
1234567812345670)
print(luhn(n))
Output:
1B
0B
0B
1B


## 360 Assembly

Translation of: VBScript

For maximum compatibility, this program uses only the basic instruction set (S/360) and an ASSIST macro (XPRNT) to keep the code as short as possible.

*        Luhn test of credit card numbers        22/05/2016
LUHNTEST CSECT
USING  LUHNTEST,R13       base register
B      72(R15)            skip savearea
DC     17F'0'             savearea
STM    R14,R12,12(R13)    prolog
ST     R13,4(R15)         "
ST     R15,8(R13)         "
LR     R13,R15            "
LA     R9,T               @t(k)
LA     R8,N               for n
LOOPK    EQU    *                  for k=1 to n
LR     R4,R9              @t(k),@s[1]
LA     R6,1               from i=1
LA     R7,M               to m
LOOPI1   CR     R6,R7              for i=1 to m
BH     ELOOPI1            leave i
CLI    0(R4),C' '           if mid(s,i,1)=" "
BNE    ITERI1               then
BCTR   R6,0                   i-1
ST     R6,L                   l=i-1
B      ELOOPI1                exit for
*                                    end if
ITERI1   LA     R4,1(R4)             next @s[i]
LA     R6,1(R6)             i=i+1
B      LOOPI1             next i
ELOOPI1  EQU    *                  out of loop i
MVC    W,BLANK            w=" "
LA     R4,W               iw=@w
LR     R5,R9              is=@s
A      R5,L               is=@s+l
BCTR   R5,0               is=s+l-1
L      R6,L               i=l
LA     R7,1               to 1
LOOPI2   CR     R6,R7              for i=l to 1 by -1
BL     ELOOPI2            leave i
MVC    0(1,R4),0(R5)        mid(w,iw,1)=mid(s,is,1)
LA     R4,1(R4)             iw=iw+1
BCTR   R5,0                 is=is-1
BCTR   R6,0                 i=i-1
B      LOOPI2             next i
ELOOPI2  EQU    *                  out of loop i
LA     R11,0              s1=0
LA     R12,0              s2=0
LA     R6,1               i=1
L      R7,L               to l
LOOPI3   CR     R6,R7              for i=1 to l
BH     ELOOPI3            leave i
LA     R2,W-1             @w-1
AR     R2,R6              w[i]
MVC    CI,0(R2)           ci=mid(w,i,1)
NI     CI,X'0F'           zap upper half byte
LR     R4,R6              i
SRDA   R4,32              >>32
D      R4,=F'2'           i/2
LTR    R4,R4              if mod(i,2)>0
BNH    NOTMOD             then
XR     R2,R2                clear
IC     R2,CI                z=cint(mid(w,i,1))
AR     R11,R2               s1=s1+cint(mid(w,i,1))
B      EIFMOD             else
NOTMOD   XR     R2,R2                clear
IC     R2,CI                cint(mid(w,i,1))
SLA    R2,1                 *2
ST     R2,Z                 z=cint(mid(w,i,1))*2
C      R2,=F'10'            if z<10
BNL    GE10                 then
A      R12,Z                  s2=s2+z
B      EIF10                else
GE10     L      R2,Z                   z
CVD    R2,PL8                 binary to packed
UNPK   CL16,PL8               packed to zoned
OI     CL16+15,X'F0'          zoned to char (zap sign)
MVC    X(1),CL16+15           x=right(cstr(z),1)
NI     X,X'0F'                zap upper half byte
XR     R2,R2                  r2=0
IC     R2,X                   r2=cint(right(cstr(z),1))
AR     R12,R2                 s2=s2+r2
LA     R12,1(R12)             s2=s2+cint(right(cstr(z),1))+1
EIF10    EQU    *                    end if
EIFMOD   EQU    *                  end if
LA     R6,1(R6)           i=i+1
B      LOOPI3             next i
ELOOPI3  EQU    *                  out of loop i
LR     R1,R11             s1
AR     R1,R12             s1+s2
CVD    R1,PL8             binary to packed
UNPK   CL16,PL8           packed to zoned
CLI    CL16+15,X'C0'      if right(cstr(s1+s2),1)="0"
BNE    NOTZERO            then
MVC    R,=CL8'Valid'        r="Valid"
B      ECLI               else
NOTZERO  MVC    R,=CL8'Invalid'      r="Invalid"
ECLI     EQU    *                  end if
MVC    PG(M),0(R9)        t(k)
MVC    PG+M+1(L'R),R      r
XPRNT  PG,L'PG            print buffer
LA     R9,M(R9)           at=at+m
BCT    R8,LOOPK           next k
L      R13,4(0,R13)       epilog
LM     R14,R12,12(R13)    "
XR     R15,R15            "
BR     R14                exit
N        EQU    (TEND-T)/L'T
M        EQU    20
T        DC     CL(M)'49927398716         '
DC     CL(M)'49927398717         '
DC     CL(M)'1234567812345678    '
DC     CL(M)'1234567812345670    '
TEND     DS     0C
W        DS     CL(M)
BLANK    DC     CL(M)' '
L        DS     F
Z        DS     F
PL8      DS     PL8
CL16     DS     CL16
CI       DS     C
X        DS     C
R        DS     CL8
PG       DC     CL80' '            buffer
YREGS
END    LUHNTEST
Output:
49927398716          Valid
49927398717          Invalid
1234567812345678     Invalid
1234567812345670     Valid


## 8080 Assembly

	org	100h
jmp 	demo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;	Check if the 0-terminated string at HL passes the Luhn test.
;;;	Returns with carry clear if the string passes, carry set
;;;	if the string fails.
luhn:	mvi	b,0	; Counter
mov	d,b	; D = S1+S2 (we don't need to keep them separate)
lscan:	mov	a,m	; Get byte
inx 	h	; Increment pointer
inr	b	; Increment counter
ana	a	; Is it 0?
jnz	lscan	; If not, try next byte
dcx	h	; Go to the byte before the 0
dcx	h
dcr	b	; Decrement counter
rz		; If 0, the string was empty, return.
lloop:	mvi	c,'0'	; ASCII zero
mov	a,d	; Add odd digit to the total
add	m
sub	c	; Subtract ASCII zero
mov	d,a
dcr	b	; If last digit, we're done
jz	ldone
dcx	h	; Go back one byte
mov	a,m	; Get even digit
sub	c	; Subtract ASCII zero
add	a	; Multiply by two
mvi	c,9	; 10-1, compensate for extra subtraction loop
ldiv:	inr	c	; Find two digits using trial subtraction
sui	10
jnc	ldiv
add	c	; Add the possible second digit in
add	d	; Add it to the total
mov	d,a
dcx	h	; Go back one byte
dcr	b	; Done yet?
jnz	lloop
ldone:	mov	a,d	; See if total is divisible by 10
mvi	b,10
lchk:	sub	b	; Trial subtraction, subtract 10
rz		; If zero, it is divisible, return (carry clear)
rc		; If carry, it is not divisible, return (carry set)
jmp	lchk
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;	Run the routine on the argument given on the CP/M command line
demo:	lxi	h,80h	; Zero-terminate the command line argument
mov	a,m
add	l
mov	l,a
inr	l
mvi	m,0
mvi	l,82h	; Run the 'luhn' subroutine
call 	luhn
mvi	c,9
lxi	d,pass	; Carry clear = print 'Pass'
jnc	5
lxi	d,fail	; Carry set = print 'Fail'
jmp	5
pass:	db	'Pass$' fail: db 'Fail$'
Output:
A>luhn 49927398716
Pass
A>luhn 49927398717
Fail
A>luhn 1234567812345678
Fail
A>luhn 1234567812345670
Pass

## 8086 Assembly

	bits	16
cpu	8086
org	100h
section	.text
jmp	demo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 	Check whether the 0-terminated string at DS:SI passes the Luhn
;;; 	test. Returns with carry clear if the string passes, carry
;;;	set if the string fails.
luhn:	push	es	; Keep original ES, and set ES=DS so SCASB can be used.
push	ds	; "REP DS:SCASB" is a bad idea, because the 286 has a
pop	es	; bug where it "forgets" the 2nd prefix if interrupted!
mov	di,si	; DI = pointer
xor	ax,ax	; Zero to test against
xor	bl,bl	; BL = S1+S2
mov	dx,0A30h	; DH = 10 (divisor), DL = '0' (ASCII zero)
xor	cx,cx	; Set counter to 65535
dec	cx
cld		; Seek forwards
repnz	scasb	; Find zero
dec	di	; SCASB goes one byte too far
xchg	si,di	; SI = pointer, DI = end (or rather, beginning)
mov	cx,si	; CX = counter
sub	cx,di
jcxz	.done	; Empty string = stop
dec	si	; We don't need the zero itself
std		; Seek backwards
.loop:	lodsb		; Get number in odd position
sub	al,dl	; Subtract ASCII zero
add	bl,al	; Add to total
dec	cx	; One fewer character
jz	.done	; No more characters = stop
lodsb		; Get number in even position
sub	al,dl	; Subtract ASCII zero
add	al,al	; Multiply by two
xor	ah,ah	; AX = AL
div	dh	; Divide by 10; AL=quotient, AH=remainder
add	al,ah	; Add the two "digits" together
add	bl,al	; Add to total
loop 	.loop	; Decrement CX and loop
.done:	xor	ah,ah	; Divide total by 10
mov	al,bl
div	dh
and	ah,ah	; If remainder 0, then return with carry clear
jz	.out
stc		; Set carry (remainder wasn't 0, the test failed)
.out:	cld		; Clean up: clear direction flag,
pop	es	; and restore ES.
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;	Run the 'luhn' routine on the argument given on the MS-DOS
;;;	command line.
demo:	mov	si,80h			; Zero-terminate the argument
xor	bh,bh
mov	bl,[si]
mov	[si+bx+1],bh
inc	si
inc	si
call 	luhn			; Call the routine
mov	ah,9
mov	dx,pass			; If carry is clear, print 'Pass'
jnc	print
mov	dx,fail			; Otherwise, print 'fail'
print:	int	21h
ret
section	.data
pass:	db	'Pass$' fail: db 'Fail$'

Output:
C:\>luhn86 49927398716
Pass
C:\>luhn86 49927398717
Fail
C:\>luhn86 1234567812345678
Fail
C:\>luhn86 1234567812345670
Pass

## 8th

\ Adapted from the C version:
: remap \ n1 -- n2
[0,2,4,6,8,1,3,5,7,9]
swap caseof ;

: luhn \ s -- f
0 swap
s:rev
(
'0 n:-
swap 2 n:mod if remap then
n:+
) s:each
10 n:mod not ;

: test-luhn \ s --
dup . space
luhn if "OK" else "FAIL" then . cr ;

"49927398716" test-luhn
"49927398717" test-luhn
"1234567812345678" test-luhn
"1234567812345670" test-luhn

bye

Output:
49927398716 OK
49927398717 FAIL
1234567812345678 FAIL
1234567812345670 OK


## ABAP

METHOD luhn_check.

DATA: sum(1) TYPE n VALUE 0. " Sum of checksum.
DATA: current TYPE i. " Current digit.
DATA: odd TYPE i VALUE 1. " Multiplier.
DATA: len TYPE i. " String crowler.

" Luhn algorithm.
len = NUMOFCHAR( pi_string ) - 1.
WHILE ( len >= 0 ).
current = pi_string+len(1) * odd.
IF ( current > 9 ).
current = current - 9. " Digits sum.
ENDIF.
sum = sum + current.
odd = 3 - odd. " 1 <--> 2 Swich
len = len - 1. " Move to next charcter.
ENDWHILE.

" Validation check.
IF ( sum = 0 ).
pr_valid = abap_true.
ELSE.
pr_valid = abap_false.
ENDIF.

ENDMETHOD.


## ACL2

(include-book "arithmetic-3/top" :dir :system)

(defun digits (n)
(if (zp n)
nil
(cons (mod n 10)
(digits (floor n 10)))))

(defun sum (xs)
(if (endp xs)
0
(+ (first xs)
(sum (rest xs)))))

(defun double-and-sum-digits (xs)
(if (endp xs)
nil
(cons (sum (digits (* 2 (first xs))))
(double-and-sum-digits (rest xs)))))

(defun dmx (xs)
(if (endp (rest xs))
(mv xs nil)
(mv-let (odds evens)
(dmx (rest (rest xs)))
(mv (cons (first xs) odds)
(cons (second xs) evens)))))

(defun luhn (n)
(mv-let (odds evens)
(dmx (digits n))
(= (mod (+ (sum odds)
(sum (double-and-sum-digits evens)))
10)
0)))

Output:
> (luhn 49927398716)
T
> (luhn 49927398717)
NIL
> (luhn 1234567812345678)
NIL
> (luhn 1234567812345670)
T

## Action!

PROC ReverseDigits(CHAR ARRAY n,rev)
BYTE i,j

i=n(0)
WHILE i>0 AND n(i)='0
DO
i==-1
OD

j=1
WHILE i>0
DO
rev(j)=n(i)
j==+1 i==-1
OD
rev(0)=j-1
RETURN

BYTE FUNC SumOddDigits(CHAR ARRAY n)
BYTE sum,i

sum=0
FOR i=1 TO n(0) STEP 2
DO
sum==+ValB(n(i))
OD
RETURN(sum)

BYTE FUNC SumEvenDigitsMultiplied(CHAR ARRAY n)
BYTE sum,i,v

sum=0
FOR i=2 TO n(0) STEP 2
DO
v=ValB(n(i))*2
IF v>9 THEN v==-9 FI
sum==+v
OD
RETURN(sum)

BYTE FUNC Luhn(CHAR ARRAY n)
CHAR ARRAY rev(20)
BYTE s1,s2

ReverseDigits(n,rev)
s1=SumOddDigits(rev)
s2=SumEvenDigitsMultiplied(rev)

IF (s1+s2) MOD 10=0 THEN
RETURN(1)
FI
RETURN(0)

PROC Test(CHAR ARRAY n)
PrintF("%S is ",n)
IF Luhn(n) THEN
PrintE("valid")
ELSE
PrintE("invalid")
FI
RETURN

PROC Main()
Test("49927398716")
Test("49927398717")
Test("1234567812345678")
Test("1234567812345670")
RETURN
Output:
49927398716 is valid
49927398717 is invalid
1234567812345678 is invalid
1234567812345670 is valid


## ActionScript

function isValid(numString:String):Boolean
{
var isOdd:Boolean = true;
var oddSum:uint = 0;
var evenSum:uint = 0;
for(var i:int = numString.length - 1; i >= 0; i--)
{
var digit:uint = uint(numString.charAt(i))
if(isOdd) oddSum += digit;
else evenSum += digit/5 + (2*digit) % 10;
isOdd = !isOdd;
}
if((oddSum + evenSum) % 10 == 0) return true;
return false;
}

trace(isValid("49927398716"));
trace(isValid("49927398717"));
trace(isValid("1234567812345678"));
trace(isValid("1234567812345670"));


## Ada

Translation of: C
Works with: GNAT
with Ada.Text_IO;
use  Ada.Text_IO;

procedure Luhn is

function Luhn_Test (Number: String) return Boolean is
Sum  : Natural := 0;
Odd  : Boolean := True;
Digit: Natural range 0 .. 9;
begin
for p in reverse Number'Range loop
Digit := Integer'Value (Number (p..p));
if Odd then
Sum := Sum + Digit;
else
Sum := Sum + (Digit*2 mod 10) + (Digit / 5);
end if;
Odd := not Odd;
end loop;
return (Sum mod 10) = 0;
end Luhn_Test;

begin

Put_Line (Boolean'Image (Luhn_Test ("49927398716")));
Put_Line (Boolean'Image (Luhn_Test ("49927398717")));
Put_Line (Boolean'Image (Luhn_Test ("1234567812345678")));
Put_Line (Boolean'Image (Luhn_Test ("1234567812345670")));

end Luhn;

Output:
TRUE
FALSE
FALSE
TRUE


## ALGOL 68

Translation of: C++ – Note: This specimen retains the original C coding style.
Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards)
PROC to int = (CHAR c)INT:
ABS c - ABS "0";

PROC confirm = (STRING id)BOOL:
(
BOOL is odd digit := TRUE;
INT s := 0;
STRING cp;

FOR cp key FROM UPB id BY -1 TO LWB id DO
INT k := to int(id[cp key]);
s +:=
IF is odd digit THEN k
ELIF k /= 9 THEN 2*k MOD 9
ELSE 9
FI;
is odd digit := NOT is odd digit
OD;
0 = s MOD 10
);

main:
(
[]STRING t cases = (
"49927398716",
"49927398717",
"1234567812345678",
"1234567812345670"
);
FOR cp key TO UPB t cases DO
STRING cp = t cases[cp key];
print((cp, ": ", confirm(cp), new line))
OD
)
Output:
49927398716: T
49927398717: F
1234567812345678: F
1234567812345670: T


## ALGOL W

Separate source so the LuhnTest procedure can be used in other tasks, e.g.: Validate International Securities Identification Number

% returns true if ccNumber passes the Luhn test, false otherwise %
% as Algol W has fixed length strings, the length of the number  %
% must be specified in ccLength                                  %
logical procedure LuhnTest ( string(32) value ccNumber
; integer    value ccLength
) ;
begin
integer checkSum;
logical oddDigit, isValid;
checkSum := 0;
isValid := oddDigit := true;
for cPos := ccLength step -1 until 1 do begin
integer digit;
digit := decode( ccNumber( cPos - 1 // 1 ) ) - decode( "0" );
if digit < 0 or digit > 9 then isValid := false
else if oddDigit
then checkSum := checkSum + digit
else checkSum := checkSum + ( case digit + 1 of ( 0, 2, 4, 6, 8
, 1, 3, 5, 7, 9
)
);
oddDigit := not oddDigit
end for_cPos ;
isValid and ( ( checkSum rem 10 ) = 0 )
end LuhnTest

Use the above to test the LuhnTest procedure:

begin
% external procedure that returns true if ccNumber passes the Luhn test, false otherwise %
logical procedure LuhnTest ( string(32) value ccNumber
; integer    value ccLength
) ; algol "LUHN" ;

% task test cases %

procedure testLuhnTest ( string(32) value ccNumber
; integer    value ccLength
) ;
write( s_w := 0, ccNumber, if LuhnTest( ccNumber, ccLength ) then " is valid" else " is invalid" );

testLuhnTest( "49927398716",      11 );
testLuhnTest( "49927398717",      11 );
testLuhnTest( "1234567812345678", 16 );
testLuhnTest( "1234567812345670", 16 )

end.
Output:
49927398716                      is valid
49927398717                      is invalid
1234567812345678                 is invalid
1234567812345670                 is valid


## APL

Works with: Dyalog APL
LuhnTest←{
digits←⍎¨⍵                       ⍝ Characters to digits
doubled←2∘×@(⌽⍤~1 0⍴⍨≢)⊢digits   ⍝ Double every other digit
partial←-∘9@(9∘<)⊢doubled        ⍝ Subtract 9 is equivalent to sum of digits for the domain 10≤x≤19
0=10|+/partial                   ⍝ Valid if sum is a multiple of 10
}

Output:
      LuhnTest¨'49927398716' '49927398717' '1234567812345678' '1234567812345670'
1 0 0 1

Works with: APL+Win
    ∇ ret←LuhnTest num;s1;s2
[1]   num←⌽((⌈10⍟num)/10)⊤num
[2]   s1←+/((⍴num)⍴1 0)/num
[3]   s2←+/∊(⊂10 10)⊤¨2×((⍴num)⍴0 1)/num
[4]   ret←0=10⊤s1+s2
∇

Output:
      LuhnTest¨ 49927398716 49927398717 1234567812345678 1234567812345670
1 0 0 1


## AppleScript

### Functional

-- luhn :: String -> Bool
on luhn(s)
-- True if the digit string represents
-- a valid Luhn credit card number.

script divMod10Sum
on |λ|(a, x)
a + x div 10 + x mod 10
end |λ|
end script

0 = foldl(divMod10Sum, 0, ¬
zipWith(my mul, ¬
map(my int, reverse of (characters of s)), ¬
cycle({1, 2}))) mod 10
end luhn

--------------------------- TEST ---------------------------
on run
map(luhn, ¬
{"49927398716", "49927398717", ¬
"1234567812345678", "1234567812345670"})

--> {true, false, false, true}
end run

---------------- REUSABLE GENERIC FUNCTIONS ----------------

-- cycle :: [a] -> Generator [a]
on cycle(xs)
script
property lng : 1 + (length of xs)
property i : missing value
on |λ|()
if missing value is i then
set i to 1
else
set nxt to (1 + i) mod lng
if 0 = ((1 + i) mod lng) then
set i to 1
else
set i to nxt
end if
end if
return item i of xs
end |λ|
end script
end cycle

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl

-- int :: String -> Int
on int(s)
s as integer
end int

-- length :: [a] -> Int
on |length|(xs)
set c to class of xs
if list is c or string is c then
length of xs
else
(2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
end if
end |length|

-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map

-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min

-- mul (*) :: Num a => a -> a -> a
on mul(a, b)
a * b
end mul

-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
set c to class of xs
if list is c then
if 0 < n then
items 1 thru min(n, length of xs) of xs
else
{}
end if
else if string is c then
if 0 < n then
text 1 thru min(n, length of xs) of xs
else
""
end if
else if script is c then
set ys to {}
repeat with i from 1 to n
set v to |λ|() of xs
if missing value is v then
return ys
else
set end of ys to v
end if
end repeat
return ys
else
missing value
end if
end take

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
set lng to min(|length|(xs), |length|(ys))
if 1 > lng then return {}
set xs_ to take(lng, xs) -- Allow for non-finite
set ys_ to take(lng, ys) -- generators like cycle etc
set lst to {}
tell mReturn(f)
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs_, item i of ys_)
end repeat
return lst
end tell
end zipWith

Output:
{true, false, false, true}

### Straightforward

on luhnTest(n)
-- Accept only text input.
if (n's class is not text) then return false
-- Edit out any spaces or dashes.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to {space, "-"}
set n to n's text items
set AppleScript's text item delimiters to ""
set n to n as text
set AppleScript's text item delimiters to astid
-- Check that what's left is numeric.
try
n as number
on error
return false
end try

-- Do the calculation two digits at a time, starting at the end of the text and working back.
set sum to 0
repeat with i from ((count n) - 1) to 1 by -2
set n2 to (text i thru (i + 1) of n) as integer
tell n2 div 10 mod 10 * 2 to set sum to sum + it div 10 + it mod 10 + n2 mod 10
end repeat
-- If there's an odd digit left over, add that in too.
if (i is 2) then set sum to sum + (character 1 of n)

return (sum mod 10 is 0)
end luhnTest

-- Test code:
set testResults to {}
repeat with testNumber in {"49927398716", "49927398717", "1234567812345678", "1234567812345670"}
set end of testResults to {testNumber:testNumber's contents, valid:luhnTest(testNumber)}
end repeat
return testResults

Output:
{{testNumber:"49927398716", valid:true}, {testNumber:"49927398717", valid:false}, {testNumber:"1234567812345678", valid:false}, {testNumber:"1234567812345670", valid:true}}


## ARM Assembly

.text
.global _start
_start:
ldr r0, =example_numbers
bl test_number

add r1, r0, #1
bl length
add r0, r1, r0
bl test_number

add r1, r0, #1
bl length
add r0, r1, r0
bl test_number

add r1, r0, #1
bl length
add r0, r1, r0
bl test_number

mov r0, #0
mov r7, #1
swi 0

test_number:
push {r0, lr}
bl print_string

bl luhn_test
cmp r0, #1
ldreq r0, =valid_message
ldrne r0, =invalid_message
bl print_string
pop {r0, lr}
mov pc, lr

print_string:
push {r0-r7, lr}
mov r1, r0   @ string to print
bl length
mov r2, r0   @ length of string
mov r0, #1   @ write to stdout
mov r7, #4   @ SYS_WRITE
swi 0        @ call system interupt
pop {r0-r7, lr}
mov pc, lr

@ r0 address of credit card number string
@ returns result in r0
luhn_test:
push {r1-r7, lr}
mov r1, r0
bl isNumerical            @ check if string is a number
cmp r0, #1
bne .luhn_test_end        @ exit if not number
mov r0, r1
ldr r1, =reversed_string  @ address to store reversed string
bl reverse                @ reverse string
push {r0}
bl length   @ get length of string
mov r4, r0  @ store string length in r4
pop {r0}
mov r2, #0  @ string index
mov r6, #0  @ sum of odd digits
mov r7, #0  @ sum of even digits
.loadNext:
ldrb r3, [r1, r2]         @ load byte into r3
sub r3, #'0'              @ convert letter to digit
and r5, r2, #1            @ test if index is even or odd
cmp r5, #0
beq .odd_digit
bne .even_digit
.odd_digit:
add r6, r3              @ add digit to sum if odd
b .continue             @ skip next step
.even_digit:
lsl r3, #1              @ multiply digit by 2
cmp r3, #10             @ sum digits
subge r3, #10           @ get digit in 1s place
addge r3, #1            @ add 1 for the 10s place
add r7, r3              @ add digit sum to the total

.continue:
add r2, #1                @ increment digit index
cmp r2, r4                @ check if at end of string
blt .loadNext

add r0, r6, r7                @ add even and odd sum
mov r3, r0                    @ copy sum to r3
ldr r1, =429496730            @ (2^32-1)/10
sub r0, r0, r0, lsr #30       @ divide by 10
umull r2, r0, r1, r0
mov r1, #10
mul r0, r1                    @ multiply the r0 by 10 to see if divisible
cmp r0, r3                    @ compare with the original value in r3
.luhn_test_end:
movne r0, #0                  @ return false if invalid card number
moveq r0, #1                  @ return true if valid card number
pop {r1-r7, lr}
mov pc, lr

length:
push {r1-r2, lr}
mov r2, r0              @ start of string address
.loop:
ldrb r1, [r2], #1   @ load byte from address r2 and increment
cmp r1, #0          @ check for end of string
bne .loop           @ load next byte if not 0
sub r0, r2, r0          @ subtract end of string address from start
sub r0, #1              @ end of line from count
pop {r1-r2, lr}
mov pc, lr

@ reverses a string
@ r0 address of string to reverse
@ r1 address to store reversed string
reverse:
push {r0-r5, lr}
push {r0, lr}
bl length                @ get length of string to reverse
mov r3, r0               @ backword index
pop {r0, lr}
mov r4, #0               @ fowrard index
.reverse_next:
sub r3, #1           @ decrement backword index
ldrb r5, [r0, r3]    @ load byte from original string at index
strb r5, [r1, r4]    @ copy byte to reversed string
add r4, #1           @ increment fowrard index
cmp r3, #0           @ check if any characters are left
bge .reverse_next

mov r5, #0
strb r5, [r1, r4]  @ write null byte to terminate reversed string
pop {r0-r5, lr}
mov pc, lr

isNumerical:
push {r1, lr}
.isNumerical_checkNext:
ldrb r1, [r0], #1
cmp r1, #0
beq .isNumerical_true
cmp r1, #'0'
blt .isNumerical_false
cmp r1, #'9'
bgt .isNumerical_false
b .isNumerical_checkNext
.isNumerical_false:
mov r0, #0
b .isNumerical_end
.isNumerical_true:
mov r0, #1
.isNumerical_end:
pop {r1, lr}
mov pc, lr

.data
valid_message:
.asciz " valid card number\n"
invalid_message:
.asciz " invalid card number\n"

reversed_string:
.space 32

example_numbers:
.asciz "49927398716"
.asciz "49927398717"
.asciz "1234567812345678"
.asciz "1234567812345670"

## Arturo

digits: function [n][
res: new []
while -> n > 0 [
'res ++ n % 10
n: n / 10
]
res
]

luhn?: function [n][
s1: new 0
s2: new 0
loop.with: 'i digits n 'd [
if? even? i -> 's1 + d
else [
'd * 2
if d > 9 -> 'd - 9
's2 + d
]
]
zero? (s1 + s2) % 10
]

print luhn? 49927398716
print luhn? 49927398717
print luhn? 1234567812345678
print luhn? 1234567812345670

Output:
true
false
false
true

## AutoHotkey

; Originally submitted by Laszlo:
; http://www.autohotkey.com/forum/post-229412.html#229412

MsgBox % LuhnTest(49927398716)
MsgBox % LuhnTest(49927398717)
MsgBox % LuhnTest(1234567812345678)
MsgBox % LuhnTest(1234567812345670)

Return

;-----------------------------

LuhnTest(Number)
{
MultFactor := 2 - ( StrLen(Number) & 1 )  ,  Sum := 0
Loop, Parse, Number
Sum += ( ( 9 < ( Temp := MultFactor * A_LoopField ) ) ? Temp - 9 : Temp )  ,  MultFactor := 3 - MultFactor
Return !Mod(Sum,10)
}


## AutoIt

Global $avarray[4] = [49927398716, 49927398717, 1234567812345678, 1234567812345670] For$i = 0 To 3
checkLuhn($avarray[$i])
Next

Func checkLuhn($number)$sum = 0
$numDigits = StringSplit($number, "")
For $i =$numDigits[0] - 1 To 1 Step -2
$numDigits[$i] = $numDigits[$i] * 2
If $numDigits[$i] >= 10 Then $numDigits[$i] -= 9
Next
For $i = 1 To$numDigits[0]
$sum +=$numDigits[$i] Next If StringRight($sum, 1) = "0" Then
ConsoleWrite("Luhn-Check (" & $number & ") : True" & @CRLF) Return True Else ConsoleWrite("Luhn-Check (" &$number & ") : False" & @CRLF)
Return False
EndIf
EndFunc   ;==>checkLuhn

Output:
Luhn-Check (49927398716) : True
Luhn-Check (49927398717) : False
Luhn-Check (1234567812345678) : False
Luhn-Check (1234567812345670) : True

## AWK

#!/usr/bin/awk -f
BEGIN {
A[1] = 49927398716;
A[2] = 49927398717;
A[3] = 1234567812345678;
A[4] = 1234567812345670;
A[5] = "01234567897";
A[6] = "01234567890";
A[7] = "00000000000";
for (k in A) print "isLuhn("A[k]"): ",isLuhn(A[k]);
}

function isLuhn(cardno) {
s = 0;
m = "0246813579";
n = length(cardno);
for (k = n; 0 < k; k -= 2) {
s += substr(cardno, k, 1);
}
for (k = n-1; 0 < k; k -= 2) {
s += substr(m, substr(cardno, k, 1)+1, 1);
}
return ((s%10)==0);
}

Output:
isLuhn(1234567812345670):  1
isLuhn(01234567897):  1
isLuhn(01234567890):  0
isLuhn(00000000000):  1
isLuhn(49927398716):  1
isLuhn(49927398717):  0
isLuhn(1234567812345678):  0

## Bash

#!/bin/bash

function luhn_validate  # <numeric-string>
{
num=$1 shift 1 len=${#num}
is_odd=1
sum=0
for((t = len - 1; t >= 0; --t)) {
digit=${num:$t:1}

if [[ $is_odd -eq 1 ]]; then sum=$(( sum + $digit )) else sum=$(( $sum + ($digit != 9 ? ( ( 2 * $digit ) % 9 ) : 9 ) )) fi is_odd=$(( ! $is_odd )) } # NOTE: returning exit status of 0 on success return$(( 0 != ( $sum % 10 ) )) } function print_result # <numeric-string> { if luhn_validate "$1"; then
echo "$1 is valid" else echo "$1 is not valid"
fi
}

print_result "49927398716"
print_result "49927398717"
print_result "1234567812345678"
print_result "1234567812345670"

Output:
49927398716 is valid
49927398717 is not valid
1234567812345678 is not valid
1234567812345670 is valid


## BASIC

### BASIC256

dim card$(5) card$[1]="49927398716"
card$[2]="49927398717" card$[3]="1234567812345678"
card$[4]="1234567812345670" for test = 1 to 4 odd = True sum = 0 for n = length(card$[test]) to 1 step -1
num = int(mid(card$[test],n,1)) if odd then sum += num odd = False else num *= 2 if num <= 9 then sum += num else sum += int(left(string(num),1)) + int(right(string(num),1)) end if odd = True end if next if sum mod 10 = 0 then print card$[test], "True"
else
print card$[test], "False" end if next test ### Chipmunk Basic Works with: Chipmunk Basic version 3.6.4 100 cls 110 rem Luhn test 120 dim card$(5)
130 card$(1) = "49927398716" 140 card$(2) = "49927398717"
150 card$(3) = "1234567812345678" 160 card$(4) = "1234567812345670"
170 for test = 1 to 4
180   odd = true
190   sum = 0
200   for n = len(card$(test)) to 1 step -1 210 num = val(mid$(card$(test),n,1)) 220 if odd then 230 sum = sum+num 240 odd = false 250 else 260 num = num*2 270 if num <= 9 then 280 sum = sum+num 290 else 300 sum = sum+val(left$(str$(num),1))+val(right$(str$(num),1)) 310 endif 320 odd = true 330 endif 340 next 350 if sum mod 10 = 0 then 360 print card$(test),"True"
370   else
380     print card$(test),"False" 390 endif 400 next test  ### IS-BASIC 100 PROGRAM "CredCard.bas" 110 DO 120 PRINT :PRINT "Credit card number:":INPUT PROMPT ">":CCN$
130   IF CCN$="" THEN EXIT DO 140 IF LUHN(TRIM$(CCN$)) THEN 150 PRINT "Card number is valid." 160 ELSE 170 SET #102:INK 3:PRINT "Card number is invalid.":SET #102:INK 1 180 END IF 190 LOOP 200 DEF LUHN(CCN$)
210   LET L=LEN(CCN$):LET S=0 220 FOR I=1 TO L 230 LET N=VAL(CCN$(L-I+1))
240     IF I BAND 1 THEN
250       LET S=S+N
260     ELSE
270       LET N=N*2:LET S=S+MOD(N,10)+INT(N/10)
280     END IF
290   NEXT
300   LET LUHN=MOD(S,10)=0
310 END DEF
320 DEF TRIM$(S$)
330   LET T$="" 340 FOR I=1 TO LEN(S$)
350     IF S$(I)>CHR$(47) AND S$(I)<CHR$(58) THEN LET T$=T$&S$(I) 360 NEXT 370 LET TRIM$=T$380 END DEF Output: Credit card number: >49927398716 Card number is valid. Credit card number: >49927398717 Card number is invalid. Credit card number: >1234 5678 1234 5678 Card number is invalid. Credit card number: >1234 5678 1234 5670 Card number is valid. ### QBasic Works with: QBasic version 1.1 Works with: QuickBasic version 4.5 CONST True = -1: False = NOT True DIM card$(5)
card$(1) = "49927398716" card$(2) = "49927398717"
card$(3) = "1234567812345678" card$(4) = "1234567812345670"

FOR test = 1 TO 4
odd = True
sum = 0
FOR n = LEN(card$(test)) TO 1 STEP -1 num = VAL(MID$(card$(test), n, 1)) IF odd THEN sum = sum + num odd = False ELSE num = num * 2 IF num <= 9 THEN sum = sum + num ELSE sum = sum + VAL(LEFT$(STR$(num), 1)) + VAL(RIGHT$(STR$(num), 1)) END IF odd = True END IF NEXT IF sum MOD 10 = 0 THEN PRINT card$(test), "True"
ELSE
PRINT card$(test), "False" END IF NEXT test  ### True BASIC LET true = -1 LET false = 0 DIM card$(5)
LET card$(1) = "49927398716" LET card$(2) = "49927398717"
LET card$(3) = "1234567812345678" LET card$(4) = "1234567812345670"

FOR test = 1 TO 4
LET odd = true
LET sum = 0
FOR n = LEN(card$(test)) TO 1 STEP -1 LET num = VAL((card$(test))[n:n+1-1])
IF odd<>0 THEN
LET sum = sum + num
LET odd = false
ELSE
LET num = num*2
IF num <= 9 THEN
LET sum = sum + num
ELSE
LET sum = sum + VAL((STR$(num))[1:1]) + VAL((STR$(num))[LEN(STR$(num))-1+1:maxnum]) END IF LET odd = true END IF NEXT n IF remainder(round(sum),10) = 0 THEN PRINT card$(test), "True" ELSE PRINT card$(test), "False" NEXT test END  ### uBasic/4tH Translation of: C Print " 49927398716", Show (Iif(FUNC(_Luhn ("49927398716")), "ok", "fail")) Print " 49927398717", Show (Iif(FUNC(_Luhn ("49927398717")), "ok", "fail")) Print "1234567812345678", Show (Iif(FUNC(_Luhn ("1234567812345678")), "ok", "fail")) Print "1234567812345670", Show (Iif(FUNC(_Luhn ("1234567812345670")), "ok", "fail")) End _Luhn Param (1) Local (4) c@ = 1 : d@ = 0 For b@ = Len(a@)-1 To 0 Step -1 e@ = Peek(a@, b@) - Ord("0") d@ = d@ + Iif (c@, e@, e@+e@-9*(e@>4)) c@ = c@ = 0 Next Return ((d@ % 10) = 0)  Output:  49927398716 ok 49927398717 fail 1234567812345678 fail 1234567812345670 ok 0 OK, 0:333 ### Yabasic dim card$(5)
card$(1)="49927398716" card$(2)="49927398717"
card$(3)="1234567812345678" card$(4)="1234567812345670"

for test = 1 to 4
odd = true
sum = 0
for n = len(card$(test)) to 1 step -1 num = val(mid$(card$(test),n,1)) if odd then sum = sum + num odd = false else num = num * 2 if num <= 9 then sum = sum + num else sum = sum + val(left$(str$(num),1)) + val(right$(str$(num),1)) fi odd = true fi next if mod(sum, 10) = 0 then print card$(test), chr$(9), "True" else print card$(test), chr$(9), "False" fi next test ## Batch File This simple implementation does not reverse the numbers. Instead, it counts from right to left. @echo off setlocal enabledelayedexpansion call :luhn 49927398716 call :luhn 49927398717 call :luhn 1234567812345678 call :luhn 1234567812345670 exit /b 0 :luhn set "input=%1" set "cnt=0" set "s1=0" set "s2=0" :digit_loop set /a "cnt-=1" set /a "isOdd=(-%cnt%)%%2" if !isodd! equ 1 ( set /a "s1+=!input:~%cnt%,1!" ) else ( set /a "twice=!input:~%cnt%,1!*2" if !twice! geq 10 ( set /a "s2+=!twice:~0,1!+!twice:~1,1!" ) else ( set /a "s2+=!twice!" ) ) if "!input:~%cnt%!"=="!input!" ( set /a "sum=(!s1!+!s2!)%%10" if !sum! equ 0 (echo !input! is valid.) else (echo !input! is not valid.) goto :EOF ) goto digit_loop Output: >luhn.bat 49927398716 is valid. 49927398717 is not valid. 1234567812345678 is not valid. 1234567812345670 is valid. > ## BBC BASIC  FOR card% = 1 TO 4 READ cardnumber$
IF FNluhn(cardnumber$) THEN PRINT "Card number " cardnumber$ " is valid"
ELSE
PRINT "Card number " cardnumber$" is invalid" ENDIF NEXT card% END DATA 49927398716, 49927398717, 1234567812345678, 1234567812345670 DEF FNluhn(card$)
LOCAL I%, L%, N%, S%
L% = LEN(card$) FOR I% = 1 TO L% N% = VAL(MID$(card$, L%-I%+1, 1)) IF I% AND 1 THEN S% += N% ELSE N% *= 2 S% += N% MOD 10 + N% DIV 10 ENDIF NEXT = (S% MOD 10) = 0  ## bc /* Return 1 if number passes Luhn test, else 0 */ define l(n) { auto m, o, s, x o = scale scale = 0 m = 1 while (n > 0) { x = (n % 10) * m if (x > 9) x -= 9 s += x m = 3 - m n /= 10 } s %= 10 scale = o if (s) return(0) return(1) } l(49927398716) l(49927398717) l(1234567812345678) l(1234567812345670)  Output: 1 0 0 1 ## BCPL get "libhdr" let luhn(s) = valof$(  let sum=0 and fac=1
for i = s%0 to 1 by -1
$( unless '0' <= s%i <= '9' resultis false sum := sum + fac*(s%i - '0') rem 10 + fac*(s%i - '0')/10 fac := 3 - fac$)
resultis sum rem 10 = 0
$) let show(s) be writef("%S: %S*N", s, luhn(s) -> "pass", "fail") let start() be$(  show("49927398716")
show("49927398717")
show("1234567812345678")
show("1234567812345670")
$) Output: 49927398716: pass 49927398717: fail 1234567812345678: fail 1234567812345670: pass ## Befunge v 1 >$0 v   v                                    <
>&:19+|v  <            >v      5      6   7      8
^  \   <>09p19p>09g+09p:|>2*:19+%19g+19p19+/19g+19p:|
2          3      4  >                           v
v"invalid"<10  9
|%+91+g91g90<
v  "valid"<
>:#,_@
11


The labelled points (1 to 11) are: 1. Read in input until number greater than 10, 2. Reverse the order, 3. Set accumulators to 0, 4. Add odd number to accumulator, 5. Mod even number with 10, 6. Add this digit to accumulator, 7. Integer divide number by 10, 8. Add this digit to accumulator, 9. Add odd and even accumulators, 10. Mod this accumulator with 10, 11. Print result.

The code requires input be separated by spaces and ended with a number greater than 10 to exit the reading loop. This could be done by reading characters and ending at a new line, but this way is much simpler.

Inputs:

4 9 9 2 7 3 9 8 7 1 6 99
4 9 9 2 7 3 9 8 7 1 7 99
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 99
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 0 99

Output:
valid
invalid
invalid
valid


## BQN

Luhn ← (0=10|⊢)∘(+´(10|⊢)+⊢≥10˙)∘(⊢×≠⥊1‿2˙)∘(⌽•Fmt-'0'˙)

(⍉⊢≍Luhn¨) ⟨49927398716,49927398717,1234567812345678,1234567812345670⟩

Output:
┌─
╵      49927398716 1
49927398717 0
1234567812345678 0
1234567812345670 1
┘

## Bracmat

  ( luhn
=   sum odd even
.   0:?sum
& rev$!arg:?arg & whl ' ( @( !arg : %?odd ( %?even ?arg | :?arg&0:?even ) ) & !odd+mod$(2*!even.10)+div$(!even.5)+!sum:?sum ) & mod$(!sum.10):0
)
& ( test
=
.   out
$(!arg ":" (luhn$!arg&true|false))
)
& test$49927398716 & test$49927398717
& test$1234567812345678 & test$1234567812345670
& ;
Output:
49927398716 : true
49927398717 : false
1234567812345678 : false
1234567812345670 : true

## Brainf***

>>>>>>>>>+>,----------[                        READ CHARACTERS UNTIL \N AND
>++++++++[<----->-]<++>>>>>>+>,----------]   SUBTRACT ASCII 0 FROM EACH
<-<<<<<<<                                      GO TO LAST DIGIT
[                                              WHILE THERE ARE DIGITS
>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<<             ADD RUNNING TOTAL TO ODD DGT
<<<<<<<                                        GO TO EVEN DIGIT
[                                              IF THERE IS ONE
>[->++<]>[-<+>]                                MUL BY TWO
>>>++++++++++<<<<[                             DIVMOD BY TEN
>>>[-]+>-[<-<]<[<<]                            DECR DIVISOR
>>[                                            IF ZERO
>++++++++++>+<<-]<<<                           SET TO TEN; INCR QUOTIENT
-]                                               DECR DIVIDEND UNTIL ZERO
++++++++++>>>>[-<<<<->>>>]                     CALCULATE REMAINDER
>[-<<<<<+>>>>>]                                ADD QUOTIENT TO IT
>>[-<<<<<<<+>>>>>>>]<<<<<<<<                   THEN ADD RUNNING TOTAL
<<<<<                                          ZERO BEFORE NEXT ODD DIGIT
]<<                                            GO TO NEXT ODD DIGIT
]
>>>>>>>-[+>>-]>                                GO TO TOTAL
>>>>++++++++++<<<<[                            MODULO TEN
>>>[-]+>-[<-<]<[<<]                            DECR DIVISOR
>>[>++++++++++<-]                              IF ZERO SET BACK TO TEN
<<<-]                                            DECR DIVIDEND UNTIL ZERO
>>>++++++++++>[-<->]<                          REMAINDER: TEN MINUS DIVISOR
<<<<<<++++++++++[->                            VALUES FOR ASCII OUTPUT
+++++++++++>                                   110
++++++++++>                                    100
++++++++>                                      80
+++++++<<<<]                                   70
>>>>>+>                                        GO BACK TO REMAINDER
[<<.<<---.<-----.+++.<]                        IF NOT ZERO FAIL
<[<<.<---.<+++++..<]                           IF ZERO PASS
++++++++++.                                    NEWLINE

Output:
$echo 49927398716 | beef luhn.bf Pass$ echo 49927398717 | beef luhn.bf
Fail
$echo 1234567812345678 | beef luhn.bf Fail$ echo 1234567812345670 | beef luhn.bf
Pass

## Bruijn

:import std/Combinator .
:import std/Math .
:import std/List .

luhn number→list → reverse → check → (\mod (+10)) → zero?
check y [[[[0 [[[6 \5 (4 + (5 odd even)) 1]]] 1]]]] k (+0)
odd 2
even digit-sum (2 ⋅ (+2))

:test (luhn (+61789372994)) ([[1]])
:test (luhn (+49927398716)) ([[1]])
:test (luhn (+49927398717)) ([[0]])
:test (luhn (+1234567812345678)) ([[0]])
:test (luhn (+1234567812345670)) ([[1]])

## Burlesque

tt         "Remove whitespace"vv
pe         "Eval to number"vv
<-         "Reverse digits"vv
XX         "Split number into digits"vv

{
{ "Odd digits"vv
2EN
}

{ "Even digits"vv
2en
{
2.*     "Double"vv
^^ 9.>  "<test>=Duplicate greater than 9"vv
{
XX++   "Sum digits"vv
}if     "If <test>"vv
}m[      "For each even digit"vv
}
}M-       "Cool map. Create array of each branch applied to argument."vv

{++}m[    "Sum each block (odd & even)"vv
++        "Sum these"vv
[-        "Last digit"vv
0==       "Equal to zero"vv
Q         "Pretty print"vv

Output:
     49927398716        1
49927398717        0
1234567812345678        0
1234567812345670        1


## C

#include <string.h>
#include <stdio.h>

int luhn(const char* cc)
{
const int m[] = {0,2,4,6,8,1,3,5,7,9}; // mapping for rule 3
int i, odd = 1, sum = 0;

for (i = strlen(cc); i--; odd = !odd) {
int digit = cc[i] - '0';
sum += odd ? digit : m[digit];
}

return sum % 10 == 0;
}

int main()
{
const char* cc[] = {
"49927398716",
"49927398717",
"1234567812345678",
"1234567812345670",
0
};
int i;

for (i = 0; cc[i]; i++)
printf("%16s\t%s\n", cc[i], luhn(cc[i]) ? "ok" : "not ok");

return 0;
}

Output:
     49927398716        ok
49927398717        not ok
1234567812345678        not ok
1234567812345670        ok


## C#

The LuhnCheck method takes an array of integers because values in memory will be integer-aligned.

    public static class Luhn
{
public static bool LuhnCheck(this string cardNumber)
{
return LuhnCheck(cardNumber.Select(c => c - '0').ToArray());
}

private static bool LuhnCheck(this int[] digits)
{
return GetCheckValue(digits) == 0;
}

private static int GetCheckValue(int[] digits)
{
return digits.Select((d, i) => i % 2 == digits.Length % 2 ? ((2 * d) % 10) + d / 5 : d).Sum() % 10;
}
}

public static class TestProgram
{
public static void Main()
{
long[] testNumbers = {49927398716, 49927398717, 1234567812345678, 1234567812345670};
foreach (var testNumber in testNumbers)
Console.WriteLine("{0} is {1}valid", testNumber, testNumber.ToString().LuhnCheck() ? "" : "not ");
}
}

49927398716 is valid
49927398717 is not valid
1234567812345678 is not valid
1234567812345670 is valid


Note that the original implementation, which follows, is flawed because it assumes that n is a number which, when represented as a string, has an even number of characters. Granted, the brief is for Credit Card Numbers which are all, at the time of writing, an even number of digits.

using System;
using System.Linq;

namespace Luhn
{
class Program
{
public static bool luhn(long n)
{
long nextdigit, sum = 0;
bool alt = false;
while (n != 0)
{
nextdigit = n % 10;
if (alt)
{
nextdigit *= 2;
nextdigit -= (nextdigit > 9) ? 9 : 0;
}
sum += nextdigit;
alt = !alt;
n /= 10;
}
return (sum % 10 == 0);
}

public static bool luhnLinq(long n)
{
string s = n.ToString();
return s.Select((c, i) => (c - '0') << ((s.Length - i - 1) & 1)).Sum(n => n > 9 ? n - 9 : n) % 10 == 0;
}

static void Main(string[] args)
{
long[] given = new long[] {49927398716, 49927398717, 1234567812345678, 1234567812345670};
foreach (long num in given)
{
string valid = (luhn(num)) ? " is valid" : " is not valid";
Console.WriteLine(num + valid);
}

}
}
}

49927398716 is valid
49927398717 is not valid
1234567812345678 is not valid
1234567812345670 is valid


A solution without using LINQ, works for all versions of .NET.

using System;
namespace Luhn_Test
{
public static class Extensions
{
public static string Reverse(this string s )
{
char[] charArray = s.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}
}
class Program
{
public static bool Luhn(long x)
{
long s1=0;
long s2=0;
bool STATE=x%10!=0; // If it ends with zero, we want the order to be the other way around
x=long.Parse(x.ToString().Reverse());
while (x!=0)
{
s1+=STATE?x%10:0;
s2+=STATE?0:((x%10)*2>9)?(((x%10)*2/10)+((x%10)*2)%10):((x%10)*2);
STATE=!STATE; //Switch state
x/=10; //Cut the last digit and continue
}
return ((s1+s2)%10==0); //Check if it ends with zero, if so, return true, otherwise,false.
}
public static void Main(string[] args)
{
long[] ks = {1234567812345670, 49927398717, 1234567812345678 ,1234567812345670 };
foreach (long k in ks)
{
Console.WriteLine("{0} is {1} Valid.",k,Luhn(k)?"":"Not");
}
Start:
try {
Console.WriteLine("Enter your credit:");
long x=long.Parse(Console.ReadLine());
Console.WriteLine("{0} Valid.",Luhn(x)?"":"Not");
goto Start;
}
catch (FormatException)
{
goto Start;
}
}
}
}

1234567812345670 is Valid.
49927398717 is Not Valid.
1234567812345678 is Not Valid.
49927398716 is Valid.


A solution optimized for readability:

using System;
using System.Linq;

public class CreditCardLogic
{
static Func<char, int> charToInt = c => c - '0';

static Func<int, int> doubleDigit = n => (n * 2).ToString().Select(charToInt).Sum();

static Func<int, bool> isOddIndex = index => index % 2 == 0;

public static bool LuhnCheck(string creditCardNumber)
{
var checkSum = creditCardNumber
.Select(charToInt)
.Reverse()
.Select((digit, index) => isOddIndex(index) ? digit : doubleDigit(digit))
.Sum();

return checkSum % 10 == 0;
}
}


Extremely compact version uses Europa rtl library https://github.com/CodeAlkemist/Europa-rtl

using System;
using EuropaRTL.Utilities;

public static partial class Algoritmhs
{
public static bool CheckLuhn(long n)
{
int s1 = n.Shatter(true).Subset(2).Arithmetic('+');
int s2 = n.Shatter(true).Subset(1, -1, 2).ArithmeticRA('*', 2).ShatterAndSum().Arithmetic('+');
return (s1 + s2) % 10 == 0 ? true : false;
}
}
class Program
{
static void Main(string[] args)
{
long[] ll = {
49927398716,
49927398717,
1234567812345678,
1234567812345670
};
foreach (var item in ll)
{
item.ToString().WriteLine();
Algoritmhs.CheckLuhn(item).ToString().WriteLine();
}
Console.ReadKey();
}
}

49927398716
True
49927398717
False
1234567812345678
False
1234567812345670
False


## C++

#include <iostream>
using namespace std;

int toInt(const char c)
{
return c-'0';
}

int confirm( const char *id)
{
bool is_odd_dgt = true;
int s = 0;
const char *cp;

for(cp=id; *cp; cp++);
while(cp > id) {
--cp;
int k = toInt(*cp);
if (is_odd_dgt) {
s += k;
}
else {
s += (k!=9)? (2*k)%9 : 9;
}
is_odd_dgt = !is_odd_dgt;
}
return 0 == s%10;
}

int main( )
{
const char * t_cases[] = {
"49927398716",
"49927398717",
"1234567812345678",
"1234567812345670",
NULL,
};
for ( const char **cp = t_cases; *cp; cp++) {
cout << *cp << ": " << confirm(*cp) << endl;
}
return 0;
}


### C++11

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool luhn( const string& id)
{
static const int m[10]  = {0,2,4,6,8,1,3,5,7,9}; // mapping for rule 3
bool is_odd_dgt = false;
auto lambda = [&](int a, char c) {return a + ((is_odd_dgt = !is_odd_dgt) ? c-'0' : m[c-'0']);};
int s = std::accumulate(id.rbegin(), id.rend(), 0, lambda);
return 0 == s%10;
}

int main( )
{
auto t_cases = {"49927398716", "49927398717", "1234567812345678", "1234567812345670"};
auto print = [](const string & s) {cout << s << ": " << luhn(s) << endl;};
for_each(t_cases.begin(), t_cases.end(), print);
return 0;
}


It is also possible to achieve a compile-time version using metaprogramming.

#include <iostream>
#include <type_traits>

template<size_t I, int... Args>
struct find_impl;

template<int A, int... Args>
struct find_impl<0, A, Args...> {
using type = std::integral_constant<int, A>;
};

template<int A, int B, int... Args>
struct find_impl<0, A, B, Args...> {
using type = std::integral_constant<int, A>;
};

template<size_t I, int A, int B, int... Args>
struct find_impl<I, A, B, Args...> {
using type = typename find_impl<I-1, B, Args...>::type;
};

namespace detail {
template<typename, typename>
struct append_sequence
{};

template<typename T, typename... Ts>
struct append_sequence<T, std::tuple<Ts...>> {
using type = std::tuple<Ts..., T>;
};

template<typename... Ts>
struct reverse_sequence {
using type = std::tuple<>;
};

template<typename T, typename... Ts>
struct reverse_sequence<T, Ts...> {
using type = typename append_sequence<
T,
typename reverse_sequence<Ts...>::type
>::type;
};
}

template<size_t I>
using rule3 = typename find_impl<I, 0, 2, 4, 6, 8, 1, 3, 5, 7, 9>::type;

template<int A, char C, bool dgt>
struct calc
: std::integral_constant<int, A + C - '0'>
{};

template<int A, char C>
struct calc<A, C, false>
: std::integral_constant<int, A + rule3<C - '0'>::type::value>
{};

template<typename Acc, bool Dgt, char...>
struct luhn_impl;

template<typename Acc, bool Dgt, char A, char... Args>
struct luhn_impl<Acc, Dgt, A, Args...> {
using type = typename calc<Acc::value, A, Dgt>::type;
};

template<typename Acc, bool Dgt, char A, char B, char... Args>
struct luhn_impl<Acc, Dgt, A, B, Args...> {
using type =
typename luhn_impl<typename calc<Acc::value, A, Dgt>::type, !Dgt, B, Args...>::type;
};

template<typename>
struct luhn;

template<typename... Args>
struct luhn<std::tuple<Args...>> {
using type = typename luhn_impl<std::integral_constant<int, 0>, true, Args::value...>::type;
constexpr static bool result = (type::value % 10) == 0;
};

template<char... Args>
bool operator "" _luhn() {
return luhn<typename detail::reverse_sequence<std::integral_constant<char, Args>...>::type>::result;
}

int main() {
std::cout << std::boolalpha;
std::cout << 49927398716_luhn << std::endl;
std::cout << 49927398717_luhn << std::endl;
std::cout << 1234567812345678_luhn << std::endl;
std::cout << 1234567812345670_luhn << std::endl;
return 0;
}

true
false
false
true


## Caché ObjectScript

Class Utils.Check [ Abstract ]
{

ClassMethod Luhn(x As %String) As %Boolean
{
// https://www.simple-talk.com/sql/t-sql-programming/calculating-and-verifying-check-digits-in-t-sql/
SET x=$TRANSLATE(x," "), cd=$EXTRACT(x,*)
SET x=$REVERSE($EXTRACT(x,1,*-1)), t=0
FOR i=1:1:$LENGTH(x) { SET n=$EXTRACT(x,i)
IF i#2 SET n=n*2 IF $LENGTH(n)>1 SET n=$EXTRACT(n,1)+$EXTRACT(n,2) SET t=t+n } QUIT cd=((t*9)#10) } } Examples: USER>For { Read ccn Quit:ccn="" Write ": "_##class(Utils.Check).Luhn(ccn), ! } 49927398716: 1 49927398717: 0 1234567812345678: 0 1234567812345670: 1 USER> ## Ceylon shared void run() { value numbers = "49927398716 49927398717 1234567812345678 1234567812345670"; for(number in numbers.lines) { print("number passes? luhn(number)"); } } shared Boolean luhn(String number) { value digits = number .reversed .map(Character.string) .map(Integer.parse) .narrow<Integer>(); value s1 = sum { 0, *digits.by(2) }; value s2 = sum { 0, *digits .skip(1) .by(2) .map(curry(times<Integer>)(2)) .map((Integer element) => element / 10 + element % 10) }; return (s1 + s2) % 10 == 0; }  ## Clojure (defn luhn? [cc] (let [factors (cycle [1 2]) numbers (map #(Character/digit % 10) cc) sum (reduce + (map #(+ (quot % 10) (mod % 10)) (map * (reverse numbers) factors)))] (zero? (mod sum 10)))) (doseq [n ["49927398716" "49927398717" "1234567812345678" "1234567812345670"]] (println (luhn? n)))  ## CLU luhn = proc (num: string) returns (bool) signals (bad_format) total: int := 0 even: bool := true for i: int in int$from_to_by(string$size(num), 1, -1) do digit: int := int$parse(string$c2s(num[i])) resignal bad_format even := ~even if even then digit := 2 * digit if digit >= 10 then digit := digit//10 + 1 end end total := total + digit end return(total // 10 = 0) end luhn start_up = proc () po: stream := stream$primary_output()
tests: sequence[string] := sequence[string]$["49927398716", "49927398717", "1234567812345678", "1234567812345670"] for test: string in sequence[string]$elements(tests) do
stream$puts(po, test || ": ") if luhn(test) then stream$putl(po, "pass")
else stream$putl(po, "fail") end end end start_up Output: 49927398716: pass 49927398717: fail 1234567812345678: fail 1234567812345670: pass ## COBOL Works with: OpenCOBOL  IDENTIFICATION DIVISION. PROGRAM-ID. LUHNTEST. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. data division. WORKING-STORAGE SECTION. 01 inp-card. 03 inp-card-ch pic x(01) occurs 20 times. 01 ws-result pic 9(01). 88 pass-luhn-test value 0. PROCEDURE DIVISION. move "49927398716" to inp-card perform test-card move "49927398717" to inp-card perform test-card move "1234567812345678" to inp-card perform test-card move "1234567812345670" to inp-card perform test-card stop run . test-card. call "LUHN" using inp-card, ws-result if pass-luhn-test display "input=" inp-card "pass" else display "input=" inp-card "fail" . END PROGRAM LUHNTEST. IDENTIFICATION DIVISION. PROGRAM-ID. LUHN. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. DATA DIVISION. WORKING-STORAGE SECTION. 01 maxlen pic 9(02) comp value 16. 01 inplen pic 9(02) comp value 0. 01 i pic 9(02) comp value 0. 01 j pic 9(02) comp value 0. 01 l pic 9(02) comp value 0. 01 dw pic 9(02) comp value 0. 01 ws-total pic 9(03) comp value 0. 01 ws-prod pic 99. 01 filler redefines ws-prod. 03 ws-prod-tens pic 9. 03 ws-prod-units pic 9. 01 ws-card. 03 filler occurs 16 times depending on maxlen. 05 ws-card-ch pic x(01). 05 ws-card-digit redefines ws-card-ch pic 9(01). LINKAGE SECTION. 01 inp-card. 03 inp-card-ch pic x(01) occurs 20 times. 01 ws-result pic 9(01). 88 pass-luhn-test value 0. PROCEDURE DIVISION using inp-card, ws-result. perform varying i from 1 by +1 until i > maxlen or inp-card-ch (i) = space end-perform compute l = i - 1 compute inplen = l perform varying j from 1 by +1 until j > inplen if l < 1 move "0" to ws-card-ch (j) else move inp-card-ch (l) to ws-card-ch (j) compute l = l - 1 end-if end-perform move 0 to ws-total perform varying i from 1 by +1 until i > inplen compute dw = 2 - (i - 2 * function integer (i / 2)) compute ws-prod = ws-card-digit (i) * dw compute ws-total = ws-total + ws-prod-tens + ws-prod-units end-perform compute ws-result = ws-total - 10 * function integer (ws-total / 10) goback . END PROGRAM LUHN.  Output: input=49927398716 pass input=49927398717 fail input=1234567812345678 fail input=1234567812345670 pass  ## Comal 0010 FUNC luhn(s$) CLOSED
0020   total#:=0
0030   even#:=TRUE
0040   FOR i#:=LEN(s$) TO 1 STEP -1 DO 0050 digit#:=VAL(s$(i#))
0060     even#:=NOT even#
0070     IF even# THEN digit#:=(2*digit#) DIV 10+(2*digit#) MOD 10
0080     total#:+digit#
0090   ENDFOR i#
0100   RETURN total# MOD 10=0
0110 ENDFUNC luhn
0120 //
0130 PROC test(s$) 0140 PRINT s$,": ",
0150   IF luhn(s$) THEN 0160 PRINT "pass" 0170 ELSE 0180 PRINT "fail" 0190 ENDIF 0200 ENDPROC test 0210 // 0220 test("49927398716") 0230 test("49927398717") 0240 test("1234567812345678") 0250 test("1234567812345670") 0260 END  Output: 49927398716: pass 49927398717: fail 1234567812345678: fail 1234567812345670: pass ## Common Lisp (defun luhn (n) (labels ((sum-digits (n) (if (> n 9) (- n 9) n))) (let ((n* (reverse n)) (l (length n))) (let ((s1 (loop for i from 0 below l by 2 summing (digit-char-p (aref n* i)))) (s2 (loop for i from 1 below l by 2 summing (sum-digits (* 2 (digit-char-p (aref n* i))))))) (zerop (mod (+ s1 s2) 10))))))  Another version, using Maciej Pasternacki's reader macros for function composition and currying in the curly package: (require :curly) (use-package :curly) (enable-curly-syntax) (defun luhn (seq) (labels ((sum-digits (n) (if (> n 9) (- n 9) n))) (funcall {zerop (mod * 10) (apply #'+) (mapcar #'sum-digits) (mapcar #'* '#1=(1 2 . #1#)) (map 'list #'digit-char-p) reverse} seq)))  ## Cowgol include "cowgol.coh"; # Given a string containing the digits of a credit card number, # see if it passes the Luhn test. sub luhn(card: [uint8]): (ok: uint8) is # Scan ahead to last digit, counting digits var n: uint8 := 0; while [card] != 0 loop n := n + 1; card := @next card; end loop; var sum: uint8 := 0; while n > 0 loop # odd digit is simply added card := @prev card; n := n - 1; sum := sum + ([card] - '0'); # if uneven amount of digits, stop if n == 0 then break; end if; # even digit card := @prev card; n := n - 1; var digit := [card] - '0'; # it is good to avoid unnecessary multiplication/ # division, since 8-bit processors and microcontrollers # don't tend to have that in hardware if digit < 5 then sum := sum + digit + digit; else digit := digit - 5; sum := sum + digit + digit + 1; end if; end loop; # there is no boolean type, comparisons only work # in conditionals; this is the only way to return # a status if sum % 10 == 0 then ok := 1; else ok := 0; end if; end sub; # Test and print sub test(card: [uint8]) is var msg: [uint8][] := {"Fail", "Pass"}; print(card); print(": "); print(msg[luhn(card)]); print_nl(); end sub; test("49927398716"); test("49927398717"); test("1234567812345678"); test("1234567812345670"); Output: 49927398716: Pass 49927398717: Fail 1234567812345678: Fail 1234567812345670: Pass ## Crystal def luhn_valid?(n) # Card values can be numbers or strings d2sum = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] sum, n = 0, n.to_u64 while n > 0; sum += n%10; n //= 10; sum += d2sum[n%10]; n //= 10 end sum % 10 == 0 end cards = [49927398716, "49927398717", 1234567812345678, "1234567812345670"] cards.each{ |i| puts "#{i}: #{luhn_valid?(i)}" }  Output: 49927398716: true 49927398717: false 1234567812345678: false 1234567812345670: true ## D ### Functional Version Translation of: Haskell import std.algorithm, std.range, std.string; enum luhnTest = (in string n) pure /*nothrow*/ @safe /*@nogc*/ => retro(n) .zip(only(1, 2).cycle) .map!(p => (p[0] - '0') * p[1]) .map!(d => d / 10 + d % 10) .sum % 10 == 0; void main() { assert("49927398716 49927398717 1234567812345678 1234567812345670" .split.map!luhnTest.equal([true, false, false, true])); }  ### More Imperative Version Translation of: C import std.algorithm; bool luhnTest(in string num) @safe pure nothrow @nogc { uint sum; foreach_reverse (immutable i, immutable n; num) { immutable uint ord = n - '\u0030'; sum += ((num.length - i) & 1) ? ord : ord / 5 + (2 * ord) % 10; } return sum % 10 == 0; } void main() { immutable data = ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]; assert(data.map!luhnTest.equal([true, false, false, true])); }  ### Stronger Statically Typed Version This version uses more precise types. Translation of: SPARK import std.stdio; struct Interval(T) { immutable T a, b; this(in T a_, in T b_) pure nothrow @nogc { this.a = a_; this.b = b_; } bool opBinaryRight(string op="in")(in T x) const pure nothrow @nogc { return x >= a && x <= b; } pure nothrow @safe @nogc const invariant { assert(a <= b); } } Interval!T interval(T)(in T a, in T b) pure nothrow @nogc { return Interval!T(a, b); } bool luhnTest(in string num) pure nothrow @nogc in { assert(num.length <= 20); } body { int sum = 0; bool od = true; bool ok = true; immutable int numLen = num.length; foreach_reverse (immutable p; 0 .. numLen) { immutable int i = num[p] - '0'; if (i !in interval(0, 9)) { ok = false; break; } immutable int x = ((i * 2) % 10) + (i / 5); assert((numLen - p) in interval(0, 19)); assert(sum in interval(0, (numLen - p) * 10)); assert(i in interval(0, 9)); assert(x in interval(0, 9)); sum += od ? i : x; od = !od; } return ok && (sum % 10) == 0; } void main() { foreach (immutable n; ["49927398716", "49927398717", "1234567812345678", "1234567812345670", "123456781234567D"]) writefln("%s is %svalid", n, luhnTest(n) ? "" : "not "); }  ## Delphi Works with: Delphi version 6.0 Uses an array to handle the situation where multiply a term by 2, creates a two digit number. The array automatically handles adding each digit of the resulting two digit number. Also, avoids reversing the number by traversing the array backwards {Test data arrays} const Num1: array [0..10] of byte = (4,9,9,2,7,3,9,8,7,1,6); const Num2: array [0..10] of byte = (4,9,9,2,7,3,9,8,7,1,7); const Num3: array [0..15] of byte = (1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8); const Num4: array [0..15] of byte = (1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,0); {Simplifies cases where we have to sum a two digit number} const DigitSum: array [0..18] of byte = (0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9); function ValidateCreditCard(CardNum: array of byte): boolean; {Validate a Credit Card number} var I,J,Len,Sum,Sum1,Sum2: integer; var Rev: array of byte; begin Sum1:=0; Sum2:=0; Len:=High(CardNum); for I:=Len downto 0 do if ((I-Len) and 1)=0 then Sum1:=Sum1 + CardNum[I] else Sum2:=Sum2 + DigitSum[CardNum[I]*2]; Sum:=Sum1+Sum2; Result:=(Sum mod 10)=0; end; function CardNumberToStr(CardNum: array of byte): string; {Convert card number to a string} var I: integer; begin Result:=''; for I:=0 to High(CardNum) do Result:=Result+IntToStr(CardNum[I]); end; procedure TestDisplayNumber(Memo: TMemo; Num: array of byte); {Test a credit card number and display results} var S: string; begin S:=CardNumberToStr(Num); if ValidateCreditCard(Num) then S:=S+': Valid' else S:=S+': Not Valid'; Memo.Lines.Add(S); end; procedure TestCreditCardNums(Memo: TMemo); {Test all credit card numbers} begin TestDisplayNumber(Memo,Num1); TestDisplayNumber(Memo,Num2); TestDisplayNumber(Memo,Num3); TestDisplayNumber(Memo,Num4); end;  Output: 49927398716: Valid 49927398717: Not Valid 1234567812345678: Not Valid 1234567812345670: Valid  ## Draco proc nonrec luhn(*char num) bool: [10] byte map = (0, 2, 4, 6, 8, 1, 3, 5, 7, 9); byte total, digit; *char start; bool even; start := num; total := 0; even := true; while num* /= '\e' do num := num + 1 od; while num := num - 1; num >= start do digit := num* - '0'; even := not even; if even then digit := map[digit] fi; total := total + digit od; total % 10 = 0 corp proc nonrec test(*char num) void: writeln(num, ": ", if luhn(num) then "pass" else "fail" fi) corp proc nonrec main() void: test("49927398716"); test("49927398717"); test("1234567812345678"); test("1234567812345670") corp Output: 49927398716: pass 49927398717: fail 1234567812345678: fail 1234567812345670: pass ## EasyLang func luhn cc$ .
for i = len cc$downto 1 odd = 1 - odd dig = number substr cc$ i 1
if odd = 0
dig = 2 * dig
if dig >= 10
dig -= 9
.
.
sum += dig
.
return if sum mod 10 = 0
.
cc$[] = [ "49927398716" "49927398717" "1234567812345678" "1234567812345670" ] for cc$ in cc$[] write cc$ & " "
if luhn cc$= 1 print "is valid" else print "is not valid" . . Output: 49927398716 is valid 49927398717 is not valid 1234567812345678 is not valid 1234567812345670 is valid  ## EchoLisp ;; value for 'even' numbers (define (even-val n) (if (> n 4) (+ n n -9) (+ n n))) ;;Luhn test ;; input : a string of decimal digits ;; output #t or #f (define (valid nums (odd #f )) (let ((nums (map string->number (reverse (string->list nums))))) (= 0 (modulo (for/sum ((n nums)) (set! odd (not odd)) (if odd n (even-val n))) 10)))) (valid "49927398716") → #t (valid "1234567812345670") → #t (valid "1234567812345678") → #f (valid "49927398717") → #f  ## Elixir defmodule Luhn do def valid?(cc) when is_binary(cc), do: String.to_integer(cc) |> valid? def valid?(cc) when is_integer(cc) do 0 == Integer.digits(cc) |> Enum.reverse |> Enum.chunk(2, 2, [0]) |> Enum.reduce(0, fn([odd, even], sum) -> Enum.sum([sum, odd | Integer.digits(even*2)]) end) |> rem(10) end end numbers = ~w(49927398716 49927398717 1234567812345678 1234567812345670) for n <- numbers, do: IO.puts "#{n}: #{Luhn.valid?(n)}"  Output: 49927398716: true 49927398717: false 1234567812345678: false 1234567812345670: true  ## Emacs Lisp Library: seq.el (require 'seq) (defun luhn (str) "Check if STR is a valid credit card number using the Luhn algorithm." (if (string-match-p "[^0-9]" str) (error "String contains invalid character") (let ((digit-list (reverse (mapcar #'(lambda (x) (- x 48)) (string-to-list str))))) (zerop (mod (apply #'+ (seq-map-indexed (lambda (elt idx) (if (not (zerop (% idx 2))) (if (> (* 2 elt) 9) (- (* 2 elt) 9) (* 2 elt)) elt)) digit-list)) 10))))) (mapcar #'luhn '("49927398716" "49927398717" "1234567812345678" "1234567812345670"))  Output: (t nil nil t)  ## Erlang -module(luhn_test). -export( [credit_card/1, task/0] ). luhn_sum([Odd, Even |Rest]) when Even >= 5 -> Odd + 2 * Even - 10 + 1 + luhn_sum(Rest); luhn_sum([Odd, Even |Rest]) -> Odd + 2 * Even + luhn_sum(Rest); luhn_sum([Odd]) -> Odd; luhn_sum([]) -> 0. check( Sum ) when (Sum rem 10) =:= 0 -> valid; check( _Sum ) -> invalid. credit_card(Digits) -> check(luhn_sum(lists:map(fun(D) -> D-$0 end, lists:reverse(Digits)))).

task() ->
Numbers = ["49927398716", "49927398717", "1234567812345678", "1234567812345670"],
[io:fwrite("~s: ~p~n", [X, credit_card(X)]) || X <- Numbers].

Output:
16> luhn_test:task().
49927398716: valid
49927398717: invalid
1234567812345678: invalid
1234567812345670: valid


## Euphoria

Translation of: C
function luhn(sequence cc)
integer isOdd, oddSum, evenSum, digit
isOdd = 1
oddSum = 0
evenSum = 0
for i = length(cc) to 1 by -1 do
digit = cc[i] - '0'
if isOdd then
oddSum += digit
else
evenSum += floor(digit / 5) + remainder(2 * digit, 10)
end if
isOdd = not isOdd
end for
return not remainder(oddSum + evenSum, 10)
end function

constant cc_numbers = {
"49927398716",
"49927398717",
"1234567812345678",
"1234567812345670"
}

for i = 1 to length(cc_numbers) do
printf(1,"%s = %d\n", {cc_numbers[i], luhn(cc_numbers[i])})
end for
Output:
49927398716 = 1
49927398717 = 0
1234567812345678 = 0
1234567812345670 = 1

## Excel

### LAMBDA

Binding the name luhnChecked to the following lambda expression in the Name Manager of the Excel WorkBook:

luhnChecked
=LAMBDA(s,
LET(
ns, REVERSECOLS(VALUE(CHARSROW(s))),
ixs, SEQUENCE(1, COLUMNS(ns), 1, 1),

0 = MOD(SUM(
FILTER(ns, 0 <> MOD(ixs, 2))
) + (
LAMBDA(n,
DIGITSUM(
CONCAT(TEXT(2 * n, "0"))
)
)(
FILTER(ns, 0 = MOD(ixs, 2))
)
),
10
)
)
)


and also assuming the following generic bindings in the Name Manager for the WorkBook:

CHARSROW
=LAMBDA(s,
MID(s,
SEQUENCE(1, LEN(s), 1, 1),
1
)
)

DIGITSUM
=LAMBDA(s,
SUM(VALUE(
MID(s,
SEQUENCE(LEN(s), 1, 1, 1),
1
)
))
)

REVERSECOLS
=LAMBDA(xs,
LET(
n, COLUMNS(xs),

SORTBY(
xs,
SEQUENCE(1, n, n, -1)
)
)
)

Output:
 =luhnChecked(A2) fx A B 1 Digit strings Luhn result 2 49927398716 TRUE 3 49927398717 FALSE 4 1234567812345678 FALSE 5 1234567812345670 TRUE

## F#

let luhn (s:string) =
let rec g r c = function
| 0 -> r
| i ->
let d = ((int s.[i - 1]) - 48) <<< c
g (r + if d < 10 then d else d - 9) (1 - c) (i - 1)
(g 0 0 s.Length) % 10 = 0


## Factor

Works with: Factor version 0.98
USING: kernel math math.parser math.order math.ranges sequences ;
IN: luhn

: reversed-digits ( n -- list )
{ } swap
[ dup 0 > ]
[ 10 /mod  swapd suffix  swap ]
while drop ;

: luhn-digit  ( n -- n )
reversed-digits dup length <iota> [
2dup swap nth
swap odd? [ 2 *  10 /mod + ] when
] map sum 10 mod
nip ;

: luhn? ( n -- ? )
luhn-digit 0 = ;

Output:
( scratchpad ) 49927398716 luhn? .
t
( scratchpad ) 49927398717 luhn? .
f
( scratchpad ) 1234567812345678 luhn? .
f
( scratchpad ) 1234567812345670 luhn? .
t


## Forth

: luhn ( addr len -- ? )
0 >r over +             ( R: sum )
begin  1- 2dup <=
while                   \ odd
dup c@ [char] 0 -
r> + >r
1- 2dup <=
while                   \ even
dup c@ [char] 0 -
2* 10 /mod +     \ even digits doubled, split, and summed
r> + >r
repeat then
2drop  r> 10 mod 0= ;

s" 49927398716"      luhn .   \ -1
s" 49927398717"      luhn .   \ 0
s" 1234567812345678" luhn .   \ 0
s" 1234567812345670" luhn .   \ -1


## Fortran

program luhn
implicit none
integer              :: nargs
character(len=20)    :: arg
integer              :: alen, i, dr
integer, allocatable :: number(:)
integer, parameter   :: drmap(0:9) = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]

! Get number
nargs = command_argument_count()
if (nargs /= 1) then
stop
end if
call get_command_argument(1, arg, alen)
allocate(number(alen))
do i=1, alen
number(alen-i+1) = iachar(arg(i:i)) - iachar('0')
end do

! Calculate number
dr = 0
do i=1, alen
dr = dr + merge(drmap(number(i)), number(i), mod(i,2) == 0)
end do

if (mod(dr,10) == 0) then
write(*,'(a,i0)') arg(1:alen)//' is valid'
else
write(*,'(a,i0)') arg(1:alen)//' is not valid'
end if
end program luhn

! Results:
! 49927398716 is valid
! 49927398717 is not valid
! 1234567812345678 is not valid
! 1234567812345670 is valid


## FreeBASIC

' version 05-07-2015
' compile with: fbc -s console

#Ifndef TRUE        ' define true and false for older freebasic versions
#Define FALSE 0
#Define TRUE Not FALSE
#EndIf

Function luhntest(cardnr As String) As Integer

cardnr = Trim(cardnr) ' we don't want spaces
Dim As String reverse_nr = cardnr
Dim As Integer i, j, s1, s2, l = Len(cardnr) - 1

' reverse string
For i = 0 To l
reverse_nr[i] = cardnr[l - i]
Next
' sum odd numbers
For i = 0 To l Step 2
s1 = s1 + (reverse_nr[i] - Asc("0"))
Next
' sum even numbers
For i = 1 To l Step 2
j = reverse_nr[i] - Asc("0")
j = j * 2
If j > 9 Then j = j Mod 10 + 1
s2 = s2 + j
Next

If (s1 + s2) Mod 10 = 0 Then
Return TRUE
Else
Return FALSE
End If

End Function

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

Dim As String input_nr(1 To ...) = {"49927398716", "49927398717",_
"1234567812345678", "1234567812345670"}
Dim As Integer a

Print  "Task test number 49927398716 should be TRUE, report back as ";
Print IIf(luhntest("49927398716" ) = TRUE, "TRUE", "FALSE")
Print : Print

Print "test card nr:"
For a = 1 To UBound(input_nr)
Print input_nr(a); " = "; IIf(luhntest(input_nr(a)) = TRUE, "TRUE", "FALSE")
Next

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
Output:
Task test number 49927398716 should be TRUE, report back as TRUE

test card nr:
49927398716 = TRUE
49927398717 = FALSE
1234567812345678 = FALSE
1234567812345670 = TRUE

## Free Pascal

see also: Pascal

program luhn;

function lunh(arg: string): boolean;
var
i, sum: integer;
temp: byte;
begin
sum := 0;
for i:= length(arg) downto 1 do begin  // Run the characters backwards
temp := byte(arg[i])-48;             // Convert from ASCII to byte
if (length(arg)-i) mod 2 = 0
then sum := sum + temp             // Odd characters just add
else if temp < 5
then sum := sum + 2*temp        // Even characters add double
else sum := sum + (2*temp)-9;   // or sum the digits of the doubling
end;
result := sum mod 10 = 0;              // Return true if sum ends in a 0
end;

begin
writeln('     49927398716: ', lunh('49927398716'));
writeln('     49927398717: ', lunh('49927398717'));
writeln('1234567812345678: ', lunh('1234567812345678'));
writeln('1234567812345670: ', lunh('1234567812345670'));
end.

Output:
     49927398716: TRUE
49927398717: FALSE
1234567812345678: FALSE
1234567812345670: TRUE

## FunL

def luhn_checksum( card_number ) =
def digits_of( n ) = [int(d) | d <- n.toString()]

digits = digits_of( card_number ).reverse()
odd_digits = digits(0:digits.length():2)
even_digits = digits(1:digits.length():2)
(sum( odd_digits ) + sum( sum(digits_of(d*2)) | d <- even_digits )) mod 10

def is_luhn_valid( card_number ) = luhn_checksum( card_number ) == 0

for n <- [49927398716, 49927398717, 1234567812345678, 1234567812345670]
println( n + ' is ' + (if is_luhn_valid(n) then 'valid' else 'invalid') )
Output:
49927398716 is valid
49927398717 is invalid
1234567812345678 is invalid
1234567812345670 is valid


## FutureBasic

include "NSLog.incl"

local fn LuhnCheck( cardStr as CFStringRef ) as BOOL
NSInteger  i, j, count, s1 = 0, s2 = 0
BOOL       result = NO

// Build array of individual numbers in credit card string
NSUInteger strLength = len(cardStr)
CFMUtableArrayRef mutArr = fn MutableArrayWithCapacity(strLength)
for i = 0 to strLength - 1
CFStringRef tempStr = fn StringWithFormat( @"%C", fn StringCharacterAtIndex( cardStr, i ) )
MutableArrayInsertObjectAtIndex( mutArr, tempStr, i )
next

// Reverse the number array
CFArrayRef reversedArray = fn EnumeratorAllObjects( fn ArrayReverseObjectEnumerator( mutArr ) )

// Get number of array elements
count = len(reversedArray)

// Handle odd numbers
for i = 0 to count - 1 step 2
s1 = s1 + fn StringIntegerValue( reversedArray[i] )
next

// Hnadle even numbers
for i = 1 to count - 1 step 2
j = fn StringIntegerValue( reversedArray[i] )
j = j * 2
if j > 9 then j = j mod 10 + 1
s2 = s2 + j
next

if (s1 + s2) mod 10 = 0 then result = YES else result = NO
end fn = result

NSLogClear
if fn LuhnCheck( @"49927398716" ) then NSLog (@"%@ is valid.", @"49927398716" ) else NSLog (@"%@ is not valid.", @"49927398716" )
if fn LuhnCheck( @"49927398717" ) then NSLog (@"%@ is valid.", @"49927398717" ) else NSLog (@"%@ is not valid.", @"49927398717" )
if fn LuhnCheck( @"1234567812345678" ) then NSLog (@"%@ is valid.", @"1234567812345678" ) else NSLog (@"%@ is not valid.", @"1234567812345678" )
if fn LuhnCheck( @"1234567812345670" ) then NSLog (@"%@ is valid.", @"1234567812345670" ) else NSLog (@"%@ is not valid.", @"1234567812345670" )

HandleEvents
Output:
49927398716 is valid.
49927398717 is not valid.
1234567812345678 is not valid.
1234567812345670 is valid.


## Gambas

Public Sub Main()
Dim sTrial As String[] = ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]
Dim sRev As String
Dim siCount, siOdd, siEven, siHold, siQty As Short

For siQty = 0 To sTrial.Max

siOdd = 0
siEven = 0
sRev = ""

For siCount = Len(sTrial[siQty]) DownTo 1
sRev &= Mid(sTrial[siQty], siCount, 1)
Next

For siCount = 1 To Len(sRev)
If Odd(siCount) Then siOdd += Val(Mid(sRev, siCount, 1))
If Even(siCount) Then
siHold = Val(Mid(sRev, siCount, 1)) * 2
If siHold > 9 Then
siEven += Val(Mid(Str(siHold), 1, 1)) + Val(Mid(Str(siHold), 2, 1))
Else
siEven += Val(Mid(sRev, siCount, 1)) * 2
End If
End If
Next

sRev = Str(siOdd + siEven)
If sRev Ends "0" Then
Print sTrial[siQty] & " is a valid number"
Else
Print sTrial[siQty] & " is NOT a valid number"
End If
Next

End

Output:

49927398716 is a valid number
49927398717 is NOT a valid number
1234567812345678 is NOT a valid number
1234567812345670 is a valid number


## GAP

IsLuhn := function(n)
local c, d, i, j, r;
d := "0123456789";
j := 1;
r := 0;
for c in Reversed(String(n)) do
i := Position(d, c);
if i = fail then
continue;
fi;
i := j*(i - 1);
r := r + QuoInt(i, 10) + RemInt(i, 10);
j := 3 - j;
od;
return RemInt(r, 10) = 0;
end;

List([49927398716, 49927398717, 1234567812345678, 1234567812345670], IsLuhn);
# [ true, false, false, true ]

# Will also work on strings, and will skip non-digits
IsLuhn("4-992-739-871-6");
# true


## Go

package main

import (
"fmt"
"strings"
)

const input = 49927398716
49927398717
1234567812345678
1234567812345670

var t = [...]int{0, 2, 4, 6, 8, 1, 3, 5, 7, 9}

func luhn(s string) bool {
odd := len(s) & 1
var sum int
for i, c := range s {
if c < '0' || c > '9' {
return false
}
if i&1 == odd {
sum += t[c-'0']
} else {
sum += int(c - '0')
}
}
return sum%10 == 0
}

func main() {
for _, s := range strings.Split(input, "\n") {
fmt.Println(s, luhn(s))
}
}

Output:
49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true


## Groovy

def checkLuhn(number) {
int total
(number as String).reverse().eachWithIndex { ch, index ->
def digit = Integer.parseInt(ch)
total += (index % 2 ==0) ? digit : [0, 2, 4, 6, 8, 1, 3, 5, 7, 9][digit]
}
total % 10 == 0
}


Testing the function:

def verifyLuhn(number, expected) {
println "Checking: $number (${checkLuhn(number)})"
assert expected == checkLuhn(number)
}

[49927398716: true, 49927398717: false, 1234567812345678: false, 1234567812345670: true].each { number, expected ->
verifyLuhn number, expected
}

Output:
Checking: 49927398716 (true)
Checking: 49927398717 (false)
Checking: 1234567812345678 (false)
Checking: 1234567812345670 (true)

## Haskell

import Data.Char (digitToInt)
luhn = (0 ==) . (mod 10) . sum . map (uncurry (+) . (divMod 10)) .
zipWith (*) (cycle [1,2]) . map digitToInt . reverse

Output:
map luhn ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]
[True,False,False,True]


Or, aiming for a legible relationship with the stages shown in the task description:

import Data.Char (digitToInt)
import Data.List (transpose)
import Data.List.Split (chunksOf)

luhn :: String -> Bool
luhn x = 0 == rem (s1 + s2) 10
where
stringInts = fmap digitToInt
[odds, evens] =
(transpose . chunksOf 2)
(stringInts $reverse x) s1 = sum odds s2 = sum$ sum . stringInts . show . (2 *) <$> evens main :: IO () main = mapM_ (print . ((,) <*> luhn)) [ "49927398716", "49927398717", "1234567812345678", "1234567812345670" ]  Output: ("49927398716",True) ("49927398717",False) ("1234567812345678",False) ("1234567812345670",True) ## HicEst CHARACTER numbers="49927398716 49927398717 1234567812345678 1234567812345670 " DO nr = 1, 4 EDIT(Text=numbers, ITeM=nr, Parse=number) sum_odds = 0 sum_even = 0 DO i = LEN(number), 1, -2 sum_odds = sum_odds + ICHAR(number(i)) - 48 IF(i > 1) THEN even2 = 2 * (ICHAR(number(i-1)) - 48) sum_even = sum_even + MOD(even2, 10) + INT(even2/10) ENDIF ENDDO valid = (0 == MOD(sum_odds + sum_even, 10)) WRITE() number, " is ", "invalid"(1 + 2*valid:) ENDDO 49927398716 is valid 49927398717 is invalid 1234567812345678 is invalid 1234567812345670 is valid ## Icon and Unicon We use map to pre-compute the sum of doubled digits. procedure main(aL) every write(i := !aL ," - ", ((\isluhn10(i),"valid")|"invalid") \ 1) end procedure isluhn10(i) #: isluhn10(i) returns i (if i passes luhn10) or fails local sum sum :=0 reverse(integer(i)) ? while not pos(0) do { sum +:= move(1) sum +:= map(move(1),"0123456789","0246813579") } return (sum % 10 = 0,i) end  Output: # luhn10 49927398716 49927398717 1234567812345678 1234567812345670 49927398716 - valid 49927398717 - invalid 1234567812345678 - invalid 1234567812345670 - valid  ## J We can treat the odd digits the same as even digits, except that they are not doubled. Also, we do not need the intermediate sums. luhn=: 0 = 10 (| +/@,) 10 #.inv 1 2 *&|: _2 "."0\ |.  Example use:  luhn&> '49927398716';'49927398717';'1234567812345678';'1234567812345670' 1 0 0 1  Interpreting that example: In J, 1 is true, 0 is false, so the first and last provided digit sequences were valid and the middle two were not. ## Java public class Luhn { public static void main(String[] args) { System.out.println(luhnTest("49927398716")); System.out.println(luhnTest("49927398717")); System.out.println(luhnTest("1234567812345678")); System.out.println(luhnTest("1234567812345670")); } public static boolean luhnTest(String number){ int s1 = 0, s2 = 0; String reverse = new StringBuffer(number).reverse().toString(); for(int i = 0 ;i < reverse.length();i++){ int digit = Character.digit(reverse.charAt(i), 10); if(i % 2 == 0){//this is for odd digits, they are 1-indexed in the algorithm s1 += digit; }else{//add 2 * digit for 0-4, add 2 * digit - 9 for 5-9 s2 += 2 * digit; if(digit >= 5){ s2 -= 9; } } } return (s1 + s2) % 10 == 0; } }  Output: true false false true ## Java Long type version public class Luhn { public static void main(String[] args) { System.out.println(luhnTest(49927398716L)); System.out.println(luhnTest(499273987163L)); System.out.println(luhnTest(1234567L)); System.out.println(luhnTest(0L)); } public static boolean luhnTest(Long digits) { int s1 = 0, s2 = 0; //Use an alternator for separate odd/even processing boolean alternator = true; //Confine digit numbers to 8 - 19 per ISO if (digits < 1e7 || digits >= 1e19) return false; for ( int i = 0; digits > 0; ++i) { Long oneDigit = digits % 10; if (alternator) { s1 += oneDigit.intValue(); } else { oneDigit *= 2; s2 += oneDigit > 9 ? oneDigit.intValue() - 9: oneDigit.intValue(); } digits /= 10; alternator = !alternator; } return (s1 + s2) % 10 == 0 ? true : false; } }  Output: true false false false ## JavaScript Using prototype. mod10check = function(cc) { return$A(cc).reverse().map(Number).inject(0, function(s, d, i) {
return s + (i % 2 == 1 ? (d == 9 ? 9 : (d * 2) % 9) : d);
}) % 10 == 0;
};
['49927398716','49927398717','1234567812345678','1234567812345670'].each(function(i){alert(mod10check(i))});


Without any library.

var LuhnCheck = (function()
{
var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
return function(str)
{
var counter = 0;
var incNum;
var odd = false;
var temp = String(str).replace(/[^\d]/g, "");
if ( temp.length == 0)
return false;
for (var i = temp.length-1; i >= 0; --i)
{
incNum = parseInt(temp.charAt(i), 10);
counter += (odd = !odd)? incNum : luhnArr[incNum];
}
return (counter%10 == 0);
}
})();


Highly compressed version.

var luhn10 = function(a,b,c,d,e) {
for(d = +a[b = a.length-1], e=0; b--;)
c = +a[b], d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;
return !(d%10)
};

// returns true
luhn10('4111111111111111')

// returns false
luhn10('4111111111111112')


Naive implementation

const lunhCheck = (str) => {
const sumDigit = (c) => (c < 10) ? c :
sumDigit( Math.trunc(c / 10) + (c % 10));

return str.split('').reverse()
.map(Number)
.map((c, i) => i % 2 !== 0 ? sumDigit(c * 2) : c)
.reduce((acc,v) => acc + v) % 10 === 0;
};

lunhCheck('49927398716'); // returns true
lunhCheck('49927398717'); // returns false
lunhCheck('1234567812345678'); // returns false
lunhCheck('1234567812345670'); // returns true


## jq

Works with: jq version 1.4 or later

Works with gojq, the Go implementation of jq

For the specific task defined here, both jq (version 1.4 or later) and gojq should suffice, but for very large integers (greater than 2^53), either gojq or a version of the C implementation of jq with support for very large external integers would be required.

def luhn:
def odds: . as $in | reduce range(0; length) as$i
([]; if ($i % 2) == 0 then . + [$in[$i]] else . end); def evens: . as$in | reduce range(1; length) as $i ([]; if ($i % 2) == 1 then . + [$in[$i]] else . end);
def digits: map([.]|implode|tonumber);
def sumdigits: tostring | explode | digits | add;

49927398716
49927398717
1234567812345678
1234567812345670
!
Pass
Fail
Fail
Pass


let even = $0.offset % 2 == 0 return even ? digit : digit == 9 ? 9 : digit * 2 % 9 }).reduce(0, +) % 10 == 0 } luhn("49927398716") // true luhn("49927398717") // false ## Tcl Based on an algorithmic encoding for the test on Wikipedia. package require Tcl 8.5 proc luhn digitString { if {[regexp {[^0-9]}$digitString]} {error "not a number"}
set sum 0
set flip 1
foreach ch [lreverse [split $digitString {}]] { incr sum [lindex { {0 1 2 3 4 5 6 7 8 9} {0 2 4 6 8 1 3 5 7 9} } [expr {[incr flip] & 1}]$ch]
}
return [expr {($sum % 10) == 0}] } Driver: foreach testNumber { 49927398716 49927398717 1234567812345678 1234567812345670 } { puts [format "%s is %s"$testNumber \
[lindex {"NOT valid" "valid"} [luhn $testNumber]]] } Output: 49927398716 is valid 49927398717 is NOT valid 1234567812345678 is NOT valid 1234567812345670 is valid  ## Terraform variable number { type = "string" } locals { digits = reverse(split("", var.number)) count = length(local.digits) odds = [for i in range(local.count): local.digits[i] if i%2==0] evens = [for i in range(local.count): local.digits[i] if i%2==1] s1 = length(flatten([for d in local.odds: range(d)])) doubles = [for d in local.evens: d * 2] partials = [for d in local.doubles: d < 10 ? d : floor(d/10)+d%10] s2 = length(flatten([for p in local.partials: range(p)])) check = (local.s1 + local.s2) % 10 } output "valid" { value = local.check == 0 } Output: $ terraform apply
var.number
Enter a value: 49927398716

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

valid = true
$TF_VAR_number=49927398717 terraform apply >/dev/null; terraform output valid false$ TF_VAR_number=1234567812345678 terraform apply >/dev/null; terraform output valid
false
$TF_VAR_number=1234567812345670 terraform apply >/dev/null; terraform output valid true ## TI-83 BASIC PROGRAM:LUHN :Disp "ENTER NUMBER" :Input Str1 :0→S :0→E :For(I,length(Str1),1,-1) :inString("0123456789",sub(Str1,I,1))–1→X :If X<0 :Goto BA :If E≠0 :Then :2X→X :If X>9 :X–9→X :End :X+S→S :not(E)→E :End :If fPart(S/10)=0 :Then :Disp "GOOD CARD" :Else :Lbl BA :Disp "BAD CARD" :End ## Transact-SQL CREATE FUNCTION dbo._CreditCardNumCheck( @strCCNum VarChar(40) ) RETURNS VarChar(7) AS BEGIN DECLARE @string VarChar(40) = REVERSE(@strCCNum); -- usage: set once, never changed DECLARE @strS2Values VarChar(10) = '0246813579'; -- constant: maps digits to their S2 summed values DECLARE @table TABLE (ID INT, Value INT, S_Value INT); -- ID=digit position. S_Value is used for SUM(). DECLARE @p INT = 0; -- loop counter: position in string -- Convert the reversed string's digits into rows in a table variable, S_Values to be updated afterwards WHILE @p < LEN(@string) BEGIN SET @p = @p+1; INSERT INTO @table (ID,Value,S_Value) VALUES (@p, CONVERT(INT,SUBSTRING(@string,@p,1)), 0); END -- Update S_Value column : the digit's value to be summed (for even-positioned digits this is mapped via @strS2Values) UPDATE @table SET S_Value = CASE WHEN ID % 2 = 1 THEN Value ELSE CONVERT(INT,SUBSTRING(@strS2Values,Value+1,1)) END -- If the SUM of S_Values ends in 0 (modulo 10 = 0) then the CC Number is valid RETURN CASE WHEN (SELECT SUM(S_Value) FROM @table) % 10 = 0 THEN 'Valid' ELSE 'Invalid' END END ## TUSCRIPT $$MODE TUSCRIPT MODE DATA$$ SET cardnumbers=* 49927398716 49927398717 1234567812345678 1234567812345670$$MODE TUSCRIPT -> collecting information for output-format SET length=MAX_LENGTH(cardnumbers) SET adjust=length+2 LOOP c=cardnumbers -> ">/" = any digit SET cstring=STRINGS (c,":>/:") SET creverse=REVERSE (cstring) SET s1=evenx2=esum=s2="" LOOP n,oe=creverse SET modrest=MOD(n,2) IF (modrest==0) THEN SET even=oe*2 IF (even>9) THEN SET estring=STRINGS (even,":>/:") SET esum=SUM (estring) SET s2=APPEND (s2,esum) ELSE SET s2=APPEND (s2,even) ENDIF ELSE SET s1=APPEND(s1,oe) ENDIF ENDLOOP SET s1=SUM(s1),s2=SUM(s2) SET checksum=s1+s2 SET c=CENTER(c,-adjust) IF (checksum.ew."0") THEN PRINT c,"true" ELSE PRINT c,"false" ENDIF ENDLOOP Output: 49927398716 true 49927398717 false 1234567812345678 false 1234567812345670 true  ## TXR @(do (defun luhn (num) (for ((i 1) (sum 0)) ((not (zerop num)) (zerop (mod sum 10))) ((inc i) (set num (trunc num 10))) (let ((dig (mod num 10))) (if (oddp i) (inc sum dig) (let ((dig2 (* 2 dig))) (inc sum (+ (trunc dig2 10) (mod dig2 10))))))))) @(collect :vars nil) @{ccnumber /[0-9]+/} @(output) @ccnumber -> @(if (luhn (int-str ccnumber 10)) "good" "bad") @(end) @(end) $ txr luhn.txr luhn.txt
49927398716 -> good
49927398717 -> bad
1234567812345678 -> bad
1234567812345670 -> good

## Uiua

Luhn ← =0◿10+⊃(/+⊢|/+∵(⍥(-9)>9.×2)⊡1)⍉⬚0↯∞_2⇌
T ← {"49927398716"
"49927398717"
"1234567812345678"
"1234567812345670"}
≡◇(Luhn ≡⋕) T
Output:
[1 0 0 1]


## UNIX Shell

Works with: bash
Works with: ksh
function luhn {
typeset n p s t=('0123456789' '0516273849')
while ((-n<${#1})); do p="${t[n--%2]%${1:n:1}*}" ((s+=${#p}))
done
((s%10))
}

for c in 49927398716 49927398717 1234567812345678 1234567812345670; do
if luhn $c; then echo$c is invalid
else
echo $c is valid fi done Notes: • The parameter expansion hack (p=${t…%${1:n:1}};…${#p}…) is an interesting way of converting a set of characters to ordinals. It's highly extensible to larger character sets (e.g. for ISBN and Code 39 checksums).
• Invalid characters are effectively treated as 0s. This is actually useful sometimes for ignoring alphabetic prefixes.
• When attempting to understand the function, remember that n is negative, so it indexes from the end of the input string.
Output:
49927398716 is valid
49927398717 is invalid
1234567812345678 is invalid
1234567812345670 is valid

## Ursala

#import std
#import nat

luhn = %nP; %np*hxiNCNCS; not remainder\10+ //sum:-0@DrlrHK32 ~&iK27K28TK25 iota10

Some notes on this solution:

• iota10 is the list of natural numbers <0,1,2,3,4,5,6,7,8,9>
• ~&K27 and ~&K28 of iota10 extract the alternate items, respectively <0,2,4,6,8> and <1,3,5,7,9>
• ~&K27K28T iota10 is their concatenation, <0,2,4,6,8,1,3,5,7,9> which is also the list of values obtained by doubling each item of iota10 and taking digit sums
• ~&iK27K28TX iota10 would be the pair (<0,1,2,3,4,5,6,7,8,9>,<0,2,4,6,8,1,3,5,7,9>), but using the reification operator K25 in place of X makes it an executable function taking any item of the left list as an argument and returning the corresponding item of the right.
• The part beginning with // is a function of the form //f a, which can be applied to any argument b to obtain f(a,b). In this case, the f is sum:-0@DrlrHK32, which is equivalent to the composition of two functions sum:-0 and ~&DrlrHK32, and a is the function just obtained by reification.
• The function ~&D by itself takes a pair (a,<b0...bn>) whose right side is a list, and returns the list of pairs <(a,b0)...(a,bn)> (i.e., a copy of a paired with each b). The a here will end up being the aforementioned function.
• ~&DrlrHK32 not only forms such a list of pairs, but operates on each pair thus obtained, alternately applying ~&r and ~&lrH to each pair in sequence, where ~&r simply returns the right side of the pair, and ~&lrH uses the left side as a function, which is applied to the right.
• sum:-0 computes the cumulative sum of a list of natural numbers using the binary sum function, and the reduction operator (:-) with vacuous sum 0.
• The whole thing described up to this point is therefore a function that will take a list of numbers in the range 0 to 9, and compute the summation obtained when doubling and digit summing alternate items.
• The input list to this function is constructed from a single natural number first by %nP, which transforms it to text format in decimal, followed by %np*hxiNCNCS, which reverses the digits, makes a separate text of each, and parses them as individual numbers.
• The output from the function is tested for divisibility by 10 with remainder\10, with the result negated so that zero values map to true and non-zero to false.

usage:

#cast %bL

test = luhn* <49927398716,49927398717,1234567812345678,1234567812345670>
Output:
<true,false,false,true>


## VBA

Option Explicit

Sub Main()
Debug.Print "Number 49927398716 is "; Luhn("49927398716")
Debug.Print "Number 49927398717 is "; Luhn("49927398717")
Debug.Print "Number 1234567812345678 is "; Luhn("1234567812345678")
Debug.Print "Number 1234567812345670 is "; Luhn("1234567812345670")
End Sub
Private Function Luhn(Nb As String) As String
Dim t$, i&, Summ&, s& t = StrReverse(Nb) For i = 1 To Len(t) Step 2 Summ = Summ + CInt(Mid(t, i, 1)) Next i For i = 2 To Len(t) Step 2 s = 2 * (CInt(Mid(t, i, 1))) If s >= 10 Then Summ = Summ - 9 End If Summ = Summ + s Next i If Summ Mod 10 = 0 Then Luhn = "valid" Else Luhn = "invalid" End If End Function Output: Number 49927398716 is valid Number 49927398717 is invalid Number 1234567812345678 is invalid Number 1234567812345670 is valid ## VBScript Function Luhn_Test(cc) cc = RevString(cc) s1 = 0 s2 = 0 For i = 1 To Len(cc) If i Mod 2 > 0 Then s1 = s1 + CInt(Mid(cc,i,1)) Else tmp = CInt(Mid(cc,i,1))*2 If tmp < 10 Then s2 = s2 + tmp Else s2 = s2 + CInt(Right(CStr(tmp),1)) + 1 End If End If Next If Right(CStr(s1 + s2),1) = "0" Then Luhn_Test = "Valid" Else Luhn_Test = "Invalid" End If End Function Function RevString(s) For i = Len(s) To 1 Step -1 RevString = RevString & Mid(s,i,1) Next End Function WScript.Echo "49927398716 is " & Luhn_Test("49927398716") WScript.Echo "49927398717 is " & Luhn_Test("49927398717") WScript.Echo "1234567812345678 is " & Luhn_Test("1234567812345678") WScript.Echo "1234567812345670 is " & Luhn_Test("1234567812345670") Output: 49927398716 is Valid 49927398717 is Invalid 1234567812345678 is Invalid 1234567812345670 is Valid ## Visual Basic Works with: Visual Basic version VB6 Standard Public Function LuhnCheckPassed(ByVal dgts As String) As Boolean Dim i As Long, s As Long, s1 As Long dgts = VBA.StrReverse(dgts) For i = 1 To Len(dgts) Step 2 s = s + CInt(Mid$(dgts, i, 1))
Next i
For i = 2 To Len(dgts) Step 2
s1 = 2 * (CInt(Mid$(dgts, i, 1))) If s1 >= 10 Then s = s - 9 End If s = s + s1 Next i LuhnCheckPassed = Not CBool(s Mod 10) End Function Test: Sub Main() Debug.Assert LuhnCheckPassed("49927398716") Debug.Assert Not LuhnCheckPassed("49927398717") Debug.Assert Not LuhnCheckPassed("1234567812345678") Debug.Assert LuhnCheckPassed("1234567812345670") End Sub ## Visual Basic .NET  Imports System.Linq Function ValidLuhn(value As String) Return value.Select(Function(c, i) (AscW(c) - 48) << ((value.Length - i - 1) And 1)).Sum(Function(n) If(n > 9, n - 9, n)) Mod 10 = 0 End Function Sub Main() Console.WriteLine(ValidLuhn("49927398716")) Console.WriteLine(ValidLuhn("49927398717")) Console.WriteLine(ValidLuhn("1234567812345678")) Console.WriteLine(ValidLuhn("1234567812345670")) End Sub Output: True False False True  ## V (Vlang) Translation of: go const ( input = '49927398716 49927398717 1234567812345678 1234567812345670' t = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] ) fn luhn(s string) bool { odd := s.len & 1 mut sum := 0 for i, c in s.split('') { if c < '0' || c > '9' { return false } if i&1 == odd { sum += t[c.int()-'0'.int()] } else { sum += c.int() - '0'.int() } } return sum%10 == 0 } fn main() { for s in input.split("\n") { println('$s ${luhn(s)}') } } Output: 49927398716 true 49927398717 false 1234567812345678 false 1234567812345670 true  ## Wren Library: Wren-fmt Library: Wren-iterate import "./fmt" for Fmt import "./iterate" for Stepped var luhn = Fn.new { |s| // reverse digits s = s[-1..0] // sum the odd digits var s1 = Stepped.new(s, 2).reduce(0) { |sum, d| sum + d.bytes[0] - 48 } // sum two times the even digits var s2 = Stepped.new(s[1..-1], 2).reduce(0) { |sum, d| var d2 = (d.bytes[0] - 48) * 2 return sum + ((d2 > 9) ? d2%10 + 1 : d2) } // check if s1 + s2 ends in zero return (s1 + s2)%10 == 0 } var tests = [ "49927398716", "49927398717", "1234567812345678", "1234567812345670"] for (test in tests) { var ans = (luhn.call(test)) ? "pass" : "fail" Fmt.print("$-16s -> $s", test, ans) } Output: 49927398716 -> pass 49927398717 -> fail 1234567812345678 -> fail 1234567812345670 -> pass  ## Xojo Public Function Modulus10(digits As String) as String // // Confirm the digits are really, well, digits // dim validator as new RegEx validator.SearchPattern = "\A\d+\z" if validator.Search( digits ) is nil then // // Raise an exception or something // end if static doublingTable() as string = array( "0", "2", "4", "6", "8", "1", "3", "5", "7", "9" ) dim digitArr() as string = digits.Split( "" ) for i as integer = digitArr.Ubound downto 0 step 2 digitArr( i ) = doublingTable( digitArr( i ).Val ) next dim sum as integer for each digit as string in digitArr sum = sum + digit.Val next dim check as integer = ( sum * 9 ) mod 10 return str( check ) End Function Public Function ValidateMod10(digits As String) as Boolean dim checkDigit as string = digits.Right( 1 ) digits = digits.Left( digits.Len - 1 ) return Modulus10( digits ) = checkDigit End Function Output: ValididateMod10( "49927398716" ) = True ValididateMod10( "49927398717" ) = False ValididateMod10( "1234567812345678" ) = False ValididateMod10( "1234567812345670" ) = True  ## XPL0 string 0; \use zero-terminated strings func Valid(Str); \Return 'true' if digits in Str pass Luhn test char Str; int Len, Sum, I, Dig; [Len:= 0; \find length of Str while Str(Len) do Len:= Len+1; Sum:= 0; \sum even and odd digits for I:= 0 to Len-1 do \(no need to reverse) [if (I xor Len) and 1 then Sum:= Sum + Str(I) - ^0 else [Dig:= Str(I) - ^0; Dig:= Dig*2; Sum:= Sum + Dig/10 + rem(0); ]; ]; return rem(Sum/10) = 0; ]; int Luhn, N; [Luhn:= ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]; for N:= 0 to 4-1 do [Text(0, Luhn(N)); Text(0, if Valid(Luhn(N)) then " is valid" else " is not valid"); CrLf(0); ]; ] Output: 49927398716 is valid 49927398717 is not valid 1234567812345678 is not valid 1234567812345670 is valid  ## zkl fcn luhnTest(n){ 0 == (n.split().reverse().reduce(fcn(s,n,clk){ s + if(clk.next()) n else 2*n%10 + n/5 },0,Walker.cycle(1,0)) %10) } T(49927398716,49927398717,1234567812345678,1234567812345670) .apply(luhnTest).println(); Output: L(True,False,False,True)  ## ZX Spectrum Basic 10 LET c$="49927398716": GO SUB 1000
20 LET c$="49927398717": GO SUB 1000 30 LET c$="1234567812345678": GO SUB 1000
40 LET c$="1234567812345670": GO SUB 1000 999 STOP 1000 REM ************* 1001 REM * LUHN TEST * 1002 REM ************* 1010 LET r$=""
1020 FOR i=LEN c$TO 1 STEP -1 1030 LET r$=r$+c$(i)
1040 NEXT i
1050 LET s1=0: LET s2=0
1060 FOR i=1 TO LEN r$STEP 2 1070 LET s1=s1+VAL r$(i)
1080 NEXT i
1090 FOR i=2 TO LEN r$STEP 2 1100 LET s2sub=VAL r$(i)*2
1110 IF s2sub>=10 THEN LET s2sub=1+s2sub-10
1120 LET s2=s2+s2sub
1130 NEXT i
1140 LET s$=STR$ (s1+s2)
1150 IF s$(LEN s$)="0" THEN PRINT c$;" VALID!": LET retval=1: RETURN 1160 PRINT c$;" INVALID!": LET retval=0: RETURN
Output:
49927398716 VALID!
49927398717 INVALID!
1234567812345678 INVALID!
1234567812345670 VALID!