g | x | w | all
Bytes Lang Time Link
055Ruby221109T225252ZJordan
010Vyxal 3250506T092454ZThemooni
085Tcl171021T200435Zsergiol
077Python 3110127T220704ZAlexandr
108PHP110127T225138ZChampo
8381Rust240806T150456Zmousetai
156Go240624T174718Zbigyihsu
082Forth gforth240701T131044Zreffu
181Rust240624T182250Zbigyihsu
071bash190323T040536Zroblogic
008Thunno 2 t!230615T180538ZThe Thon
052Zsh201211T012242Zroblogic
037><>221110T095728ZEmigna
008Vyxal221109T233919Zlyxal
nanFig221109T212415ZSeggan
005Factor + validators221107T132647Zchunes
050Julia 1.0221107T095649Zamelies
026K ngn/k201208T201618Zcoltim
061JavaScript ES6160420T204129Zedc65
172C clang210602T022005ZStack Ex
016Vyxal210604T073009Zemanresu
011Vyxal210506T210200ZAaroneou
147Pxem210505T083103Zuser1004
027x8616 machine code190326T160301Z640KB
009Jelly171021T155744Zcaird co
110C gcc201220T181621Zengineer
031GolfScript201220T005921Zcnamejj
061dc201211T163057Zjuh
013Husk201210T233401ZDominic
046R201210T232918ZDominic
033Burlesque200122T153644ZDeathInc
8382PHP190326T205811Z640KB
01005AB1E170220T152142ZEmigna
013Japt180201T104248ZShaggy
014Japt v2.0a0190327T050304ZGymhgy
074APLNARS190326T191914Zuser5898
073Haskell190310T184022ZLaikoni
011MathGolf181127T152412Zmaxb
067Julia181127T094623Zxiaodai
037Perl 6181113T084759ZJo King
120Dart181113T081126ZElcan
014Jelly180125T012443Zellie
074Powershell181112T124232Zmazzy
077Kotlin180201T094837Zjrtapsel
020Pyt180125T012409Zmudkip20
028K oK180124T233101Zmkst
020MATL170220T053855ZB. Mehta
019Pyth161025T135722ZTheBikin
041Perl160421T202345ZTon Hosp
136PHP160421T173905ZFlame
096Haskell110131T051435Zsepp2k
042Retina160420T201136ZMartin E
035K4140201T213037ZAaron Da
028APL140201T225527ZTobia
038APL140201T213505ZAaron Da
144D110203T222936ZJonathan
140GNU sed160111T181934ZToby Spe
106JavaScript 1.8130119T201019Zkojiro
097Haskell130122T170629Zuser7010
132Scala120408T040305Zuser unk
063Q120407T183500Ztmartin
119C#110128T065427Zmootinat
082Windows PowerShell110213T020811ZJoey
123PowerShell110213T013403ZTy Auvil
024Golfscript110202T165627ZNabb
034Golfscript110201T115904Zgnibbler
085Ruby110131T080810ZNemo157
069Python110129T085338ZKeith Ra
044GolfScript110129T043051ZC. K. Yo

Ruby, 55 bytes

->n{i=1
n.digits.sum{(_1.*1+(i+=1)%2).digits.sum}%10<1}

Attempt This Online!

Vyxal 3, 10 bytes

-1 byte by lyxal

f⇄UdϾWf∑①≛

Vyxal It Online!

f⇄UdϾWf∑①≛
f           # ‎⁡digits of implicit input
 ⇄          # ‎⁢reversed
  U         # ‎⁣Uninterleave
   d        # ‎⁤double the digits of 1 side of the uninterleaved (conveniently on top of stack)
    Ͼ       # ‎⁢⁡sum each
     Wf     # ‎⁢⁢wrap the stack and flatten the resulting array
       ∑    # ‎⁢⁣sum the result
        ①≛ # ‎⁢⁤is the sum divisible by 10?
💎

Created with the help of Luminespire.

<script type="vyxal3">
f⇄UdϾWf∑①≛
</script>
<script>
    args=[["49927398716"],["49927398717"],["1234567812345670"],["1234567812345678"],["79927398712"],["79927398713"],["374652346956782346957823694857692364857368475368"],["374652346956782346957823694857692364857387456834"]]
</script>
<script src="https://themoonisacheese.github.io/snippeterpreter/snippet.js" type="module"/>

Tcl, 85 bytes

proc L n {expr ([regsub -all . [string rev $n] {+([incr i]%2?&:&*2%10+(&>4))}])%10<1}

Try it online!

# [Tcl], 86 bytes
proc L n {expr !(([regsub -all . [string rev $n] {+([incr i]%2?&:&*2%10+(&>4))}])%10)}

Try it online!

Tcl, 112 bytes

proc L n {expr 1>([lmap a [lreverse [split $n ""]] {list +([incr i]%2?$a:[join [split [expr 2*$a] ""] +])}])%10}

Try it online!

Python 3, 77 bytes

c=lambda a:sum(sum(divmod(int(a[-e-1])<<e%2,10))for e in range(len(a)))%10==0

PHP, 108 bytes

<?function v($s,$t=0){for($i=strlen($s);$i>=0;$i--,$c=$s[$i])$t+=$c+$i%2*(($c>4)*-4+$c%5);return!($t % 10);}

Rust, 83 81 bytes

|d|(0..).zip(d).fold(0,|a,(b,&c)|a+[(c-48)*2%10+(c-48)/5,c-48][b+d.len()&1])%10<1

Attempt This Online!

Go, 164 158 156 bytes

import."fmt"
func f(s string)bool{o,L:=0,len(s)
for i:=range L{r:=(s[L-i-1]-48)<<(i%2)
n,k:=Sprint(r),0
for j:=range n{k+=int(n[j])-48}
o+=k}
return o%10<1}

Attempt This Online!

Explanation

