The Luhn algorithm for verifying credit card numbers, etc

Write the shortest program or function to calculate the Luhn Algorithm for verifying (credit card) numbers.

From RosettaCode, this algorithm for the purposes of this challenge is specified as such, with the example input of `49927398716`:

``````Reverse the digits, make an array:
6, 1, 7, 8, 9, 3, 7, 2, 9, 9, 4
Double the numbers in odd indexes:
6, 2, 7, 16, 9, 6, 7, 4, 9, 18, 4
Sum the digits in each number:
6, 2, 7, 7, 9, 6, 7, 4, 9, 9, 4
Sum all of the numbers:
6 + 2 + 7 + 7 + 9 + 6 + 7 + 4 + 9 + 9 + 4 = 70
If the sum modulo 10 is 0, then the number is valid:
70 % 10 = 0 => valid
``````

Input: A string or number (your choice), in your language's input/output format of choice

Output: A truthy or falsy value, respectively, indicating whether or not the input is valid according to the test above.

Notes / Tips

• Try not to accidentally post your own credit card or account numbers, if you use them to test :)

• If the input is invalid and impossible to process with the specified algorithm (i.e, too short to work with), you can do whatever you want, including blow up my computer.

• However, the previous bullet does not mean that your language can do whatever it wants with Numbers that are too large for it to handle. If your language isn't capable of handling a test case, then consider taking a string as input.

Examples: The following examples were validated with this Python script; if you think one is wrong or have a question, just ping @cat.

``````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  **
``````

** according to the Python implementation, but you may do anything because these are too short to be eligible by a strict adherence to the specification.

If any of the above invalidates existing answers (though I believe that should not be possible), then those answers are stil valid. However, new answers, in order to be valid, should follow the specification above.

-

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, 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.

-
This seems to return 0 for the example number on wikipedia (49927398716) – gnibbler Feb 1 '11 at 10:51
nm. I forgot to use `echo -n` – gnibbler Feb 1 '11 at 11:49
@gnibbler: Haha, fail. :-P (Seriously, I got stung by that one too, in my initial testing.) – Chris Jester-Young Feb 1 '11 at 13:06
A few places to save a few easy characters here. `-1% 2/` can be combined into `-2/`. `1,` can be replaced with `0` (0 is coerced to an array, then `+` is concatenate). `9>9*-` can be replaced with `9>+` (since we're only concerned with the last digit). Also, the checking for odd lengths is a bit long, using `.,2%,\+` is shorter. After doing this, we can also change `{16%}%` and `(\0=` into `{16}/` (inside the loop). Once you've done all that, it'll look something like this: `.,2%,\+-2/0\+{{16%}/2*.9>+++}*10%!`. – Nabb Feb 2 '11 at 17:15
@Nabb: Thanks! I'll incorporate those into my solution, although it looks like you already have one that's kicking serious arse. :-) – Chris Jester-Young Feb 2 '11 at 17:40

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
``````
-
You can save two more chars by not looping backwards : `D[-2::-2]` -> `D[1::2]` as the order of a sum isn't important :) – ThinkChaos Feb 1 '14 at 23:14

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;}
``````
-
It's a good idea, and an interesting approach, but it doesn't appear to work. At least not with my few tests. It looks like the "i" in your first lambda is supposed to be the index of the character in the string. Does that work as it should? If so, why do you reverse the string only to then modify it based on index position? Seems a bit redundant, no? – Nellius Feb 1 '11 at 23:48
I only tested one of my credit cards and a few off by one errors from it TBH. (Using the VS 2008 debugger) The algorithm is supposed to double every second digit starting with the LAST digit. If I didn't reverse the string, it would be incorrect for strings with odd lengths. – mootinator Feb 2 '11 at 1:37
Turns out I did have the result of `i%2<1?1:2` backwards. Thanks. – mootinator Feb 2 '11 at 1:59

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

Golfscript - 34 chars

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

``````{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 ...
[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]
70
10%     mod 10
0
!       invert the result
1
``````
-
The `.+(9%)` is very innovative (for me, anyway). I like! +1 – Chris Jester-Young Feb 1 '11 at 13:09
Srsly though, GolfScript needs a partitioning operator, so you don't need to do this "drop end item off and repeat" nonsense. :-) – Chris Jester-Young Feb 1 '11 at 13:14
@Chris, I learned about that many years ago called "casting out nines". It is a neat way to double check longhand additions and multiplications – gnibbler Feb 1 '11 at 13:22
This won't work for a value of 0 being doubled (`0(9%)` is 9 and not 0). – Nabb Feb 2 '11 at 16:59

PHP 108 characters:

``````<?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);}
``````
-

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

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`.

-

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

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

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

Windows PowerShell, 82

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

History:

• 2011-02-13 03:08 (84) First attempt.
• 2011-02-13 12:13 (82) I don't need to join, as spaces do not hurt. `+1 + +3` can still be evaluated.
-

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

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

Perl, 4642 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\$/
``````
-
Can you please explain how this works? You seem to be decrementing by the match and then also by the match times 1.2 but only in the correct positions. Why 1.2? Shouldn't it be `\$=-=-\$&-\$&*/\G(..)+\$/`? – msh210 Apr 22 at 21:33
@msh210: It encodes the effect of the multiplication by 2. `0..4` * 2 gives `0, 2, 4, 6, 8` but `5..9` gives `10,12,14,16,18` which sum to `1 3 5 7 9` which have the same last digits as `11 13 15 17 19` which are the same values as `0..9 * 2.2` if you truncate to integer. The first `\$&` already contributes a factor `1`, so a correction by `1.2` is still needed. `\$=` can only hold integers and starts with a value that ends on 0 so takes care of the truncating. The negative values are needed since the `/\G/` regex changes any `\$&` still on the evaluation stack so they need to be changed – Ton Hospel Apr 22 at 21:58
Oh. Brilliant! And thanks for the explanation. – msh210 Apr 22 at 22:57

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")
``````
• reverse ("79927398713") = 31789372997
• s(0), s.tail: (3)(1789372997)
• sliding (2,2) = (17 89 37 29 97)
• map (q((n(0)-48*2 + n(1)-48)) => q(('1'-'0')*2)+ '7'-'0')=1*2+7
-

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

``````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?
}
``````
-

K4, 35 bytes

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

JavaScript (ES6), 61 bytes

Non-competing, as JavaScript was very different in 2011.

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

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

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…

-

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 `r`ight, 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 `1`s (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 `1`s. 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.

-

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

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

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