Luhn test of credit card numbers

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.

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

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

<lang 11l>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))</lang>
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. <lang 360asm>* 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</lang>
Output:
49927398716          Valid
49927398717          Invalid
1234567812345678     Invalid
1234567812345670     Valid

8080 Assembly

<lang 8080asm> 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$'</lang>

Output:
A>luhn 49927398716
Pass
A>luhn 49927398717
Fail
A>luhn 1234567812345678
Fail
A>luhn 1234567812345670
Pass

8086 Assembly

<lang asm> 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$'</lang>

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


8th

<lang Forth> \ 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</lang>

Output:
49927398716 OK
49927398717 FAIL
1234567812345678 FAIL
1234567812345670 OK

ABAP

<lang 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.</lang>

ACL2

<lang Lisp>(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)))</lang>
Output:
> (luhn 49927398716)
T
> (luhn 49927398717)
NIL
> (luhn 1234567812345678)
NIL
> (luhn 1234567812345670)
T

ActionScript

<lang 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"));</lang>

Ada

Translation of: C
Works with: GNAT

<lang Ada>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;</lang>

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)

<lang algol68>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

)</lang>

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 <lang algolw>% 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</lang>

Use the above to test the LuhnTest procedure:

<lang algolw>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.</lang>

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

APL

Works with: Dyalog APL

<lang 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       
}</lang>
Output:
      LuhnTest¨'49927398716' '49927398717' '1234567812345678' '1234567812345670'
1 0 0 1
Works with: APL+Win

<lang APL> ∇ 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

   ∇</lang>
Output:
      LuhnTest¨ 49927398716 49927398717 1234567812345678 1234567812345670
1 0 0 1

AppleScript

Functional

<lang applescript>-- 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</lang>

Output:
{true, false, false, true}

Straightforward

<lang applescript>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</lang>

Output:

<lang applescript>{{testNumber:"49927398716", valid:true}, {testNumber:"49927398717", valid:false}, {testNumber:"1234567812345678", valid:false}, {testNumber:"1234567812345670", valid:true}}</lang>

ARM Assembly

<lang 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" </lang>

AutoHotkey

<lang 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)

}</lang>

AutoIt

<lang 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 </lang>

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

AWK

<lang 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);	

}</lang>

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

Bash

<lang 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"</lang>

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

Batch File

This simple implementation does not reverse the numbers. Instead, it counts from right to left. <lang dos>@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</lang>

Output:
>luhn.bat
49927398716 is valid.
49927398717 is not valid.
1234567812345678 is not valid.
1234567812345670 is valid.

>

BBC BASIC

<lang bbcbasic> 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</lang>

bc

<lang 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)</lang>

Output:
1
0
0
1

Befunge

<lang 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

</lang> 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

Bracmat

<lang 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 & ;</lang>

Output:
49927398716 : true
49927398717 : false
1234567812345678 : false
1234567812345670 : true

Brainf***

<lang>>>>>>>>>>+>,----------[ 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 </lang>

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


C

<lang c>#include <string.h>

  1. 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;

}</lang>

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.

<lang csharp>

   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 ");
       }
   }

</lang>

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.

<lang csharp>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);
           }
           
       }
   }

}</lang>

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. <lang csharp> 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; } } } } </lang>

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

A solution optimized for readability: <lang csharp> 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;
   }

} </lang>

Extremely compact version uses Europa rtl library https://github.com/CodeAlkemist/Europa-rtl <lang csharp> 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();
   }

} </lang>

49927398716
True
49927398717
False
1234567812345678
False
1234567812345670
False

C++

<lang cpp>#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;

}</lang>

C++11

<lang cpp>#include <iostream>

  1. include <vector>
  2. 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;

} </lang>

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

<lang cpp>#include <iostream>

  1. 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;

} </lang>

true
false
false
true

Caché ObjectScript

<lang cos>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) }

}</lang>

Examples:
USER>For  { Read ccn Quit:ccn=""  Write ": "_##class(Utils.Check).Luhn(ccn), ! }
49927398716: 1
49927398717: 0
1234567812345678: 0
1234567812345670: 1

USER>

Ceylon

<lang 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; }</lang>

Clojure

<lang 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)))</lang>

COBOL

Works with: OpenCOBOL

<lang cobol> 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.</lang>
Output:
input=49927398716         pass 
input=49927398717         fail 
input=1234567812345678    fail 
input=1234567812345670    pass 

Common Lisp

<lang 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))))))</lang> Another version, using Maciej Pasternacki's reader macros for function composition and currying in the curly package: <lang lisp>(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)))</lang>

Cowgol

<lang cowgol>include "cowgol.coh";

  1. Given a string containing the digits of a credit card number,
  2. 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;


  1. 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");</lang>

Output:
49927398716: Pass
49927398717: Fail
1234567812345678: Fail
1234567812345670: Pass

Crystal

<lang ruby>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)}" }</lang>

Output:
49927398716: true
49927398717: false
1234567812345678: false
1234567812345670: true

D

Functional Version

Translation of: Haskell

<lang d>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]));

}</lang>

More Imperative Version

Translation of: C

<lang d>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]));

}</lang>

Stronger Statically Typed Version

This version uses more precise types.

Translation of: SPARK

<lang d>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 ");

}</lang>

EchoLisp

<lang lisp>

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 </lang>

Elixir

<lang 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)}"</lang>

Output:
49927398716: true
49927398717: false
1234567812345678: false
1234567812345670: true

Emacs Lisp

<lang lisp> (require 'seq) (defun luhn (str)

 "Check if an input string STR is valid using lhun algorithm."
 (if (string-match-p "[^0-9]" str)
     (error "String contains invalid character")
   (progn
     (let ((digit-list (reverse (mapcar #'(lambda (x) (- x 48))
                                        (string-to-list str)))))
       (zerop
        (mod (apply #'+ (seq-map-indexed
                         (lambda (elt idx)
                           (if (oddp idx)
                               (if (> (* 2 elt) 9)
                                   (- (* 2 elt) 9)
                                 (* 2 elt))
                             elt))
                         digit-list))
             10))))))


(mapcar #'luhn '("49927398716" "49927398717" "1234567812345678" "1234567812345670"))

</lang>

Output:
 (t nil nil t) 

Erlang

<lang 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].

</lang>

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

Euphoria

Translation of: C

<lang euphoria>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</lang>

Output:
49927398716 = 1
49927398717 = 0
1234567812345678 = 0
1234567812345670 = 1

F#

<lang fsharp>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</lang>

Factor

Works with: Factor version 0.98

<lang factor>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 = ;

</lang>

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

Forth

<lang 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</lang>

Fortran

<lang 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</lang>

FreeBASIC

<lang FreeBASIC>' version 05-07-2015 ' compile with: fbc -s console

  1. Ifndef TRUE ' define true and false for older freebasic versions
   #Define FALSE 0
   #Define TRUE Not FALSE
  1. 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</lang>

Output:
Task test number 49927398716 should be TRUE, report back as TRUE

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

FunL

<lang 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') )</lang>
Output:
49927398716 is valid
49927398717 is invalid
1234567812345678 is invalid
1234567812345670 is valid

Gambas

Click this link to run this code <lang 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</lang> Output:

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

GAP

<lang 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);

  1. [ true, false, false, true ]
  1. Will also work on strings, and will skip non-digits

IsLuhn("4-992-739-871-6");

  1. true</lang>

Go

<lang 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))
   }

}</lang>

Output:
49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true

Groovy

<lang 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

}</lang> Testing the function: <lang groovy>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

}</lang>

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

Haskell

<lang haskell>import Data.Char (digitToInt) luhn = (0 ==) . (`mod` 10) . sum . map (uncurry (+) . (`divMod` 10)) .

      zipWith (*) (cycle [1,2]) . map digitToInt . reverse</lang>
Output:

<lang haskell>map luhn ["49927398716", "49927398717", "1234567812345678", "1234567812345670"] [True,False,False,True]</lang>

Or, aiming for a legible relationship with the stages shown in the task description: <lang haskell>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"
   ]</lang>
Output:
("49927398716",True)
("49927398717",False)
("1234567812345678",False)
("1234567812345670",True)

HicEst

<lang 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</lang>

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. <lang icon>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</lang>

Output:
# luhn10 49927398716 49927398717 1234567812345678 1234567812345670

49927398716 - valid
49927398717 - invalid
1234567812345678 - invalid
1234567812345670 - valid

IS-BASIC

<lang 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</lang>

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.

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.

<lang J>luhn=: 0 = 10 (| +/@,) 10 #.inv 1 2 *&|: _2 "."0\ |.</lang>

Example use: <lang J> luhn&> '49927398716';'49927398717';'1234567812345678';'1234567812345670' 1 0 0 1</lang>

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

<lang 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;
   }

}</lang>

Output:
true
false
false
true

JavaScript

Using prototype. <lang javascript>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))});</lang>

Without any library. <lang javascript>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); } })();</lang>

Highly compressed version. <lang javascript>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') </lang>

jq

<lang jq>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;
 (tostring | explode | reverse ) as $reverse
 | ($reverse | odds  | digits | add) as $s1
 | ($reverse | evens | digits | map(. * 2 | sumdigits) | add) as $s2
 | 0 == ($s1 + $s2) % 10 ;</lang>

Example <lang jq> ( 49927398716,

   49927398717,
   1234567812345678,
   1234567812345670
 ) | "\(.) => \(luhn)";</lang>
Output:
$ jq -r -M -n -f luhn.jq
49927398716 => true
49927398717 => false
1234567812345678 => false
1234567812345670 => true

Julia

The test function itself is only a single line of code:

<lang Julia>luhntest(x::Integer) = (sum(digits(x)[1:2:end]) + sum(map(x -> sum(digits(x)), 2 * digits(x)[2:2:end]))) % 10 == 0</lang>