import."fmt"
func f(s string)bool{
o,L:=0,len(s)     // setup: sum variable, and length of string
for i:=0;i<L;i++{ // for 0 to len(s)...
r:=(s[L-i-1]-48)  // get the char at i-th from the end, and convert to 0-9
         <<(i%2)  // if an odd index, double it
n,k:=Sprint(r),0  // convert to a string for digit summing
for j:=range n{k+=int(n[j])-48} // sum digits
o+=k}             // add to total sum
return o%10<1}    // check if divisible by 10

Forth (gforth), 82 bytes

: f >r i + 1- 0 r> 0 do over i - c@ '0 - i 2 mod 1+ * 10 /mod + + loop 10 mod 0= ;

Try it online!

Explanation

Takes input as a string, loops over the digits backwards, doubling if odd, then adds the digits of each number to the total.

Code Explanation

: f           \ start new word definition
  >r          \ stick the string length on the return stack temporarily
  i + 1-      \ add the string length to the addr -1 to get the addr of the last char
  0           \ initialize the sum as 0
  r> 0        \ set up the loop variables to run from 0 to string length
  do          \ start the counted loop
    over i -  \ get the address of the current char
    c@ '0 -   \ get the value of the current char, then subtract ascii 0 to get it as a num
    i 2 mod   \ get whether the current index is odd or even
    1+ *      \ add 1 and multiply by the current digit (will be 2* if odd, and 1* if even)
    10 /mod + \ get the digits of the new number and add them together
    +         \ add this value to the sum
  loop        \ end the counted loop
  10 mod 0=   \ check if divisible by 10
;             \ end word definition

Rust, 195 181 bytes

|s:&str|s.chars().map(|c|c.to_digit(10).unwrap()).rev().enumerate().map(|(i,n)|n<<i%2).map(|n|format!("{n}").chars().map(|c|c.to_digit(10).unwrap()).sum::<u32>()).sum::<u32>()%10<1;

Attempt This Online!

I'm pretty unfamiliar with Rust golf, so feel free to suggest savings.

Explanation

|s:&str|                           // input is a &str
s                                  // original string
.chars()                           // get the characters
.map(|c|c.to_digit(10).unwrap())   // convert each character into a digit
.rev()                             // reversed
.enumerate()                       // into pairs of (index, digit)
.map(|(i,n)|n<<i%2)                // into n or 2*n if the index is odd
.map(                              // getting the digit sum...
  |n|format!("{n}")                // to string
  .chars()                         // get the chars chars
  .map(|c|c.to_digit(10).unwrap()) // convert to digits
  .sum::<u32>())                   // sum them up
.sum::<u32>()                      // sum all the numbers up
 %10<1;                            // check if divisible by 10

bash, 109 106 90 71 bytes

Output of 0 means True. Anything else means False.

for x in `rev<<<$1|fold -1`;{((s+=++i%2?x:(x*22/10)%10));}
echo $[s%10]

Try it online!  90bytes  Alt-90bytes-backwards

Thunno 2 t!, 8 bytes

drŻɗ⁺×ʂS

Attempt This Online!

Or 10 bytes flagless:

drŻɗ⁺×ʂSt~

Attempt This Online!

Explanation

drŻɗ⁺×ʂSt~  # Implicit input
dr          # Cast to digits; reverse the list
  Ż         # Without popping, push [0..length)
   ɗ⁺       # Mod 2 of each; increment each
     ×      # Multiply elementwise
      ʂ     # Sum the digits of each number
       S    # Sum the resulting list
        t   # Pop and push the last digit
         ~  # And check if this equals 0
            # Implicit output

Zsh, 52 bytes

for j (${(Oas::)1})((s+=++i%2?j:j*2.2%10))
<<<$s[-1]

Try it Online..

Parse input into array and reverse it: ${(Oas::)1}. Then iterate over the array elements.
0 is truthy, non-zero is falsy.

From my work, the Visa test number (4111 1111 1111 1111) is embedded in my brain.

Previous efforts: 55 bytes 61 bytes 72 bytes 77 bytes

><>, 39 37 bytes

00@:}2%1+$c%*:a%$9)++{1+$1l3=.
n;a%0=

Try it online

Explanation

00                                 # init sum and counter to 0
  @:}2%1+                          # set counter to 1 if even and 2 if odd
         $c%*                      # mod current number by 12 and multiply by counter
               :a%$9)++            # sum digits and add to total sum
                       {1+$        # increment counter
                           1l3=.   # jump to next row if done, else skip init on 1st row
n;a%0=                             # print sum mod 10 == 0

Vyxal, 8 bytes

fṘ⁽dẇṠ∑t

Try it Online!

Outputs 0 for truthy, any positive integer for falsey.

Explained

fṘ⁽dẇṠ∑t
fṘ       # reverse the list of digits of the input
  ⁽dẇ    # double each odd-indexed digit
     Ṡ∑t # sum each number, and take the tail of the sum

Fig, \$10\log_{256}(96)\approx\$ 8.231 bytes

]SeSn2@h$f

Try it online!

Outputs using inverted logic: positive integer for falsey, 0 for truthy

]SeSn2@h$f
         f # Digits of number
        $  # Reverse
    n2@    # For every other item in the list
       h   # Unhalve (double)
  eS       # Digit sum of each
 S         # Sum
]          # Take the last digit (equivalent to mod 10)

Factor + validators, 5 bytes

luhn?

Try it online!

Julia 1.0, 51 50 bytes

~=digits;!n=(k=~n;k[2:2:end]*=2;sum(sum,.~k)%10<1)

Try it online!

K (ngn/k), 26 bytes

