# The Luhn algorithm for verifying credit card numbers, etc

### Challenge

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

### Luhn algorithm explained

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


### IO Rules

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.

var QUESTION_ID=22,OVERRIDE_USER=73772;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

# 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!

# 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


# 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

• Oh, didn't see you'd posted this before I fixed mine. Don't forget, you only have 'til Tuesday to post 3 more solutions and qualify for the additional 300 rep bounty. – Shaggy Mar 28 at 17:23

# 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
È               :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
Ã       :End function
v      :Test for divisibility by
A     :  10

• This doesn't reverse the array, so inputs like 24 return the wrong result – Embodiment of Ignorance Mar 27 at 4:32
• Thanks, @EmbodimentofIgnorance, looks like I made a faulty assumption somewhere along the way. Fixed and saved a byte in the process. – Shaggy Mar 27 at 11:28

# 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

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

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


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!

proc L n {expr !(([join [lmap a [lreverse [split $n ""]] {expr [incr i]%2?$a:[join [split [expr 2*$a] ""] +]}] +])%10)}  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:  # 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! # 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

Julia, 67 bytes

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


# 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


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!

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


# Bash (bash 4.4.5)+, 109 106 bytes

Output of 0 means True. Anything else means False. Try it Online!

1. -3 chars: echo $n|rev ==> rev<<<$n

2. -3 chars: for i in seq ${#r}; ==> for((;${#r}>i++;))

3. y obtained by x * 2.2 and taking the last int digit. Equivalent to multiplying by 2 and summing digits, but quicker

r=rev<<<$n for((;${#r}>i++;)){
x=${r:i-1:1} y=bc<<<"($x*2.2)%10/1"
s=$((i%2>0?s+x:s+y));} echo$[s%10]


Explanation:

r=echo $1|rev #read input ($1) and reverse it (r)
for((;${#r}>i++;)){ #loop over digits of r ; do (i) x=${r:i-1:1};                #  x is the (i-1)'th digit of r
y=bc<<<"($x*2.2)%10/1" # y is sum of doubled digits of x s=$((i%2>0?s+x:s+y))         #  s is running total of digit-sums,
;}                           #    alternately adding x and y
echo \$[s%10]                   #print s modulo 10