More readable version:

<lang julia>function luhntest(x::Integer)

   d = reverse(digits(x))
   s = sum(d[1:2:end])
   s += sum(sum.(digits.(2d[2:2:end])))
   return s % 10 == 0

end

for card in [49927398716, 49927398717, 1234567812345678, 1234567812345670]

   println(luhntest(card) ? "PASS " : "FAIL ", card)

end</lang>

Output:
PASS 49927398716
FAIL 49927398717
FAIL 1234567812345678
PASS 1234567812345670

K

<lang k>so: {+/x@2*!_ceil(#x)%2} se: {+/{+/0$'$x}'2*x@1+2*!(#x)%2} luhn: {n:|0$'$x; 0=((se n)+so n)!10}</lang>

Translation of: J

<lang k>luhn2: {~(+/,//10_vs'1 2*+-1 2#((#n)!2){x,0}/n:0$'|$x)</lang>

Example:

<lang k> luhn'49927398716 49927398717 1234567812345678 1234567812345670 1 0 0 1

 luhn2'49927398716 49927398717 1234567812345678 1234567812345670

1 0 0 1</lang>

Works with: K version 3

<lang k>luhn:{[cc]

   digits:0$/:|cc / convert chars to digit ints
   s:digits*(#cc)#1 2 / evens doubled, odds not
   nines:+/s>9 / number of sums greater than 9
   :~((+/s)-(9*nines))!10 / sum minus the nines is mod ten?
   }</lang>

Example:

<lang k> test:("49927398716";"49927398717";"1234567812345678";"1234567812345670")

 luhn'test

1 0 0 1</lang>

Kotlin

<lang scala>// version 1.0

fun checkLuhn(number: String): Boolean {

   var isOdd = true
   var sum = 0
   for (index in number.indices.reversed()) {
       val digit = number[index] - '0'
       sum += if (isOdd) digit else (digit * 2).let { (it / 10) + (it % 10) }
       isOdd = !isOdd
   }
   return (sum % 10) == 0

}

fun main(args: Array<String>) {

   val numbers = arrayOf("49927398716", "49927398717", "1234567812345678", "1234567812345670")
   for (number in numbers)
       println("${number.padEnd(16)} is ${if(checkLuhn(number)) "valid" else "invalid"}")

}</lang>

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

langur

Translation of: Go
Works with: langur version 0.8.10

<lang langur>val .luhntest = f(.s) {

   val .t = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
   val .numbers = s2n .s
   val .oddeven = len(.numbers) rem 2
   for[=0] .i of .numbers {
       _for += if(.i rem 2 == .oddeven: .numbers[.i]; .t[.numbers[.i]+1])
   } div 10

}

val .tests = h{

   "49927398716": true,
   "49927398717": false,
   "1234567812345678": false,
   "1234567812345670": true,

}

for .key of .tests {

   val .pass = .luhntest(.key)
   write .key, ": ", .pass
   writeln if(.pass == .tests[.key]: ""; " (LUHN TEST FAILED)")

}</lang>

Output:
49927398717: false
49927398716: true
1234567812345678: false
1234567812345670: true

Lasso

Part of the Lasso's implementation of "valid_creditcard". <lang lasso>#!/usr/bin/lasso9

define luhn_check(number) => {

 local(
   rev = #number->asString,
   checksum = 0
 )
 #rev->reverse
 iterate(#rev, local(digit)) => {
   if((loop_count % 2) == 0) => {
     #checksum += (2 * integer(#digit))
     integer(#digit) >= 5 ? #checksum -= 9
   else
     #checksum += integer(#digit)
   }
 }
 (#checksum % 10) != 0 ? return false
 return true

}

stdoutnl(luhn_check(49927398716)) // true stdoutnl(luhn_check(49927398717)) // false stdoutnl(luhn_check(1234567812345678)) // false stdoutnl(luhn_check(1234567812345670)) // true</lang>

Liberty BASIC

<lang lb>' [RC] Luhn test

card$(1)="49927398716" card$(2)="49927398717" card$(3)="1234567812345678" card$(4)="1234567812345670"

for test = 1 to 4

   odd=1
   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=0
       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=1
       end if
   next
   if sum mod 10 = 0 then
       print card$(test),"True"
   else
       print card$(test),"False"
   end if

next</lang>

LiveCode

<lang LiveCode>function LuhnTest cc

   local s1,evens, s2
   repeat with n = 1 to len(cc)
       if n mod 2 is not 0 then
           add (char -n of cc) to s1
       else
           put (char -n of cc) * 2 into evens
           if evens > 9 then subtract 9 from evens
           add evens to s2
       end if
   end repeat
   return the last char of (s1 + s2) is 0

end LuhnTest

-- test repeat for each item ccno in "49927398716,49927398717,1234567812345678,1234567812345670"

   put ccno && LuhnTest(ccno) & cr after luhncheck

end repeat put luhncheck

49927398716 true 49927398717 false 1234567812345678 false 1234567812345670 true </lang>

<lang logo>to small? :list

 output or [empty? :list] [empty? bf :list]

end to every.other :list

 if small? :list [output :list]
 output fput first :list every.other bf bf :list

end to wordtolist :word

 output map.se [?] :word

end

to double.digit :digit

 output item :digit {0 2 4 6 8 1 3 5 7 9}@0
 ; output ifelse :digit < 5 [2*:digit] [1 + modulo 2*:digit 10]

end

to luhn :credit

 localmake "digits reverse filter [number? ?] wordtolist :credit
 localmake "s1 apply "sum every.other :digits
 localmake "s2 apply "sum map "double.digit every.other bf :digits
 output equal? 0 last sum :s1 :s2

end

show luhn "49927398716  ; true show luhn "49927398717  ; false show luhn "1234-5678-1234-5678  ; false show luhn "1234-5678-1234-5670  ; true</lang>

Lua

<lang Lua>function luhn(n)

 n=string.reverse(n)
 print(n)
 local s1=0
 --sum odd digits
 for i=1,n:len(),2 do
   s1=s1+n:sub(i,i)
 end
 --evens
 local s2=0
 for i=2,n:len(),2 do
   local doubled=n:sub(i,i)*2
   doubled=string.gsub(doubled,'(%d)(%d)',function(a,b)return a+b end)
   s2=s2+doubled
 end
 print(s1)
 print(s2)
 local total=s1+s2
 if total%10==0 then
   return true
 end
 return false

end

-- Note that this function takes strings, not numbers. -- 16-digit numbers tend to be problematic -- when looking at individual digits. print(luhn'49927398716') print(luhn'49927398717') print(luhn'1234567812345678') print(luhn'1234567812345670')</lang>

M2000 Interpreter

Translation of: FreeBASIC

<lang M2000 Intertrpeter> Module Checkit {

     Function luhntest(cardnr$) {
      
           cardnr$ = Trim$(cardnr$) ' we don't want spaces
           if len(cardnr$)=0 then exit
           Dim Base 0,  reverse_nr$(Len(cardnr$))
           Def integer  i, j, s1, s2, l , l2
           Let l=Len(cardnr$)-1, l2=l+1
              
           ' reverse string
           For i = 0 To l
               reverse_nr$(i) = mid$(cardnr$,l2-i,1)
           Next i
           ' sum odd numbers
           For i = 0 To l Step 2
               s1 = s1 + (Asc(reverse_nr$(i)) - Asc("0"))
           Next i
           ' sum even numbers
           For i = 1 To l Step 2
               j = Asc(reverse_nr$(i)) - Asc("0")
               j = j * 2
               If j > 9 Then j = j Mod 10 + 1
               s2 = s2 + j
           Next i
              
           If (s1 + s2) Mod 10 = 0 Then
               = 1=1
           Else
               = 1=0
           End If       
     }
     Flush
     Data "49927398716",  "49927398717", "1234567812345678", "1234567812345670"
     while not empty
           over
           print letter$;" = ";luhntest(letter$)
     end while

} Checkit </lang>

Output:
49927398716 = True
49927398717 = False
1234567812345678 = False
1234567812345670 = True

Mathematica

<lang Mathematica>LuhnQ[nb_] := (Mod[Total[(2*ToExpression[#2;;All;;2]) /. {z_?(Function[v, v>9]) -> z-9}]

      + Total[ToExpression[#1;;All;;2]], 10] == 0)& [Characters[StringReverse[ToString[nb]]] ]

LuhnQ /@ {49927398716, 49927398717, 1234567812345678, 1234567812345670} ->{True, False, False, True}</lang>

Alternate Code

Eliminates conversion of numbers to strings and back <lang Mathematica>LuhnQ[n_Integer] :=

Block[{digits = Reverse@IntegerDigits@n},
 Mod[Total[{digits;; ;; 2, 
     IntegerDigits[2 #] & /@ digits2 ;; ;; 2}, -1], 10] == 0]

LuhnQ /@ {49927398716, 49927398717, 1234567812345678, 1234567812345670}</lang>

Output:
{True,False,False,True}

MATLAB

The solution is basically the same as for Octave. <lang MATLAB>function passed = luhn(num) if nargin == 0 % evaluate test cases

 testnum = [49927398716 49927398717 1234567812345678 1234567812345670];
 for num = testnum
   disp([int2str(num) ': ' int2str(luhn(num))])
 end
 return  

end % luhn function starts here d = int2str(num) - '0'; % convert number into vector of digits m = [2:2:8,1:2:9]; % rule 3: maps 1:9 to [2 4 6 8 1 3 5 7 9] passed = ~mod(sum(d(end:-2:1)) + sum(m(d(end-1:-2:1))), 10); end</lang>

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

min

Works with: min version 0.19.3

<lang min>((dup 10 <) 'quote (((10 mod) (10 div)) cleave) 'cons linrec) :digits ((0 0) dip (pop 'succ dip over even?) partition ((pop pop) dip) dip) :evens/odds ((2 * digits sum) map sum) :evens-sum (digits evens/odds ('evens-sum 'sum) => spread + 10 mod 0 ==) :luhn?

(49927398716 49927398717 1234567812345678 1234567812345670) (dup print! " " print! luhn? puts!) foreach</lang>

Output:
49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true

MiniScript

<lang MiniScript>isValid = function(s)

   sum = 0
   odd = true
   for i in range(s.len-1)
       d = val(s[i])
       sum = sum + d * (2 - odd)
       if not odd and d > 4 then sum = sum - 9
       odd = not odd
   end for
   return sum % 10 == 0

end function

test = function(s)

   if isValid(s) then print s + ": valid" else print s + ": invalid"

end function

test "49927398716" test "49927398717" test "1234567812345678" test "1234567812345670"</lang>

Output:
49927398716: valid
49927398717: invalid
1234567812345678: invalid
1234567812345670: valid

MUMPS

<lang mumps>LUHN(C)

NEW ODD,EVEN,S
SET S=$REVERSE(C)
SET ODD=0 FOR I=1:2:$LENGTH(S) SET ODD=ODD+$EXTRACT(S,I)
SET EVEN=0 FOR I=2:2:$LENGTH(S) SET T=$EXTRACT(S,I)*2 SET EVEN=EVEN+$SELECT(T<=9:T,T>9:$EXTRACT(T,1)+$EXTRACT(T,2))
QUIT '((ODD+EVEN)#10)</lang>
USER>W !,$S($$LUHN^ROSETTA("49927398716")=0:"INVALID",1:"VALID")
 
VALID
USER>W !,$S($$LUHN^ROSETTA("49927398717")=0:"INVALID",1:"VALID")
 
INVALID
USER>W !,$S($$LUHN^ROSETTA("1234567812345678")=0:"INVALID",1:"VALID")
 
INVALID
USER>W !,$S($$LUHN^ROSETTA("1234567812345670")=0:"INVALID",1:"VALID")
 
VALID

Nanoquery

Translation of: Java

<lang Nanoquery>def reverse_str(string)

   to_return = ""
   for i in range(len(string) - 1, 0, -1)
       to_return += string[i]
   end for
   return to_return

end reverse_str

def luhnTest(number)

   s1 = 0; s2 = 0
   reversed = reverse_str(number)
   for i in range(0, len(reversed) - 1)
       digit = int(reversed[i])
       if (i % 2) = 0
           s1 += digit
       else
           s2 += 2 * digit
           if digit >= 5
               s2 -= 9
           end if
       end if
   end for
   return ((s1 + s2) % 10) = 0

end luhnTest

println luhnTest("49927398716") println luhnTest("49927398717") println luhnTest("1234567812345678") println luhnTest("1234567812345670")</lang>

Output:
true
false
false
true

NetRexx

Translation of: REXX

<lang netrexx>

class LuhnTest

 method main(args=String[]) static
   cc	  = 0 
   cc[1] = '49927398716'
   cc[2] = '49927398717'
   cc[3] = '1234567812345678'
   cc[4] = '1234567812345670'

   loop k=1 while cc[k] <> 0
     r = checksum(cc[k])
     if r==0 then say cc[k].right(20) 'passed'
     else say cc[k].right(20) 'failed'
   end
   
   -- Luhn algorithm checksum for credit card numbers
 method checksum(t) static
   if t.length()//2 then t = '0't  --pad # on left with 0
   t = t.reverse()
   s = 0
   loop j = 1 to t.length()-1 by 2
     q = 2*t.substr(j+1,1)
     if q>9 then q = q.left(1) + q.right(1)
     s= s+t.substr(j,1)+q
   end
   return s//10\==0

</lang>

Nim

<lang nim>proc luhn(cc: string): bool =

 const m = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
 var sum = 0
 var odd = true
 for i in countdown(cc.high, 0):
   let digit = ord(cc[i]) - ord('0')
   sum += (if odd: digit else: m[digit])
   odd = not odd
 result = sum mod 10 == 0

for cc in ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]:

 echo cc, ' ', luhn(cc)</lang>
Output:
49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true

Objeck

<lang objeck>bundle Default {

 class Luhn {
   function : IsValid(cc : String) ~ Bool {
     isOdd := true;
     oddSum := 0;
     evenSum := 0;
     
     for(i := cc->Size() - 1; i >= 0; i -= 1;) {
       digit : Int := cc->Get(i) - '0';
       if(isOdd) {
         oddSum += digit;
       } 
       else {
         evenSum += digit / 5 + (2 * digit) % 10;
       };
       isOdd := isOdd <> true;
     };
      
     return (oddSum + evenSum) % 10 = 0;
   }
   
   function : Main(args : String[]) ~ Nil {
     IsValid("49927398716")->PrintLine();
     IsValid("49927398717")->PrintLine();
     IsValid("1234567812345678")->PrintLine();
     IsValid("1234567812345670")->PrintLine();
   }
 }

}</lang>

Objective-C

<lang objc>- (NSArray *) toCharArray {

NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[self length]]; for (int i=0; i < [self length]; i++) { NSString *ichar = [NSString stringWithFormat:@"%C", [self characterAtIndex:i]]; [characters addObject:ichar]; }

return characters; }

+ (BOOL) luhnCheck:(NSString *)stringToTest {

NSArray *stringAsChars = [stringToTest toCharArray];

BOOL isOdd = YES; int oddSum = 0; int evenSum = 0;

for (int i = [stringToTest length] - 1; i >= 0; i--) {

int digit = [(NSString *)stringAsChars[i] intValue];

if (isOdd) oddSum += digit; else evenSum += digit/5 + (2*digit) % 10;

isOdd = !isOdd; }

return ((oddSum + evenSum) % 10 == 0); }

BOOL test0 = [self luhnCheck:@"49927398716"]; //Result = YES BOOL test1 = [self luhnCheck:@"49927398717"]; //Result = NO BOOL test2 = [self luhnCheck:@"1234567812345678"]; //Result = NO BOOL test3 = [self luhnCheck:@"1234567812345670"]; //Result = YES</lang>

OCaml

<lang ocaml>let luhn s =

 let rec g r c = function
 | 0 -> r
 | i ->
     let d = c * ((int_of_char s.[i-1]) - 48) in 
     g (r + (d/10) + (d mod 10)) (3-c) (i-1)
 in
 (g 0 1 (String.length s)) mod 10 = 0
</lang>
Output:

<lang ocaml># List.map luhn [ "49927398716"; "49927398717"; "1234567812345678"; "1234567812345670" ];; - : bool list = [true; false; false; true]</lang>

Octave

<lang Octave> function y = isluhn(s); if isnumeric(s) s = mat2str(s); end; % make sure s is a string d = s-'0'; % convert string into vector of digits m = [2:2:8,1:2:9]; % rule 3: maps [1:9] -> i y = ~mod(sum(d(end:-2:1)) + sum(m(d(end-1:-2:1))),10);

  end; </lang>
Output:

<lang octave> isluhn('49927398716') ans = 1

 isluhn('49927398717')

ans = 0

 isluhn('1234567812345678')

ans = 0

 isluhn('1234567812345670')

ans = 1 </lang>

Oforth

<lang Oforth>: luhnTest(n) | s i |

  n asString reverse ->s
  0 s size loop: i [ 
     i s at asDigit 
     i isEven ifTrue: [ 2 * dup 10 >= ifTrue: [ 9 - ] ] +
     ]
  10 mod ==0 ; </lang>
Output:
[ 49927398716, 49927398717, 1234567812345678, 1234567812345670 ] map(#luhnTest) println
[1, 0, 0, 1]

OpenEdge/Progress

<lang progress>FUNCTION fnLuhnAlgorithm RETURNS LOGICAL

 (INPUT pcNumber AS CHARACTER):

/*------------------------------------------------------------------------------

 Purpose:  Applies Luhn Algorithm to check a Number 
   Notes:  Returns True/False Validation based on check digit

*/

   DEFINE VARIABLE cNum        AS CHARACTER NO-UNDO.
   DEFINE VARIABLE iCheck      AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iLength     AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iLoopCnt    AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iNum        AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iNum1       AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iNum2       AS INTEGER   NO-UNDO.
   DEFINE VARIABLE iTestLength AS INTEGER   NO-UNDO.
   ASSIGN 
     iLength     = LENGTH(pcNumber)
     iTestLength = iLength - 1
       iCheck = 1. /* 1 for the check digit we skip */
   DO iLoopCnt = iTestLength TO 1 BY -1:
     ASSIGN 
         iNum = INTEGER(SUBSTR(pcNumber,iLoopCnt,1))
         iCheck = iCheck + 1.
     IF iCheck MODULO 2 = 1 THEN
         ASSIGN iNum1 = iNum1 + iNum.
     ELSE
     DO:
         ASSIGN iNum2 = iNum * 2.
         IF iNum2 < 10 THEN
             ASSIGN iNum1 = iNum1 + iNum2.
         ELSE
             ASSIGN
               cNum  = STRING(iNum2)
               iNum1 = iNum1 + INTEGER(SUBSTR(cNum,1,1)) + INTEGER(SUBSTR(cNum,2,1)).   
     END.
   END.
   ASSIGN 
       iNum2 = iNum1 * 9
       iNum = iNum2 MODULO 10.
   
   IF iNum = INTEGER(SUBSTR(pcNumber,iLength,1)) THEN
     RETURN TRUE.
   ELSE
     RETURN FALSE.

END FUNCTION. /* fnLuhnAlgorithm */</lang>

Output:
49927398716      - yes
49927398717      - no
1234567812345678 - no
1234567812345670 - yes

Order

This example highlights Order's unusual treatment of numbers. Numbers larger than 100 are not recognized by the interpreter in literal form and must instead be entered as "native" numbers (i.e. listing the separate digits as arguments to 8nat). Since internally, a native number is just a sequence of the digits in reverse order with an end digit marker, converting the number into a reversed list of digits mainly involves removing this terminator, so that we can immediately treat the digits as number elements. <lang c>#include <order/interpreter.h>

  1. define ORDER_PP_DEF_8luhn ORDER_PP_FN( \

8fn(8N, 8if(8is_seq(8N), 8luhn_wk(8num_to_seq(8N)), 8false)) )

  1. define ORDER_PP_DEF_8num_to_seq ORDER_PP_FN( \

8fn(8N, 8seq_push_back(8seq(8seq_last(8N)), 8seq_pop_back(8N))) )

  1. define ORDER_PP_DEF_8luhn_wk ORDER_PP_FN( \

8fn(8N, \

   8lets((8P, 8unzip(8N, 8nil, 8nil, 8true))                   \
         (8O, 8seq_fold(8plus, 0, 8tuple_at_0(8P)))            \
         (8E, 8seq_fold(8plus, 0,                              \
                        8seq_map(8dig_map, 8tuple_at_1(8P)))), \
         8is_0(8remainder(8plus(8O, 8E), 10)))) )
  1. define ORDER_PP_DEF_8dig_map ORDER_PP_FN( \

8fn(8X, 8tuple_at(8X, 8tuple(0,2,4,6,8,1,3,5,7,9))) )

  1. define ORDER_PP_DEF_8unzip ORDER_PP_FN( \

8fn(8S, 8L, 8R, 8O, \

   8if(8is_nil(8S),                                                 \
       8pair(8L, 8R),                                               \
       8if(8O,                                                      \
           8unzip(8seq_tail(8S), 8seq_push_back(8seq_head(8S), 8L), \
                  8R, 8false),                                      \
           8unzip(8seq_tail(8S), 8L,                                \
                  8seq_push_back(8seq_head(8S), 8R), 8true)))) )

ORDER_PP(8seq_to_tuple(

 8seq_map(8luhn, 8seq(8nat(4,9,9,2,7,3,9,8,7,1,6),
                      8nat(4,9,9,2,7,3,9,8,7,1,7),
                      8nat(1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8),
                      8nat(1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,0)))

))</lang>

Output:

<lang>(8true,8false,8false,8true)</lang>

Oz

<lang oz>declare

 fun {Luhn N}
    {Sum {List.mapInd {Reverse {Digits N}}
          fun {$ Idx Dig}
             if {IsEven Idx} then {Sum {Digits 2*Dig}}
             else Dig
             end
          end}}
    mod 10 == 0
 end
 fun {Digits N}
    {Map {Int.toString N} fun {$ D} D - &0 end}
 end
 fun {Sum Xs}
    {FoldL Xs Number.'+' 0}
 end

in

 {Show
  {Map
   [49927398716 49927398717 1234567812345678 1234567812345670]
   Luhn}}</lang>

Pascal

<lang 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.</lang>

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

Perl

<lang perl>sub luhn_test {

       my @rev = reverse split //,$_[0];
       my ($sum1,$sum2,$i) = (0,0,0);
       for(my $i=0;$i<@rev;$i+=2)
       {
               $sum1 += $rev[$i];
               last if $i == $#rev;
               $sum2 += 2*$rev[$i+1]%10 + int(2*$rev[$i+1]/10);
       }
       return ($sum1+$sum2) % 10 == 0;

} print luhn_test('49927398716'); print luhn_test('49927398717'); print luhn_test('1234567812345678'); print luhn_test('1234567812345670');</lang>

Or using map( ) and a precomputed array:

<lang Perl>sub luhn {

   my (@n,$i,$sum) = split //, reverse $_[0];
   my @a = map {int(2*$_ / 10) + (2*$_ % 10)} (0..9);
   map {$sum += $i++ % 2 ? $a[$_] : $_} @n;
   return ($sum % 10) ? 0 : 1;

}

  1. Test and display

map {print luhn($_), ": $_\n"}

   qw(49927398716 49927398717 1234567812345678 1234567812345670);</lang>
Output:
1: 49927398716
0: 49927398717
0: 1234567812345678
1: 1234567812345670

Phix

<lang Phix>function Luhn(string st) integer s=0, d

   for i=1 to length(st) do
       d = st[i]-'0'
       s += iff(mod(i,2)?d,d*2-(d>4)*9)
   end for
   return remainder(s,10)=0

end function

procedure test(string s)

   printf(1,"%20s : %s\n",{s,iff(Luhn(reverse(s))?"OK":"FAIL")})

end procedure

test("49927398716") test("49927398717") test("1234567812345678") test("1234567812345670")</lang>

Output:
         49927398716 : OK
         49927398717 : FAIL
    1234567812345678 : FAIL
    1234567812345670 : OK

PHP

Translation of: C

<lang php>$numbers = "49927398716 49927398717 1234567812345678 1234567812345670"; foreach (split(' ', $numbers) as $n)

   echo "$n is ", luhnTest($n) ? 'valid' : 'not valid', '
';

function luhnTest($num) {

   $len = strlen($num);
   for ($i = $len-1; $i >= 0; $i--) {
       $ord = ord($num[$i]);
       if (($len - 1) & $i) {
           $sum += $ord;
       } else {
           $sum += $ord / 5 + (2 * $ord) % 10;
       }
   }       
   return $sum % 10 == 0;

}</lang>

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

And a more concise example using PHP core methods: <lang php>function luhn_test($num) {

   $str = ;
   foreach( array_reverse( str_split( $num ) ) as $i => $c ) $str .= ($i % 2 ? $c * 2 : $c );
   return array_sum( str_split($str) ) % 10 == 0;

}

foreach (array('49927398716','49927398717','1234567812345678','1234567812345670') as $n)

   echo "$n is ", luhn_test($n) ? 'valid' : 'not valid', "
\n";</lang>
Output:
49927398716 is valid
49927398717 is not valid
1234567812345678 is not valid
1234567812345670 is valid

PicoLisp

<lang PicoLisp>(de luhn (Num) # 'Num' may be a number or a string

  (=0
     (%
        (sum
           '((C F)
              (setq C (- (char C) 48))
              (if F
                 C                               # Odd
                 (+ (/ C 5) (% (* 2 C) 10)) ) )  # Even
           (flip (chop Num))
           '(T NIL .) )
        10 ) ) )</lang>
Output:
: (mapcar luhn (49927398716 49927398717 1234567812345678 1234567812345670))
-> (0 NIL NIL 0)

PL/I

<lang pli>test: procedure options (main);

  declare (cardnumber, rcn) character (20) varying;
  declare (i, k, s1, s2) fixed binary;
  get edit (cardnumber) (L);
  cardnumber = trim(cardnumber);
  rcn = reverse(cardnumber);
  s1, s2 = 0;
  /* Sum the odd-numbered digits */
  do i = 1 to length(rcn) by 2;
     s1 = s1 + substr(rcn, i, 1);
  end;
  /* Twice the even-numbered digits. */
  do i = 2 to length(rcn) by 2;
     k = 2 * substr(rcn, i, 1);
     s2 = s2 + mod(k,10) + trunc(k/10);
  end;
  if mod(s1 + s2, 10) = 0 then
     put skip edit (cardnumber, ' passes the Luhn test' )(a);
  else
     put skip edit (cardnumber, ' does not pass the Luhn test' )(a);
  put skip list (s1 + s2);

end test;</lang>

Output:
49927398716 passes the Luhn test
       70 
49927398717 does not pass the Luhn test
       71 
1234567812345678 does not pass the Luhn test
       68 
1234567812345670 passes the Luhn test
       60

Comment: it isn't necessary to reverse the string in order to perform the test.

PL/SQL

<lang PLSQL>FUNCTION algoLuhn ( p_numeroVerif VARCHAR2 )

   RETURN NUMBER
 IS
   i         NUMBER;
   v_NBi     SMALLINT;
   v_retour  SMALLINT;
   v_somme   NUMBER := 0;
   v_nbCar   NUMBER;
   
 BEGIN  
   v_nbCar := LENGTH(p_numeroVerif);    
   
   FOR i IN 1..v_nbCar
   LOOP
       v_NBi := TO_NUMBER(SUBSTR(p_numeroVerif,v_nbCar+1-i,1));
       
       v_somme := v_somme
                 + MOD(i,2)   * v_NBi
                 + MOD(i+1,2) * SIGN(-SIGN(v_Nbi-4)+1) * (2*v_NBi)
                 + MOD(i+1,2) * SIGN( SIGN(v_Nbi-5)+1) * (2*v_NBi-9);
    
   END LOOP;
       
   v_retour := SIGN(MOD(v_somme,10));
   
   RETURN v_retour;
 
 EXCEPTION
   WHEN OTHERS
     THEN
       RETURN 1;
       
 END algoLuhn;</lang>

Plain English

<lang plainenglish>To run: Start up. Test whether "49927398716" will pass the luhn test. Test whether "49927398717" will pass the luhn test. Test whether "1234567812345678" will pass the luhn test. Test whether "1234567812345670" will pass the luhn test. Wait for the escape key. Shut down.

To test whether a string will pass the luhn test: Write the string then ": " on the console without advancing. If the string will pass the luhn test, write "valid" on the console; exit. Write "invalid" on the console.

A sum is a number.

To decide if a string will pass the luhn test: If the string is blank, say no. Privatize the string. Reverse the string. Put 0 into a first sum. Put 0 into a second sum. Put 1 into a count. Slap a rider on the string. Loop. If the rider's source is blank, break. Put the rider's source's first's target into a byte. If the byte is not any digit, say no. Convert the byte to a number. If the count is odd, add the number to the first sum; bump the count; bump the rider; repeat. Double the number. If the number is greater than 9, digital root the number. Add the number to the second sum. Bump the count. Bump the rider. Repeat. If the first sum plus the second sum is evenly divisible by 10, say yes. Say no.

To digital root a number: Divide the number by 10 giving a quotient and a remainder. Put the quotient plus the remainder into the number.

To convert a byte to a number: If the byte is any digit, put the byte minus 48 into the number.</lang>

Output:
49927398716: valid
49927398717: invalid
1234567812345678: invalid
1234567812345670: valid

PowerBASIC

Translation of: Visual Basic

<lang powerbasic>#COMPILE EXE

  1. DIM ALL
  2. COMPILER PBCC 6

FUNCTION LuhnCheckPassed(BYVAL dgts AS STRING) AS INTEGER LOCAL i, s, s1 AS DWORD

 dgts = STRREVERSE$(dgts)
   FOR i = 1 TO LEN(dgts) STEP 2
       s += VAL(MID$(dgts, i, 1))
   NEXT i
   FOR i = 2 TO LEN(dgts) STEP 2
       s1 = 2 * VAL(MID$(dgts, i, 1))
       IF s1 >= 10 THEN
           s -= 9
       END IF
       s += s1
   NEXT i
 FUNCTION = NOT ISTRUE (s MOD 10)

END FUNCTION

FUNCTION PBMAIN () AS LONG

 ' this test is expected to pass:
 CON.PRINT IIF$(LuhnCheckPassed("49927398716"), "passed", "failed")
 ' this test is expected to fail:
 CON.PRINT IIF$(LuhnCheckPassed("49927398717"), "passed", "failed")
 ' this test is expected to fail:
 CON.PRINT IIF$(LuhnCheckPassed("1234567812345678"), "passed", "failed")
 ' this test is expected to pass:
 CON.PRINT IIF$(LuhnCheckPassed("1234567812345670"), "passed", "failed")

END FUNCTION</lang>

Output:
passed
failed
failed
passed

PowerShell

<lang PowerShell> function Test-LuhnNumber {

 <#
   .SYNOPSIS
       Tests validity of credit card numbers.
   .DESCRIPTION
       Tests validity of credit card numbers using the Luhn test.
   .PARAMETER Number
       The number must be 11 or 16 digits.
   .EXAMPLE
       Test-LuhnNumber 49927398716
   .EXAMPLE
       [int64[]]$numbers = 49927398716, 49927398717, 1234567812345678, 1234567812345670
       C:\PS>$numbers | ForEach-Object {
                 "{0,-17}: {1}" -f $_,"$(if(Test-LuhnNumber $_) {'Is valid.'} else {'Is not valid.'})"
             }
 #>
   [CmdletBinding()]
   [OutputType([bool])]
   Param
   (
       [Parameter(Mandatory=$true,
                  Position=0)]
       [ValidateScript({$_.Length -eq 11 -or $_.Length -eq 16})]
       [ValidatePattern("^\d+$")]
       [string]
       $Number
   )
   $digits = ([Regex]::Matches($Number,'.','RightToLeft')).Value
   
   $digits |
       ForEach-Object `
              -Begin   {$i = 1} `
              -Process {if ($i++ % 2) {$_}} |
       ForEach-Object `
              -Begin   {$sumOdds = 0} `
              -Process {$sumOdds += [Char]::GetNumericValue($_)}
   $digits |
       ForEach-Object `
              -Begin   {$i = 0} `
              -Process {if ($i++ % 2) {$_}} |
       ForEach-Object `
              -Process {[Char]::GetNumericValue($_) * 2} |
       ForEach-Object `
              -Begin   {$sumEvens = 0} `
              -Process {
                           $_number = $_.ToString()
                           if ($_number.Length -eq 1)
                           {
                               $sumEvens += [Char]::GetNumericValue($_number)
                           }
                           elseif ($_number.Length -eq 2)
                           {
                               $sumEvens += [Char]::GetNumericValue($_number[0]) + [Char]::GetNumericValue($_number[1])
                           }
                       }
   ($sumOdds + $sumEvens).ToString()[-1] -eq "0"

} </lang> <lang PowerShell> Test-LuhnNumber 49927398716 </lang>

Output:
True

<lang PowerShell> 49927398716, 49927398717, 1234567812345678, 1234567812345670 | ForEach-Object {

   "{0,-17}: {1}" -f $_,"$(if(Test-LuhnNumber $_) {'Is valid.'} else {'Is not valid.'})"

} </lang>

Output:
49927398716      : Is valid.
49927398717      : Is not valid.
1234567812345678 : Is not valid.
1234567812345670 : Is valid.

PureBasic

<lang PureBasic>DataSection

 Sample:
 Data.s "49927398716"
 Data.s "49927398717"
 Data.s "1234567812345678"
 Data.s "1234567812345670"
 Data.s ""

EndDataSection

Procedure isValid(cardNumber.s)

 Protected i, length, s1, s2, s2a
 
 cardNumber = ReverseString(cardNumber)
 length = Len(cardNumber)
 For i = 1 To length Step 2
   s1 + Val(Mid(cardNumber, i, 1))
 Next 
 For i = 2 To length Step 2
   s2a = Val(Mid(cardNumber, i, 1)) * 2
   If s2a < 10
     s2 + s2a
   Else
     s2 + 1 + Val(Right(Str(s2a), 1))
   EndIf 
 Next 
 
 If Right(Str(s1 + s2), 1) = "0"
   ProcedureReturn #True
 Else
   ProcedureReturn #False
 EndIf 

EndProcedure


If OpenConsole()

 Define cardNumber.s
 
 Restore Sample
 Repeat 
   Read.s cardNumber
   If cardNumber <> ""
     Print(cardNumber + " is ")
     If isValid(cardNumber)
       PrintN("valid")
     Else
       PrintN("not valid")
     EndIf
   EndIf
 Until cardNumber = ""
 
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
 Input()
 CloseConsole()

EndIf</lang>

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

Python

Functional

The divmod in the function below conveniently splits a number into its two digits ready for summing: <lang python>>>> def luhn(n): r = [int(ch) for ch in str(n)][::-1] return (sum(r[0::2]) + sum(sum(divmod(d*2,10)) for d in r[1::2])) % 10 == 0

>>> for n in (49927398716, 49927398717, 1234567812345678, 1234567812345670): print(n, luhn(n))</lang>

Output:
49927398716 True
49927398717 False
1234567812345678 False
1234567812345670 True

Or, using itertools cycle with map and reduce:

Works with: Python version 3.7

<lang python>Luhn test of credit card numbers

from operator import add, mul from functools import reduce from itertools import cycle


  1. luhn :: Integer -> Bool

def luhn(n):

   True if n is a valid Luhn credit card number.
   def divMod10Sum(a, x):
       return a + add(*divmod(x, 10))
   return 0 == reduce(
       divMod10Sum,
       map(
           mul,
           cycle([1, 2]),
           map(int, reversed(str(n)))
       ),
       0
   ) % 10


  1. ---------------------------TEST---------------------------
  2. main :: IO ()

def main():

   Tests
   print(list(
       map(luhn, [
           49927398716, 49927398717,
           1234567812345678, 1234567812345670
       ])
   ))


if __name__ == '__main__':

   main()</lang>
Output:
[True, False, False, True]

Or alternatively, we can prune out some of the imports, define the Luhn predicate over strings rather than integers,

and cycle lambdas rather than integers.

<lang python>Luhn test of credit card numbers

from itertools import cycle


  1. luhn :: String -> Bool

def luhn(k):

   True if k is a valid Luhn credit card number string
   
   def asDigits(s):
       return (int(c) for c in s)
   return 0 == sum(map(
       lambda f, x: f(x),
       cycle([
           lambda n: n,
           lambda n: sum(asDigits(str(2 * n)))
       ]),
       asDigits(reversed(k))
   )) % 10


  1. ------------------------- TEST -------------------------
  2. main :: IO ()

def main():

   Tests
   print('\n'.join([
       repr((x, luhn(x))) for x in [
           "49927398716",
           "49927398717",
           "1234567812345678",
           "1234567812345670"
       ]
   ]))


if __name__ == '__main__':

   main()

</lang>

Output:
('49927398716', True)
('49927398717', False)
('1234567812345678', False)
('1234567812345670', True)

Procedural

Without usingsum() and divmod() functions: <lang python>>>> def vérifLuhn(ch):

 sum = 0
 chParity = len(ch) % 2
 for i in range (len(ch)-1, -1, -1):
   j = int(ch[i])
   if ((i + 1) % 2 != chParity):
     j = j * 2 
   if (j > 9):
     j = j - 9 
   sum = sum + j
 print("value calculated = ", str(sum))
 return sum % 10 == 0         
  

for n in (49927398716, 49927398717, 1234567812345678, 1234567812345670):

       print (str(n)+" =>", vérifLuhn(str(n)))

</lang>

Q

<lang q>sd:{s:0; while[x<>0; s+:x mod 10; x:floor x%10]; s} / Sum digits of x luhn:{

   r:reverse string x;                             / Reversed credit card number
   o:("I"$) each r[2*til ceiling (count r) % 2];   / Odd-indexed numbers
   e:("I"$) each r[1+2*til floor (count r) % 2];   / Even-indexed numbers
   0=(sum o,sd each e*2) mod 10                    / Return 1b if checksum ends in 0; 0b otherwise

}</lang>

Output:
q)luhn each  49927398716 49927398717 1234567812345678 1234567812345670
1001b

Quackery

<lang Quackery> [ 1 & ] is odd ( n --> b )

 [ [] swap
   [ 10 /mod 
     rot join swap
     dup 0 = until ]
     drop ]            is digits     ( n --> [   )
 [ [] [] rot
   dup size odd dip
   [ witheach 
       [ nested join 
         swap ] ]
   not if swap ]       is unzip      ( [ --> [ [ )
 [ [] swap
   witheach
     [ 2 * 
       10 /mod + 
       join ] ]        is 2*digitsum ( [ --> [   )
 [ behead swap
   witheach + ]        is sum        ( [ --> n   )
 [ digits 
   reverse
   unzip
   2*digitsum
   sum 
   swap sum
   + 10 mod 0 = ]      is luhn       ( n --> b   )


' [ 49927398716 49927398717

   1234567812345678 1234567812345670 ]

witheach

 [ dup echo
   luhn iff
     [ say " valid" ]
   else
     [ say " invalid" ]
   cr ]</lang>
Output:
49927398716 valid
49927398717 invalid
1234567812345678 invalid
1234567812345670 valid

R

<lang rsplus> is.luhn <- function(cc){

 numbers <- as.numeric(rev(unlist(strsplit(cc,""))))
 (sum(numbers[seq(1,length(numbers),by=2)]) + sum({numbers[seq(2,length(numbers),by=2)]*2 ->.;  .%%10 +.%/%10})) %% 10 == 0

}

sapply(c("49927398716","49927398717","1234567812345678","1234567812345670"),is.luhn)

</lang>

Output:
sapply(c("49927398716","49927398717","1234567812345678","1234567812345670"),is.luhn)
     49927398716      49927398717 1234567812345678 1234567812345670 
            TRUE            FALSE            FALSE             TRUE 

Racket

<lang Racket>

  1. lang racket

(define (luhn-test n)

 (let loop ([n n] [odd? #t] [s 0])
   (if (zero? n)
     (zero? (modulo s 10))
     (let*-values ([(q r)   (quotient/remainder n 10)]
                   [(rq rr) (quotient/remainder (* (if odd? 1 2) r) 10)])
       (loop q (not odd?) (+ s rq rr))))))

(map luhn-test '(49927398716 49927398717 1234567812345678 1234567812345670))

-> '(#t #f #f #t)

</lang>

Raku

(formerly Perl 6)

Works with: rakudo version 2015-11-29

Here we make use of comb, which splits into individual characters, and the sequence operator ..., which can intuit an even or odd sequence from the first two values. %% is the divisible-by operator.

<lang perl6>sub luhn-test ($number --> Bool) {

   my @digits = $number.comb.reverse;
   my $sum = @digits[0,2...*].sum
           + @digits[1,3...*].map({ |($_ * 2).comb }).sum;
   return $sum %% 10;

}

  1. And we can test it like this:

use Test;

my @cc-numbers =

   '49927398716'       => True,
   '49927398717'       => False,
   '1234567812345678'  => False,
   '1234567812345670'  => True;

plan @cc-numbers.elems;

for @cc-numbers».kv -> ($cc, $expected-result) {

   is luhn-test(+$cc), $expected-result,
       "$cc {$expected-result ?? 'passes' !! 'does not pass'} the Luhn test.";

}</lang>

Output:
1..4
ok 1 - 49927398716 passes the Luhn test.
ok 2 - 49927398717 does not pass the Luhn test.
ok 3 - 1234567812345678 does not pass the Luhn test.
ok 4 - 1234567812345670 passes the Luhn test.

REXX

version 1

<lang REXX>/*REXX program validates credit card numbers using the Luhn algorithm. */

  1. .=; #.1= 49927398716 /*the 1st sample credit card number. */
                   #.2= 49927398717             /* "   2nd     "      "     "     "    */
                   #.3= 1234567812345678        /* "   3rd     "      "     "     "    */
                   #.4= 1234567812345670        /* "   4th     "      "     "     "    */
     do k=1  while #.k\==                     /*validate all the credit card numbers.*/
     say right( Luhn(#.k), 9)          ' the Luhn test, credit card number: '    #.k
     end   /*k*/                                /* [↑] function returns passed│flunked.*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ Luhn: procedure; parse arg x; $= 0 /*get credit card number; zero $ sum. */

     y= reverse( left(0, length(x) // 2)x)      /*add leading zero if needed, reverse. */
             do j=1  to length(y)-1  by 2;                _= substr(y, j+1, 1) * 2
             $= $ + substr(y, j, 1) + left(_, 1) + substr(_, 2, 1, 0)     /* ◄────────┐*/
             end   /*j*/                       /*sum odd and even decimal digits ►────┘*/
     return word('passed flunked',1+($//10==0)) /*$ ending in zero?  Then the # passed.*/</lang>
output   when using the (internal) default inputs:
  flunked  the Luhn test, credit card number:  49927398716
   passed  the Luhn test, credit card number:  49927398717
   passed  the Luhn test, credit card number:  1234567812345678
  flunked  the Luhn test, credit card number:  1234567812345670

Version 2

<lang REXX>/* Rexx ***************************************************

  • 09.04.2013 Walter Pachl
  • Implements the task's description in a rather concise way
  • Instead of reverting the ccn work it backwards
                                                                                                                    • /

numeric digits 20

push 49927398716 push 49927398717 push 1234567812345678 push 1234567812345670

do while queued() > 0

 parse pull ccnum
 if luhn(ccnum) then ln = 'passed'
 else                ln = 'failed'
 say right(ccnum, 20) ln
 end

return exit

luhn: Parse Arg ccn /* credit card number */ sum=0 /* initialize test sum */ even=0 /* even indicator */ Do i=length(ccn) To 1 By -1 /* process all digits */

 c=substr(ccn,i,1)          /* pick one digit at a time */
 If even Then Do            /* even numbered digit      */
   c=c*2                    /* double it                */
   If c>=10 Then            /* 10, 12, 14, 16, 18       */
     c=c-9                  /* Sum of the two digits    */
   End                      /* end of even numbered     */
 even=\even                 /* flip even indicator      */
 sum=sum+c                  /* add into test sum        */
 End

Return right(sum,1)=0 /* ok if last digit is 0 */ </lang>

Output:
    1234567812345670 passed
    1234567812345678 failed
         49927398717 failed
         49927398716 passed

Ring

<lang ring>decimals(0)

test = ["49927398716", "49927398717", "1234567812345678", "1234567812345670"] for n = 1 to len(test)

     see test[n] + " -> " + cardtest(test[n]) + nl

next

func cardtest(numstr)

       revstring = revstr(numstr)
       s1 = revodd(revstring)
       s2 = reveven(revstring)
       s3 =right(string(s1+s2), 1)
       if s3 = "0"
          return "Valid"
       else
          return "Invalid"
       ok

func revstr(str)

     strnew = ""
     for nr = len(str) to 1 step -1
          strnew = strnew + str[nr]
     next
     return strnew

func revodd(str)

       strnew = ""
       for nr = 1 to len(str) step 2
            strnew = strnew + str[nr]
       next
       sumodd = 0
       for p = 1 to len(strnew)
             sumodd = sumodd + number(strnew[p])
       next     
       return sumodd

func reveven(str)

       strnew = ""
       for nr = 2 to len(str) step 2
            strnew = strnew + str[nr]
       next
       lsteven = []
       for p = 1 to len(strnew)
            add(lsteven, string(2*number(strnew[p])))
       next  
       arreven = list(len(lsteven))
       for q = 1 to len(lsteven)
             sum = 0
             for w = 1 to len(lsteven[q])
                   sum = sum + lsteven[q][w]
             next
             arreven[q] = sum
       next
       sumarr = 0
       for x = 1 to len(arreven)
            sumarr = sumarr + arreven[x]
       next
       return sumarr                    

</lang> Output:

49927398716 -> Valid
49927398717 -> Invalid
1234567812345678 -> Invalid
1234567812345670 -> Valid

Ruby

<lang ruby> def luhn_valid?(str)

  str.scan(/\d/).reverse            #using str.to_i.digits fails for cases with leading zeros
     .each_slice(2)
     .sum { |i, k = 0| i.to_i + ((k.to_i)*2).digits.sum }
     .modulo(10).zero?
end

["49927398716", "49927398717", "1234567812345678", "1234567812345670"].map{ |i| luhn_valid?(i) } </lang>

Output:
[true, false, false, true]

Simpler Alternative <lang ruby>def luhn_valid?(n) # Card values can be numbers or strings

 d2sum = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
 sum, num = 0, n.to_i
 num.digits.each_with_index { |digit, i| sum += i.even? ? digit : d2sum[digit] }
 sum % 10 == 0

end

cards = [49927398716, "49927398717", 1234567812345678, "1234567812345670"] cards.each{ |i| puts "#{i}: #{luhn_valid?(i)}" }</lang>

Output:
49927398716: true
49927398717: false
1234567812345678: false
1234567812345670: true

Run BASIC

<lang runbasic>card$(1) = "49927398716" card$(2) = "49927398717" card$(3) = "1234567812345678" card$(4) = "1234567812345670"

for i = 1 to 4 print card$(i);" ";luhn$(card$(i)) next i

FUNCTION luhn$(card$)

   lc      = len(card$)
   for i   = lc to 1 step -1
     digit = val(mid$(card$,i,1))
     if ((lc -i) mod 2) = 0 then chkSum = chkSum + digit else chkSum = chkSum + int(digit * 2.2)
   next i
   if chkSum mod 10 = 0 then luhn$ = "True" else luhn$ = "False"

end function</lang>

Output:
49927398716 True
49927398717 False
1234567812345678 False
1234567812345670 True

Rust

<lang rust>extern crate luhn_test_of_credit_card_numbers;

use luhn_test_of_credit_card_numbers::luhn_test;

fn validate_isin(isin: &str) -> bool {

   if !isin.chars().all(|x| x.is_alphanumeric()) || isin.len() != 12 {
       return false;
   }
   if !isin[..2].chars().all(|x| x.is_alphabetic())
       || !isin[2..12].chars().all(|x| x.is_alphanumeric())
       || !isin.chars().last().unwrap().is_numeric()
   {
       return false;
   }
   let bytes = isin.as_bytes();
   let s2 = bytes
       .iter()
       .flat_map(|&c| {
           if c.is_ascii_digit() {
               vec![c]
           } else {
               (c + 10 - ('A' as u8)).to_string().into_bytes()
           }
       })
       .collect::<Vec<u8>>();
   let string = std::str::from_utf8(&s2).unwrap();
   let number = string.parse::<u64>().unwrap();
   return luhn_test(number as u64);

}

  1. [cfg(test)]

mod tests {

   use super::validate_isin;
   #[test]
   fn test_validate_isin() {
       assert_eq!(validate_isin("US0378331005"), true);
       assert_eq!(validate_isin("US0373831005"), false);
       assert_eq!(validate_isin("U50378331005"), false);
       assert_eq!(validate_isin("US03378331005"), false);
       assert_eq!(validate_isin("AU0000XVGZA3"), true);
       assert_eq!(validate_isin("AU0000VXGZA3"), true);
       assert_eq!(validate_isin("FR0000988040"), true);
   }

}</lang>

Output:
49927398716: true
49927398717: false
1234567812345678: false
1234567812345670: true

Scala

Library: Scala

Functional style

<lang scala>object Luhn {

 private def parse(s: String): Seq[Int] = s.map{c =>
   assert(c.isDigit)
   c.asDigit
 }
 def checksum(digits: Seq[Int]): Int = {
   digits.reverse.zipWithIndex.foldLeft(0){case (sum,(digit,i))=>
     if (i%2 == 0) sum + digit
     else sum + (digit*2)/10 + (digit*2)%10
   } % 10
 }
 def validate(digits: Seq[Int]): Boolean = checksum(digits) == 0
 def checksum(number: String): Int = checksum(parse(number))
 def validate(number: String): Boolean = validate(parse(number))

}

object LuhnTest extends App {

 Seq(("49927398716", true),
   ("49927398717", false),
   ("1234567812345678", false),
   ("1234567812345670", true)
 ).foreach { case (n, expected) =>
   println(s"$n ${Luhn.validate(n)}")
   assert(Luhn.validate(n) == expected)
 }

}</lang>

Output:
49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true

Imperative style

<lang scala> def luhnTest1(number: String): Boolean = {

   var (odd, sum) = (true, 0)
   for (int <- number.reverse.map { _.toString.toShort }) {
     if (odd) sum += int
     else sum += (int * 2 % 10) + (int / 5)
     odd = !odd
   }
   sum % 10 == 0
 }</lang>

Scheme

<lang scheme>(define luhn

 (lambda (n)
   (let loop ((number n)
              (index 0)
              (result 0))
     (if (= 0 number)
         (= 0 (remainder result 10))
         (loop (quotient number 10)
               (+ index 1)
               (+ result
                  (if (even? index)
                      (remainder number 10)
                      (let ((part (* 2 (remainder number 10))))
                        (+ (remainder part 10) (quotient part 10))))))))))</lang>
Output:
(map luhn '(49927398716 49927398717 1234567812345678 1234567812345670))
(#t #f #f #t)

sed

<lang sed># Split number into double evens and odds s/.*/&: /

split

s/\([0-4]\)\([0-9]\):\(.*\) /:\1\1\3 \2/ s/\([5-9]\)\([0-9]\):\(.*\) /:1\1\1\3 \2/ t split

  1. Set up addition lookup table

s/\([0-9]\)*:\(.*\) \(.*\)/\1\2\3:0123456789012345678/

add

s/\([0-9]\)0:/\1:/ s/\([0-9]\)1:\(.*\1.\{0\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)2:\(.*\1.\{1\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)3:\(.*\1.\{2\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)4:\(.*\1.\{3\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)5:\(.*\1.\{4\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)6:\(.*\1.\{5\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)7:\(.*\1.\{6\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)8:\(.*\1.\{7\}\([0-9]\).*\)/\3:\2/ s/\([0-9]\)9:\(.*\1.\{8\}\([0-9]\).*\)/\3:\2/ t add

/0:/a\ Pass /0:/!a\ Fail d</lang>

Output:
$ sed -f luhn.sed <<!
49927398716
49927398717
1234567812345678
1234567812345670
!
Pass
Fail
Fail
Pass

Seed7

<lang seed7>$ include "seed7_05.s7i";

const func boolean: luhnTest (in string: cardNumber) is func

 result
   var boolean: luhnTest is FALSE;
 local
   var integer: index is 0;
   var integer: digit is 0;
   var boolean: isOdd is TRUE;
   var integer: oddSum is 0;
   var integer: evenSum is 0;
 begin
   for index range length(cardNumber) downto 1 do
     digit := integer parse str(cardNumber[index]);
     if isOdd then
       oddSum +:= digit;
     else
       evenSum +:= digit div 5 + (2 * digit) rem 10;
     end if;
     isOdd := not isOdd;
   end for;
   luhnTest := (oddSum + evenSum) rem 10 = 0;
 end func;

const proc: main is func

 local
   var string: cardNumber is "";
 begin
   for cardNumber range [] ("49927398716", "49927398717", "1234567812345678", "1234567812345670") do
     writeln(cardNumber <& ": " <& luhnTest(cardNumber));
   end for;
 end func;</lang>
Output:
49927398716: TRUE
49927398717: FALSE
1234567812345678: FALSE
1234567812345670: TRUE

SenseTalk

<lang sensetalk>function LuhnCheck ccNum put length of ccNum into numDigits put the last character of ccNum into total put numDigits modulo 2 into parity repeat for each character of the first numDigits - 1 characters of ccNum put it into digit if (the counter - 1) modulo 2 equals parity multiply digit by 2 end if if digit is greater than 9 subtract 9 from digit end if add digit to total end repeat return total is divisible by 10 end LuhnCheck</lang>

<lang sensetalk>repeat for each item of (49927398716, 49927398717, 1234567812345678, 1234567812345670) put it && LuhnCheck(it) end repeat</lang>

SequenceL

<lang sequenceL> main(args(2)) := sum(luhnTest(asciiToInt(args[1]) - asciiToInt('0'))) mod 10 = 0;

s2Mapping := [0,2,4,6,8,1,3,5,7,9];

luhnTest(x(1))[i] := x[i] when i mod 2 = size(x) mod 2 else s2Mapping[x[i] + 1]; </lang>

Shen

<lang shen> (define mapi

 _ _ []       -> []
 F N [X | Xs] -> [(F N X) | (mapi F (+ N 1) Xs)])

(define double

 X -> (let Y (* 2 X) (if (> Y 9) (- Y 9) Y)))

(define luhn?

 Number ->
   (let Exploded (explode Number)
        Digits   (map (/. H (- (string->n H) 48)) Exploded)
        Reversed (reverse Digits)
        Doubled  (mapi (/. N X (if (= 1 (shen.mod N 2)) (double X) X)) 0 Reversed)
        Summed   (sum Doubled)
        Modded   (shen.mod Summed 10)
     (= 0 Modded)))

"Expected: [true false false true]"

(map (function luhn?) ["49927398716" "49927398717" "1234567812345678" "1234567812345670"]) </lang>

Output:
mapi
transform-x
luhn?
"Expected: [true false false true]"
[true false false true]

run time: 0.014999985694885254 secs
loaded

Sidef

<lang ruby>func luhn (n) {

   static a = {|j| (2*j // 10) + (2*j % 10) }.map(^10)
   var checksum = n.digits.map_kv {|i,j|
       i.is_odd ? a[j] : j
   }.sum
   checksum % 10 == 0

}

for n in [49927398716, 49927398717, 1234567812345678, 1234567812345670] {

   say [n, luhn(n)]

}</lang>

Output:
[49927398716, true]
[49927398717, false]
[1234567812345678, false]
[1234567812345670, true]

SNOBOL4

Using a precomputed array. <lang SNOBOL4> define('luhn(n)a,d,i,j,sum') :(luhn_end) luhn n = reverse(n); a = array('0:9') ln1 a = (2 * i / 10) + remdr(2 * i,10)

       i = lt(i,9) i + 1 :s(ln1)

ln2 n len(1) . d = :f(ln3)

       d = ne(remdr(j,2),0) a<d>; j = j + 1
       sum = sum + d :(ln2)

ln3 luhn = 0; luhn = eq(remdr(sum,10),0) 1 :(return) luhn_end

  • # Test and display
       test = " output = luhn(n) ': ' n"
       n = '49927398716'; eval(test)
       n = '49927398717'; eval(test)
       n = '1234567812345678'; eval(test)
       n = '1234567812345670'; eval(test)

end</lang>

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

SPARK

Works with SPARK GPL 2010 and GPS GPL 2010.

Based on the Ada version. All code shown to be free of run-time type errors.

A final test has been added which passes as valid unless there is an explicit test for all digits. <lang ada>with Spark_IO; --# inherit Spark_IO; --# main_program; procedure Luhn --# global in out Spark_IO.Outputs; --# derives Spark_IO.Outputs from *; is

  function Luhn_Test (Num : String) return Boolean
  --# pre  Num'Last <= 20;
  is
     Sum : Integer := 0;
     Od  : Boolean := True;
     Int : Integer;
     X   : Integer;
     OK  : Boolean := True;
  begin
     for P in reverse Integer range Num'Range loop
        Int := Character'Pos(Num(P)) - Character'Pos('0');
        if Int not in 0 .. 9 then
           OK := False;
           exit;
        end if;
        X := (((Int*2) mod 10) + (Int / 5));
        --# assert Num'Last - P in 0 .. 19
        --#   and  Sum in 0 .. (Num'Last - P) * 10
        --#   and  Int in 0 .. 9
        --#   and  X   in 0 .. 10;
        if Od then
           Sum := Sum + Int;
        else
           Sum := Sum + X;
        end if;
        Od := not Od;
     end loop;
     return OK and (Sum mod 10) = 0;
  end Luhn_Test;
  procedure Do_Test (Num : in     String)
  --# global in out Spark_IO.Outputs;
  --# derives Spark_IO.Outputs from *, Num;
  --# pre  Num'Last <= 20;
  is
  begin
     Spark_IO.Put_String(Spark_IO.Standard_Output, Num, 16);
     if Luhn_Test(Num) then
        Spark_IO.Put_String(Spark_IO.Standard_Output, " is valid.", 0);
     else
        Spark_IO.Put_String(Spark_IO.Standard_Output, " is not valid.", 0);
     end if;
     Spark_IO.New_Line(Spark_IO.Standard_Output, 1);
  end Do_Test;

begin

  Do_Test("49927398716");
  Do_Test("49927398717");
  Do_Test("1234567812345678");
  Do_Test("1234567812345670");
  Do_Test("123456781234567D");

end Luhn;</lang>

Output:
49927398716      is valid.
49927398717      is not valid.
1234567812345678 is not valid.
1234567812345670 is valid.
123456781234567D is not valid.

SQL PL

Works with: Db2 LUW

With SQL PL: <lang sql pl> --#SET TERMINATOR @

SET SERVEROUTPUT ON @

CREATE OR REPLACE FUNCTION LUHN_TEST (

 IN NUMBER VARCHAR(24)
) RETURNS SMALLINT
--) RETURNS BOOLEAN
BEGIN
 DECLARE TYPE CARD_NUMBER AS VARCHAR(1) ARRAY [24];
 DECLARE LENGTH SMALLINT;
 DECLARE REVERSE CARD_NUMBER;
 DECLARE I SMALLINT;
 DECLARE POS SMALLINT;
 DECLARE S1 SMALLINT;
 DECLARE S2 SMALLINT;
 DECLARE TEMP SMALLINT;
 DECLARE RET SMALLINT;
 --DECLARE RET BOOLEAN;
 DECLARE INVALID_CHAR CONDITION FOR SQLSTATE 'LUHN1';
 -- Reverse the order of the digits in the number.
 SET LENGTH = LENGTH(NUMBER);
 SET I = 1;
 WHILE (I <= LENGTH) DO
  SET POS = LENGTH - I + 1;
  SET REVERSE[POS] = SUBSTR(NUMBER, I, 1);
  IF (ASCII(REVERSE[POS]) < 48 OR 57 < ASCII(REVERSE[POS])) THEN
   SIGNAL INVALID_CHAR SET MESSAGE_TEXT = 'Invalid character, not a digit';
  END IF;
  SET I = I + 1;
 END WHILE;
 -- Take the first, third, ... and every other odd digit in the reversed digits and sum them to form the partial sum s1
 SET S1 = 0;
 SET I = 1;
 WHILE (I <= LENGTH) DO
  IF (MOD(I, 2) = 1) THEN
   SET S1 = S1 + REVERSE[I];
  END IF;
  -- CALL DBMS_OUTPUT.PUT_LINE('I ' || I || ', S1 ' || S1 || ', val ' || REVERSE[I]);
  SET I = I + 1;
 END WHILE;

 -- Taking the second, fourth ... and every other even digit in the reversed digits:
 SET S2 = 0;
 SET TEMP = 0;
 SET I = 1;
 WHILE (I <= LENGTH) DO
  IF (MOD(I, 2) = 0) THEN
   -- Multiply each digit by two and sum the digits if the answer is greater than nine to form partial sums for the even digits
   SET TEMP = REVERSE[I] * 2;
   IF (TEMP > 9) THEN
    SET TEMP = (TEMP / 10) + (MOD(TEMP, 10));
   END IF;
   -- Sum the partial sums of the even digits to form s2
   SET S2 = S2 + TEMP;
  END IF;
  -- CALL DBMS_OUTPUT.PUT_LINE('I ' || I || ', S2 ' || S2 || ', TEMP ' || TEMP || ' val ' || REVERSE[I]);
  SET I = I + 1;
 END WHILE;
 -- 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.
 SET RET = 1;
 --SET RET = FALSE;
 SET TEMP = S1 + S2;
 IF (MOD(TEMP, 10) = 0) THEN
  SET RET = 0;
  --SET RET = TRUE;
  CALL DBMS_OUTPUT.PUT_LINE('It is a valid number ' || S1 || '+' || S2 || '=' || TEMP);
 ELSE
  CALL DBMS_OUTPUT.PUT_LINE('It is NOT a valid number ' || S1 || '+' || S2 || '=' || TEMP);
 END IF;
 RETURN RET;
END

@ </lang> Output:

db2 -td@
db2 => SET SERVEROUTPUT ON @
DB20000I  The SET SERVEROUTPUT command completed successfully.
db2 => CREATE OR REPLACE FUNCTION VALIDATE_CREDIT_CARD_NUMBER (
...
db2 (cont.) => END @
DB20000I  The SQL command completed successfully.
db2 => values VALIDATE_CREDIT_CARD_NUMBER(49927398716)@                      

1     
------
     0

  1 record(s) selected.

It is a valid number 42+28=70
db2 => VALUES VALIDATE_CREDIT_CARD_NUMBER(49927398717)@

1     
------
     1

  1 record(s) selected.

It is NOT a valid number 43+28=71
db2 => VALUES VALIDATE_CREDIT_CARD_NUMBER(1234567812345678)@

1     
------
     1

  1 record(s) selected.

It is NOT a valid number 40+28=68
db2 => VALUES VALIDATE_CREDIT_CARD_NUMBER(1234567812345670)@

1     
------
     0

  1 record(s) selected.

It is a valid number 32+28=60

Standard ML

<lang sml>local

 fun revDigits 0 = []
   | revDigits n = (n mod 10) :: revDigits (n div 10)
 fun digitSum n = if n > 9 then digitSum (n div 10 + n mod 10)
                           else n
 fun luhn_sum []  = 0
   | luhn_sum [d] = d
   | luhn_sum (d::d'::ds) = d + digitSum (2*d') + luhn_sum ds

in

 fun luhn_test n = luhn_sum (revDigits n) mod 10 = 0
 val res = map luhn_test [49927398716, 49927398717, 1234567812345678, 1234567812345670];

end;

(* [opening file "luhn.sml"] > val luhn_test = fn : int -> bool

 val res = [true, false, false, true] : bool list

[closing file "luhn.sml"]

  • )</lang>

Swift

<lang swift>func luhn(_ number: String) -> Bool {

   return number.reversed().enumerated().map({
       let digit = Int(String($0.element))!
       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</lang>

Tcl

Based on an algorithmic encoding for the test on Wikipedia. <lang tcl>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}]

}</lang> Driver: <lang tcl>foreach testNumber {

   49927398716
   49927398717
   1234567812345678
   1234567812345670

} {

   puts [format "%s is %s" $testNumber \

[lindex {"NOT valid" "valid"} [luhn $testNumber]]] }</lang>

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

Terraform

<lang hcl>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

}</lang>

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

<lang ti83b>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

</lang>

Transact-SQL

<lang 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 </lang>

TUSCRIPT

<lang 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</lang>

Output:
49927398716       true
49927398717       false
1234567812345678  false
1234567812345670  true 

TXR

<lang 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)</lang>

$ txr luhn.txr luhn.txt
49927398716 -> good
49927398717 -> bad
1234567812345678 -> bad
1234567812345670 -> good

UNIX Shell

Works with: bash
Works with: ksh

<lang bash>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</lang>

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

<lang Ursala>#import std

  1. import nat

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

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: <lang ursala>#cast %bL

test = luhn* <49927398716,49927398717,1234567812345678,1234567812345670></lang>

Output:
<true,false,false,true>

VBA

<lang VB> 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</lang>

Output:
Number 49927398716 is valid
Number 49927398717 is invalid
Number 1234567812345678 is invalid
Number 1234567812345670 is valid

VBScript

<lang 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")</lang>

Output:
49927398716 is Valid
49927398717 is Invalid
1234567812345678 is Invalid
1234567812345670 is Valid

Visual Basic

Works with: Visual Basic version VB6 Standard

<lang vb>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</lang>

Test: <lang vb>Sub Main()

 Debug.Assert LuhnCheckPassed("49927398716")
 Debug.Assert Not LuhnCheckPassed("49927398717")
 Debug.Assert Not LuhnCheckPassed("1234567812345678")
 Debug.Assert LuhnCheckPassed("1234567812345670")

End Sub</lang>

Visual Basic .NET

<lang 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

</lang>

Output:
True
False
False
True

Wren

Library: Wren-fmt
Library: Wren-trait

<lang ecmascript>import "/fmt" for Fmt import "/trait" 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"
   System.print("%(Fmt.s(-16, test)) -> %(ans)")

}</lang>

Output:
49927398716      -> pass
49927398717      -> fail
1234567812345678 -> fail
1234567812345670 -> pass

Xojo

<lang 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 </lang>

Output:
ValididateMod10( "49927398716" ) = True
ValididateMod10( "49927398717" ) = False
ValididateMod10( "1234567812345678" ) = False
ValididateMod10( "1234567812345670" ) = True

XPL0

<lang 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);
       ];

]</lang>

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

zkl

<lang 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)

}</lang> <lang zkl>T(49927398716,49927398717,1234567812345678,1234567812345670) .apply(luhnTest).println();</lang>

Output:
L(True,False,False,True)

ZX Spectrum Basic

<lang ZXBasic>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 </lang>

Output:
49927398716 VALID!
49927398717 INVALID!
1234567812345678 INVALID!
1234567812345670 VALID!