{~10!+//10\(1+2!!#x)*.'|x}

Try it online!

Another k variant, with a major debt to @streetster's answer.

JavaScript (ES6), 61 bytes

Sum of digits of 2*n is 2*n if n in 0..4, 2*n-9 if n in 5..9. That said, all the sum can be computed in one step.

s=>!([...s].reduceRight((t,d)=>t-d-i++%2*(d>4?d-9:d),i=0)%10)

C (clang), 264 212 196 175 172 bytes

l,x;main(i){char*s;gets(s);int n[i=l=strlen(s)];for(;i--;)n[i]=s[i]-48;for(;(i+=2)<l;n[i]>9?n[i]=n[i]/10+n[i]%10:0)n[i]*=2;for(;l--;)x+=n[l];printf(x%10<1?"True":"False");}

Try it online!

Simply the basic way of programming the algorithm, but all whitespace is removed. All I could say is that there are a bunch of for-loops in this one.

Thanks to ceilingcat for golfing 52 bytes, another 16 bytes, and another 21 bytes, and another 3 bytes.

Vyxal, 16 bytes

₀τƛ¥₂ßd&›₀τ∑;∑₀Ḋ

Try it Online!

₀τ               # Digits...
  ƛ         ;    # Map
   ¥₂            # If register is even
     ßd          # Double
       &›        # Increment register
         ₀τ      # Digits...
           ∑     # Sum
             ∑   # Sum of all...
              ₀Ḋ # is divisible by 10?

Vyxal, 12 11 bytes

-1 byte thanks to @lyxal reminding me about multibyte lambdas.

ṘÞTf‡d∑ẇ∑₀Ḋ

Try it Online!

Explanation:

             # Implicit input
Ṙ            # Reverse
 ÞT          # Transpose
   f         # Flatten list
    ‡  ẇ     # For every second element:
     d       #   Double
      ∑      #   Sum digits
        ∑    # Sum all elements
         ₀Ḋ  # x % 10 == 0?
             # Implicit output

Pxem, 0 bytes (content) + 147 bytes (filename).

Try it online!

Usage

A single line that matches ^[0-9]+$, ending with EOF, is given from stdin. A single Y is output if and only if truthy.

Algorithm

  1. Let l1 be a list storing each digit in reverse order.
  2. Let s be 0.
  3. Let l2 be an empty list.
  4. If l1 is empty, go to step 9.
  5. Pop one value from l1 and let it be n. Push n*(s+1) onto l2.
  6. If last value on l2 is more than 9, subtract 9 from it.
  7. Let s be 1-s.
  8. Go to step 4.
  9. Calculate (sum of each item in l2)%10.
  10. If step 9 resulted in 0, the program returns truthy; otherwise falsey.

With comments

# getchar() unil EOF
# substract 48 for each character
.w0.-.i.c\001.+.aXX.z
# at this point stack is -1, [0-9], ..., [0-9], 48.
# add 1 to -1 so: 0, ..., 48.
# move 0 to bottom: [0-9], ..., 48, 0.
.a\001.+.t.v.m.vXX.z
# loop
# every time loop begins, bottom should be [01].
# also heap should be same as bottom.
.aQJ.zXX.z
  # to: [0-9], [01], ..., 48, ..., [01]... I think
  # WTF did I do here?
  .a.v.m.v.c.m.+.c.t.-.m.v.t.v.m.-.mXX.z
  # multiply [0-9] to ([01]+1)
  .a\001.+.!XX.z
  # subtract 9 if more than 9
  .a.c\011.x\011.-XX.aXX.z
  # move top to bottom, replacing it
  .a.t.v.s.m.vXX.z
  # alt for [01] xor 1; subtract from 1
  # then move to bottom
  .a\001.-.t.v.m.vXX.z
# break if top equals 48
.a.c0.aXX.z
# make 48 to 10, then remove botton [01]
# OBTW reversed, but whatever
.a\046.-.v.sXX.z
# loop
.a@.wXX.z
  # if size is 1; then
  .a.t.c.c.ZXX.z
    # modulo by 10
    .a.m\012.%XX.z
    # if it is 0; then print Y and exit; else exit; fi
    .a.w.d.aY.o.d.AXX.z
  # fi; push (pop+pop)
  .a.m.+
# end of loop
.a@.a

x86-16 machine code, 27 bytes

Binary:

00000000: bb00 0103 f1fd ac2c 30f6 df78 06d0 e0d4  .......,0..x....
00000010: 0a02 dc02 d8e2 ef93 d40a c3              ...........

Listing:

BB 0100         MOV  BX, 100H           ; running sum (BL) to 0, BH to a positive value
03 F1           ADD  SI, CX             ; start at end of input string
FD              STD                     ; set LODSB direction to decrement
            DIGIT_LOOP: 
AC              LODSB                   ; load next digit into AL, decrement SI
2C 30           SUB  AL, '0'            ; convert ASCII char to binary value 
F6 DF           NEG  BH                 ; flip sign of BH to alternate odd/even index
78 06           JS   IS_EVEN            ; if not odd index, do not double
D0 E0           SHL  AL, 1              ; double the value
D4 0A           AAM                     ; split digits (ex: 18 --> AH = 1, AL = 8) 
02 DC           ADD  BL, AH             ; add tens digit to running sum
            IS_EVEN:
02 D8           ADD  BL, AL             ; add ones digit to running sum 
E2 EF           LOOP DIGIT_LOOP 
93              XCHG AX, BX             ; sum is in BL, move to AL for mod 10 check
D4 0A           AAM                     ; ZF = ( AL % 10 == 0 ) 
C3              RET                     ; return to caller

Uses (abuses) x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Callable function, input card num string pointer in SI, length in CX. Output: ZF if valid.

Example test program output:

enter image description here

Alternate version, 29 bytes

33 DB           XOR  BX, BX             ; running sum (BL) to 0
03 F1           ADD  SI, CX             ; start at end of string
4E              DEC  SI                 ; align for WORD
FD              STD                     ; set LODSB direction to decrement
            DIGIT_LOOP:
AD              LODSW                   ; load next two digits into AH:AL, dec SI by 2
25 0F0F         AND  AX, 0F0FH          ; convert ASCII chars to binary value
02 DC           ADD  BL, AH             ; add ones digit of even index to sum
49              DEC  CX                 ; decrement counter for WORD
74 0A           JZ   DONE               ; if input is odd length, will be 0 at the end
D0 E0           SHL  AL, 1              ; double the value
D4 0A           AAM                     ; split digits (ex: 18 --> AH = 1, AL = 8)
02 DC           ADD  BL, AH             ; add tens digit to sum
02 D8           ADD  BL, AL             ; add ones digit to sum
E2 ED           LOOP DIGIT_LOOP
            DONE:
93              XCHG AX, BX             ; move sum to AL for mod 10 check
D4 0A           AAM                     ; ZF = ( AL % 10 == 0 )
C3              RET                     ; return to caller

This version loads two digits at the same time, eliminating the flip/flop branch. The issue here is having to check for an odd number of digits on the input and discard the value in memory right before the beginning of the string once it reaches the last word. Obviously not shorter, but perhaps someone clever can golf it more!

Jelly, 12 11 9 bytes

ṚḤÐeDFS⁵ḍ

Try it online!

How it works

ṚḤÐeDFS⁵ḍ - Main link. Takes an integer n on the left
Ṛ         - Cast n to digits and reverse
  Ðe      - To values at even indices:
 Ḥ        -   Unhalve; Double
    D     - Cast to digits
     F    - Flatten
      S   - Sum
        ḍ - Divisible by:
       ⁵  - 10?

C (gcc), 126 110 bytes

-16 bytes thanks to ceilingcat

#define e s[1][i]
c,b;main(i,s)char**s;{for(i=strlen(s[1]);i--;b+=e-=e/10?9:0)e-=48,e*=c++%2+1;return!(b%10);}

Input is taken through an argument and output uses exit codes, 0 for false and 1 for true

Explanation:

#define e s[1][i]
c,b;
main(i,s) // i, c, and b are ints for program use
char**s; // argv, used for input
{
    for(i=strlen(s[1]); i--; b+=e-=e/10?9:0) // iterate backwards through string, and add to the total (b) while also doing the digit add
        e-=48, // subtract '0'
        e*=c++%2+1; // double each odd index
    return!(b%10); // check if b ends in 0 and return that
}

GolfScript, 31 bytes

.,2%0\@{48-..4>+@!:a*++a}/;10%!

Try it online!

Golfscript pushes the input as a list of characters to the stack at the start of the program.

.                                Duplicate the top of the stack (input)
 ,2%                             Compute the modulo 2 of the length of the input,
                                 pushed 1/0 on the stack if the number if odd/even
    0                            Push an accumulater var on the stack, set to 0
    
     \                           Flip the even/odd and accumulator order on the stack
      @                          Bring the 3rd entry forward, input to the top

       {                }        Code block...
                         /       Apply the block of code to the elements of the list at
                                 the top of the stack. Each time through the loop, the
                                 next element from the list if pushed to the top of the
                                 stack
        48-                      Subtract "0" from the top of stack (which is a codepoint
                                 for the current digit/character)
           ..                    Duplicate the top of stack (the current digit) twice
             4>+                 If the current digit is >4 add one to the digit
                @                Pull the 3rd entry, the even/odd indicator, to the top
                 !:a             Flip the value and save in variable "a"
                    *            Multiple the top two stack entries, will be "0" or the
                                 value of current digit, with or without "1" more for the
                                 "+10" rule
                     ++          Add the current digit, to the possible "double" and
                                 "even/odd" bump
                       a         Push the flipped even/odd indicated to the top
                          ;      Drop the stop of stack, the even/odd indicator 
                           10%   Find the modulo 10 of the accumulated digits
                              !  Invert the result

The only thing on the stack is the answer, which is printed by default

dc, 61 bytes

[A~rdZ1<S]dsSxz2%1=0[2*SaSaz1<LLaLalSx]dsLx[+z1<L]dsLxA%0=0zp

Try it online!

[A~rdZ1<S]dsSx # split: take quotient and remainder by 10, rotate quotient to top
z2%1=0 # if odd length, prepend 0 (I think. I poked it until it worked)
[2*SaSaz1<LLaLalSx]dsLx # double every other number, split them all
[+z1<L]dsLx # sum everything
A%0=0zp # if n%10 == 0, print 1; else, print 0

The last line works because:

  1. Each register holds 0 by default
  2. Comparisons attempt to execute whatever's in the specified register (0 here)
  3. Executing a number simply returns the number

So if we execute the contents of register 0, then we have one item on the stack: 0. Otherwise, the stack is empty. Use z to convert this to a 0 or 1.

Husk, 15 13 bytes

Edit: -2 bytes thanks to Razetime

¬→dṁΣzod*¢ḣ2↔

Try it online!

¬                   # logical NOT of
 →d                 # last decimal digit of
   ṁΣ               # sum of sums of results of
     z              # zipping two lists together
         ¢ḣ2        # list 1: [1,2] repeated
            ↔       # list 2: input, reversed
      o             # using these two functions:
       d*           # decimal digits of product

R, 46 bytes

function(x,y=rev(x)*1:2)!sum(y%%10+y%/%10)%%10

Try it online!

Burlesque, 33 bytes

riXX<-J2ENj2en2?***{XX++}ms10.%z?

Try it online!

ri         # Read input as int
XX         # Explode into digits
<-         # Reverse
J2EN       # Duplicate and take every 2nd starting from 1
j2en       # Take the other half
2?*        # Multiply each digit by 2
**         # Remerge arrays
{XX++}ms   # Sum the digits of multidigit and then sum result
10.%z?     # If result `mod` 10 is 0

PHP, 83 82 bytes

foreach(str_split(strrev($argn))as$x=>$d)$m+=$d+($d%10+$d/5|0)*$x&=1;echo!($m%10);

As standalone program, call with php -F. Input is STDIN, output is to STDOUT as bool (1 or empty).

$ echo 49927398716|php -F luhn.php
1

$ echo 49927398717|php -F luhn.php

$ echo 1234567812345670|php -F luhn.php
1

Verify all test cases

05AB1E, 12 10 bytes

RSāÈ>*SOTÖ

Try it online! or as a Test Suite

Explanation

R             # reverse input
 S            # split to list of digits
  ā           # push range[1 ... len(input)]
   È          # map isEven on each
    >         # increment
     *        # multiply doubling every other item
      SO      # sum digits
        TÖ    # mod 10 == 0

Japt, 14 13 bytes

Takes input as an array of digits.

ÔxÈ*ÒYu)ìxÃvA

Try it

ÔxÈ*ÒYu)ìxÃvA     :Implicit input of array
Ô                 :Reverse
 x                :Reduce by addition
  È               :After passing each element at 0-based index Y through the following function
   *              :   Multiply by
    Ò             :     Bitwise increment
     Yu           :     Y modulo 2
       )          :   End multiplication
        ì         :   Convert to digit array
         x        :   Reduce by addition
          Ã       :End function
           v      :Test for divisibility by
            A     :  10

Japt v2.0a0, 14 bytes

¬ÔxÈ*ÒYu)ìxÃvA

The first byte can be removed if I took input as array of chars.

Try it

¬                   //Split (implicit) input into list of chars
 Ô                  //Reverse
  xÈ                //Get the sum of every char after passing through the following function
    *               //  Multiply the element
     ÒYu)           //  By the index modulus 2 plus 1 (Odd -> 2, Even -> 2)
         ìx         //  And take the sum of the digits
  Ã                 //Close function
vA                  //And check if result is divisible by 10

APL(NARS), 37 chars, 74 bytes

{0=10∣+/{+/10 10⊤⍵}¨v+v×0=2∣⍳≢v←⌽⍎¨⍵}

test:

  f←{0=10∣+/{+/10 10⊤⍵}¨v+v×0=2∣⍳≢v←⌽⍎¨⍵}
  f '1234567812345670'
1
  f '49927398717'
0
  f '1234567812345678'
0
  f '79927398710'
0
  f '79927398719'
0
  f '374652346956782346957823694857692364857368475368'
1
  f '374652346956782346957823694857692364857387456834'
0
  f ,'8'
0
  f ,'0'
1

comment:

{0=10∣+/{+/10 10⊤⍵}¨v+v×0=2∣⍳≢v←⌽⍎¨⍵}
                                ⍎¨⍵ for each element of ⍵ (that would be char digits) convert in int
                             v←⌽    reverse the array result of above, and assign it to variable v
                           ⍳≢        produce all index of above v that are 1..≢v
                        0=2∣         produce one array of boolean where 0 means even index, 1 odd
                    v+v×            multipy that array for v itself (means get only odd ones the other 0)
                                    and sum it to v (so we have v with elements index odd duplicate)
       {+/10 10⊤⍵}¨                convert each element of the array of 2 digits base 10 than sum
   10∣+/                            sum all element mod 10
 0=                                if result is 0 return 1 (true), else return 0 (false)

Haskell, 73 bytes

i#0=0
i#n|m<-mod n 10=i*(m+sum[-9|m>4])+m+(1-i)#div n 10
f n=mod(0#n)10<1

Try it online!

MathGolf, 11 bytes

▒xôï¥)*Σ+♂÷

Try it online!

At least I tied with Jelly, I can't really see a way to remove a byte from this.

Explanation

▒             split to list of chars/digits
 x            reverse int/array/string
  ô           start block of length 6 (for-each)
   ï          index of current loop
    ¥         modulo 2
     )        increment
      *       pop a, b : push(a*b)
       Σ      digit sum
        +     add to the counter (implicitly calculates 0+x when stack only has one element)
              Block ends here
         ♂    push 10
          ÷   is divisible

Julia, 67 bytes

x=digits(n)
sum(x[1:2:end])+sum(reduce(vcat,digits.(x[2:2:end]*2)))

Perl 6, 37 bytes

(*.flip.comb >>*>>[1,2]).comb.sum%%10

Try it online!

A Whatever lambda that takes a number and returns a boolean.

Explanation:

 *.flip                  # Reverse the number
       .comb             # Split to list of digits
             >>*>>       # Multiply each element by:
                  [1,2]  # The list 1,2,1,2,1,2...
(                      ).comb           # Split the list to a list of digits
                             .sum       # Get the digit sum
                                 %%10   # Return if it is divisible by 10

Dart, 120 bytes

f(s,{i=0})=>s.split('').reversed.map(int.parse).map((n)=>i++%2>0?n*2:n).map((n)=>n>9?n-10+1:n).fold(0,(p,e)=>p+e)%10==0;

Try it online!

Jelly, 14 bytes

DUḤJḤ$¦DS$€S⁵ḍ

Try it online!

Explanation:

D              get digits
 U             reverse array
   JḤ$         for every other index,
  Ḥ   ¦        double the value
          €    for each value,
       D $     get the digits
        S$     and sum them
           S   sum the list
            ⁵ḍ check if it's divisible by 10

Powershell, 74 bytes

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

Explanation

  1. for each char of an argument string, in reverse order
  2. get a digit of double value of a digit
  3. a double value of a digit can not be greater then 18. Therefore, we accumulate a value minus 9 if value > 9
  4. return true if the remainder of the division by 10 is 0

Test script

$f = {

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

}

@(
    ,("49927398716"      , $True)
    ,("49927398717"      , $False)
    ,("1234567812345670" , $True)
    ,("1234567812345678" , $False)
    ,("79927398710"      , $False)
    ,("79927398711"      , $False)
    ,("79927398712"      , $False)
    ,("79927398713"      , $True)
    ,("79927398714"      , $False)
    ,("79927398715"      , $False)
    ,("79927398716"      , $False)
    ,("79927398717"      , $False)
    ,("79927398718"      , $False)
    ,("79927398719"      , $False)
    ,("374652346956782346957823694857692364857368475368" , $True)
    ,("374652346956782346957823694857692364857387456834" , $False)
    ,("8" , $False)
    ,("0" , $True)
) | % {
    $s, $expected = $_
    $result = &$f $s
    "$($result-eq$expected): $result : $s"
}

Output

True: True : 49927398716
True: False : 49927398717
True: True : 1234567812345670
True: False : 1234567812345678
True: False : 79927398710
True: False : 79927398711
True: False : 79927398712
True: True : 79927398713
True: False : 79927398714
True: False : 79927398715
True: False : 79927398716
True: False : 79927398717
True: False : 79927398718
True: False : 79927398719
True: True : 374652346956782346957823694857692364857368475368
True: False : 374652346956782346957823694857692364857387456834
True: False : 8
True: True : 0

Kotlin, 77 bytes

mapIndexed{i,c->(""+(2-(length%2 xor i%2))*(c-'0')).sumBy{it-'0'}}.sum()%10<1

Beautified

mapIndexed { i, c ->
    ("" + (2 - (length % 2 xor i % 2)) * (c - '0')).sumBy { it - '0' }
}.sum() % 10 < 1

Test

data class Test(val input: String, val output: Boolean)

val tests = listOf(
        Test("49927398716", true),
        Test("49927398717", false),
        Test("1234567812345670", true),
        Test("1234567812345678", false),
        Test("79927398710", false),
        Test("79927398711", false),
        Test("79927398712", false),
        Test("79927398713", true),
        Test("79927398714", false),
        Test("79927398715", false),
        Test("79927398716", false),
        Test("79927398717", false),
        Test("79927398718", false),
        Test("79927398719", false),
        Test("374652346956782346957823694857692364857368475368", true),
        Test("374652346956782346957823694857692364857387456834", false),
        Test("8", false),
        Test("0", true)
)

fun String.f() =
mapIndexed{i,c->(""+(2-(length%2 xor i%2))*(c-'0')).sumBy{it-'0'}}.sum()%10<1
fun main(args: Array<String>) {
    for ((input, expectedOut) in tests) {
        val actualOut = input.f()
        if (actualOut != expectedOut) {
            System.err.println("$input $expectedOut $actualOut")
        }
    }
}

TIO

TryItOnline

Pyt, 20 bytes

ĐḶ⌊⁺⇹ą↔⇹ř⁻2%⁺*ŚƩ1ᴇ%¬

Explanation:

                        Implicit input
Đ                       Duplicate input
 Ḷ⌊⁺                    Get length of integer in base-10 (floor(log_10(input))+1)
    ⇹                   Swap top two on stack
     ą↔                 Convert input to an array of digits, and reverse
       ⇹                Swap top two on stack
        ř⁻              Push [0,1,2,...,floor(log_10(input))]
          2%            Take previous array element-wise mod 2
            ⁺           Increment each element of the array
             *          Elementwise multiplication of the arrays
              Ś         Elementwise sum of digits
               Ʃ        Sum up array
                1ᴇ%     Mod 10
                   ¬    Negate (this returns false if not 0, and true otherwise)

Try it online!

K (oK), 28 bytes

Solution:

~10!+/48!,/$(1+2!!#x)*48!|x:

Try it online!

Examples:

~10!+/48!,/$(1+2!!#x)*48!|x:"1234567812345670"
1
~10!+/48!,/$(1+2!!#x)*48!|x:"1234567812345678"
0

Explanation:

~10!+/48!,/$(1+2!!#x)*48!|x: / the solution
                          x: / save input as variable x
                         |   / reverse it
                      48!    / mod with 48 (converts ascii -> int)
            (       )*       / multiply with stuff in brackets
                  #x         / length of x
                 !           / til, the range 0..x-1
               2!            / mod with 2 (0 1 2 3 -> 0 1 0 1)
             1+              / add 1 (0 1 0 1 -> 1 2 1 2)
           $                 / convert to string
         ,/                  / flatten string
      48!                    / convert this into integers
    +/                       / sum over the list
 10!                         / modulo 10
~                            / negate (so 1 for truthy, 0 for falsy)

Extra:

A couple of 30-byte solutions in K4, not quite as short...

~.*|$+/,/10\:'((#x)#1 2)*.:'x:
~.*|$+/.:'',/$((#x)#1 2)*.:'x:

MATL, 23 20 bytes (non competing)

P!Utn:2X\!*t9>+s10\~

Try it online!

Outputs 1 for a valid number, 0 otherwise.

Saved three bytes thanks to Luis Mendo's suggestions.

Explanation

P       % flip the order of elements
!       % transpose into column vector
U       % convert char matrix to numeric
t       % duplicate the vector
n       % find the length
:       % create a new vector length n (1, 2, 3, ... n)
2       % number literal
X\      % take it mod 2, to make the new vector (1, 2, 1, ..., (n-1) mod 2 +1)
!       % transpose
*       % element-wise product
t       % duplicate
9       % push 9
>       % 1 if it is greater than 9
+       % add the vectors, this makes the last digit of each the same as the sum of the digits
s       % add them
10      % number literal
\       % mod 10
~       % logical 'not' (element-wise)
        % (implicit) convert to string and display

Pyth, 19 bytes (non-competing)

Non-competing since Pyth is newer than this challenge.

!%s.esj*b@S2kT_jQTT

A program that takes input of a string on STDIN and prints True or False as appropriate.

Try it online or verify all test cases

How it works

!%s.esj*b@S2kT_jQTT  Program. Input: Q
               jQT   Yield the base-10 representation of Q as a list, giving the digits
              _      Reverse
   .e                Enumerated map, with elements as b and indices as k:
          S2           Yield [1, 2]
         @  k          Modular indexing with k, yielding 1 for even indices and 2 for odd
                       indices
       *b              Multiply by b
      j      T         Yield the digits
     s                 Sum
  s                  Sum the resulting list
 %                T  Modulo 10
!                    Logical not, yielding True for 0 and False otherwise
                     Implicitly print

Perl, 46 42 41 bytes

Includes +1 for -p

Give input on STDIN:

luhn.pl <<< 79927398713

luhn.pl:

#!/usr/bin/perl -p
s%.%$=-=-$&-$&*1.2*/\G(..)+$/%eg;$_=/0$/

PHP - 136 characters

function t($c){foreach($a=str_split(strrev($c)) as $k=>&$v){$v=array_sum(str_split(($k % 2)!==0?2*$v:$v));}return !(array_sum($a)% 10);}

Haskell, 96 bytes

There must be a better/shorter way, but here's my Haskell solution in 96 characters:

l=(==0).(`mod`10).sum.zipWith($)(cycle[id,\x->x`mod`5*2+x`div`5]).reverse.map((+(-48)).fromEnum)

Sadly the digitToInt function can only be used if you import Data.Char first. Otherwise I could get down to 88 characters by replacing ((+(-48)).fromEnum) with digitToInt.

Retina, 43 42 bytes

Retina is (much) newer than this challenge.


;
r`(.);.
$1$&
\d
$*
1+
$.&
.
$*
$
$._
0$

The leading empty line is significant.

Prints 0 for falsy and 1 for truthy results.

Try it online! (Slightly modified to run all test cases at once.)

Explanation


;

Insert ; in every position to separate digits.

r`(.);.
$1$&

From the right, we repeatedly match two digits and double the left one. This way we avoid an expensive reversing of the list.

\d
$*

We match each digit and convert it to that many 1s (that is, we convert each digit to unary).

1+
$.&

This matches each unary number and converts it back to decimal by replacing it with its length. Together with the previous stage, this adds the doubled digits.

.
$*

Again, we match every character and turn it into that many 1s. That is we convert each digit individually back to unary. This also matches the ; separators, which are treated as zeros in the conversion, which means they're simply removed. Since all the unary numbers are now squashed together we've automatically added the unary representations of the all digits together.

$
$._

At the end, we insert the length of the entire string, i.e. the decimal representation of the unary checksum.

0$

Finally we count the number of matches of this regex, i.e. we check whether the decimal representation ends in 0, printing 0 or 1 accordingly.

K4, 35 bytes

{~.*|$+/.:',/$x*1+1{y;~x}\|x:|.:'x}

APL, 28 bytes

{0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵}

Exploded view

{                     v←⍎¨⍵}  ⍝ turn the string into a numeric vector of its digits, v
                2-2|⍳⍴v       ⍝ make a vector of the same length, with 2 in every 2nd place
             v×⌽              ⍝ multiply it with v, starting from the right
          ∊⍕¨                 ⍝ turn each component into a string and collect all the digits
      +/⍎¨                    ⍝ turn each digit again into a number and sum them
 0=10|                        ⍝ check whether the sum is a multiple of 10

Examples

      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '79927398713'
1
      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '123456789'
0

APL, 38 bytes

d←10∘⊥⍣¯1⋄{0=10|+/+/d x×1+~2|⍳⍴x←⌽d ⍵}

expects the number as a number, not a string, but that's only because tryAPL (understandably) doesn't implement

further reducible, i'm sure…

D, 144 bytes

bool f(S)(S s){int t(C)(C c){return to!int(c)-'0';}int n,v;foreach(i,c;array(retro(s))){v=i&1?t(c)*2:t(c);n+=v>=10?v%10+v/10:v;}return n%10==0;}

More legibly:

bool f(S)(S s)
{
    int t(C)(C c)
    {
        return to!int(c) - '0';
    }

    int n, v;

    foreach(i, c; array(retro(s)))
    {
        v = i & 1 ? t(c) * 2 : t(c);

        n += v >= 10 ? v % 10 + v / 10 : v;
    }

    return n % 10 == 0;
}

GNU sed, 140 bytes

(including +1 for the -r flag)

s/^(..)*.$/0&/
s/(.)./\1x&/g
s/x[5-9]/1&/g
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
s/.{10}//g
s/.+/false/
s/^$/true/

Sed is almost never the most natural language for arithmetic, but here we go:

#!/bin/sed -rf

# zero-pad to even length
s/^(..)*.$/0&/
# double every other digit
s/(.)./\1x&/g
# add carry (converts mod-9 to mod-10)
s/x[5-9]/1&/g
# convert sum to unary
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
# remove whole tens
s/.{10}//g
# output 'true' or false
s/.+/false/
s/^$/true/

JavaScript 1.8: 106 characters

This is an original solution I came up with before I found this post:

function(n){return!(n.split('').reverse().reduce(function(p,c,i){return(+c&&((c*(1+i%2)%9)||9))+p},0)%10)}

Readable form:

function luhnCheck(ccNum) {
    return !(                                  // True if the result is zero.
             ccNum.split('').
               reverse().                      // Iterate over the string from rtl.
               reduce(function(prev, cur, idx) {
                 return prev +                 // Sum the results of each character.
                        (+cur &&               // If the current digit is 0, move on.
                         ((cur * (1 + idx % 2) // Double cur at even indices.
                           % 9) || 9));        // Sum the digits of the result.
               }, 0)
            % 10);                             // Is the sum evenly divisible by 10?
}

Haskell: 97

For some reason this isn't working for me, so here is my version

l=(\x->(==0)$(`mod`10).sum$zipWith($)(cycle[id,sum.map(read.(:"")).show.(*2)])(map(read.(:""))x))

Scala: 132

def q(x:Int)=x%10+x/10
def c(i:String)={val s=i.reverse
(s(0)-48)==10-(s.tail.sliding(2,2).map(n=>(q((n(0)-48)*2)+n(1)-48)).sum%10)}

invocation:

c("79927398713")

Q, 63

{0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}

usage

q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398711"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398712"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398713"
1b

C# 119 characters:

bool l(string n){return(String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2<1?1:2)+"").ToArray()).Sum(x=>x-48))%10<1;}

Not too bad for a code golf n00b in a statically typed language, I hope.

This can be reduced to 100:

bool l(string n){return String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2+1))).Sum(x=>x+2)%10<1;}

Windows PowerShell, 82

filter f{!((''+($_[($_.length)..0]|%{+"$_"*($i++%2+1)})-replace'.','+$&'|iex)%10)}

History:

PowerShell 123

filter L($x){$l=$x.Length-1;$l..0|%{$d=$x[$_]-48;if($_%2-eq$l%2){$s+=$d}elseif($d-le4){$s+=$d*2}else{$s+=$d*2-9}};!($s%10)}

Golfscript - 24 chars

-1%{2+0!:0)*109%+}*10%8=

Explanation:

  1. -1% reverses the string
  2. { begins a block (which we use as a loop). Each character in the strings is pushed as it's ascii value.
    1. 2+ adds 2. (the ascii value of a digit is 48+n, so we have 50+n now and the last digit is n)
    2. 0!:0 inverts the value of 0 and stores it (everything is a variable), so we have 1 on the first iteration, 0 on the second, etc.
    3. )* adds one to this value and multiplies it, so we multiply by 2, then 1, then 2, etc.
    4. 109% is remainder modulo 109. This affects only values 5-9 which have been doubled and reduces them to the correct value.
    5. + adds this value to the running sum
  3. }* ends the block and does a 'fold' operation. First, the first character is pushed (since we have reversed, this is the check digit). Then, alternate pushing and executing the block. Thus, we are using the first character's ascii value as the starting value for the running sum.
  4. 10% takes the remainder modulo 10.
  5. 8= will return 1 if the value is 8. We use this because we did not normalize the first pushed character (the check digit).

One might think that we could use 8- instead of 2+ to save a character by changing 109% to 89%, except then we would need to add a space so the - is subtraction (instead of -0).

Golfscript - 34 chars

{15&}%.-2%\);-2%{.+(9%)}%+{+}*10%!

Example number from wikipedia page 4992739871

{15&}%  does a bitwise and of each ascii digit with 00001111
        now I have a list of digits 
        [4 9 9 2 7 3 9 8 7 1 6]
.       makes a copy of the list, now I have two identical lists
        [4 9 9 2 7 3 9 8 7 1 6] [4 9 9 2 7 3 9 8 7 1 6]
-2%     like [::-2] in python takes every second element in reverse
        [4 9 9 2 7 3 9 8 7 1 6] [6 7 9 7 9 4]
\       swap the two lists around
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1 6]
);      drop the last digit off the list
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1]
-2%     same as before
        [6 7 9 7 9 4] [1 8 3 2 9]
{       for each item in the list ...
.+      ... double it ...
(       ... subtract 1 ...
9%      ... mod 9 ...
)}%     ... add 1 ...
        [6 7 9 7 9 4] [2 7 6 4 9]
+       join the two lists
        [6 7 9 7 9 4 2 7 6 4 9]
{+}*    add the elements up
        70
10%     mod 10
        0
!       invert the result
        1

Ruby - 85 characters

def f s
l=s.size
s.chars.map{|k|(i=k.to_i*((l-=1)%2+1))%10+i/10}.inject(:+)%10==0
end

Python, 73 69 characters

def P(x):D=map(int,x);return sum(D+[d-d/5*9for d in D[-2::-2]])%10==0

GolfScript, 44 chars

-1%{16%}%2/1,\+{(\.{0=2*.9>9*-+}{;}if+}*10%!

Selected commentary

Interestingly, the first two items below demonstrate three completely different uses of the % operator: array selection, map, and mod. Most GolfScript operators are "context-sensitive", giving them hugely divergent behaviours depending on what types the arguments are.

  1. -1% reverses the string. This is important as the digit pairs are counted from the right.
  2. {16%}% converts all the ASCII digits into numbers, by modding them with 16.
  3. 2/ splits the array into groups of 2.
  4. 1, is a cheap way to do [0].
  5. \+ effectively prepends the 0 to the digits array. It does this by swapping then concatenating.

The 0 is prepended in preparation for the fold that comes in next. Rather than taking an explicit initial value, GolfScript's fold uses the first item in the array as the initial value.

Now, let's look at the actual fold function. This function takes two arguments: the folded value, and the current item on the array (which in this case will be an array of 2 or (uncommonly) 1, because of the 2/ earlier). Let's assume the arguments are 1 [2 3].

  1. (\. splits out the leftmost array element, moves the remaining array to the front, then copies it. Stack now looks like: 1 2 [3] [3].
  2. The if checks if the array is empty (which is the case for the last group when dealing with an odd-sized account number). If so, then no special processing happens (just pop off the empty array).
  3. For an even group:
    1. 0= grabs the first (only, in this case) element of the array. 1 2 3
    2. 2* doubles the number. 1 2 6
    3. .9>9*- subtracts 9 from the number if it's greater than 9. Implemented as: copy the number, compare with 9, multiply the result (which is either 0 or 1) with 9, then subtract. 1 2 6
    4. + finally adds that to the first number. 1 8
  4. + (after the if) adds the result of the if to the original value, resulting in the new folded value.

After the folding completes, we simply mod with 10 (10%), and negate the result (!), so that we return 1 iff the sum is a multiple of 10.