## Credit Card Validation

### April 8, 2011

Most credit card numbers, and many other identification numbers including the Canadian Social Insurance Number, can be validated by an algorithm developed by Hans Peter Luhn of IBM, described in U. S. Patent 2950048 in 1954 (software patents are nothing new!), and now in the public domain. The Luhn algorithm will detect almost any single-digit error, almost all transpositions of adjacent digits except 09 and 90, and many other errors.

The Luhn algorithm works from right-to-left, with the right-most digit being the check digit. Alternate digits, starting with the first digit to left of the check digit, are doubled. Then the digit-sums of all the numbers, both undoubled and doubled, are added. The number is valid if the sum is divisible by ten.

For example, the number 49927398716 is valid according to the Luhn algorithm. Starting from the right, the sum is 6 + (2) + 7 + (1 + 6) + 9 + (6) + 7 + (4) + 9 + (1 + 8) + 4 = 70, which is divisible by 10; the digit-sums of the doubled digits have been shown in parentheses.

Your task is to write two functions, one that adds a check digit to a identifying number and one that tests if an identifying number is valid. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 14 Responses to “Credit Card Validation”

```import Data.Char
import Data.List.HT

luhnSum :: Integral a => a -> a
luhnSum n = digitSum a + digitSum (show . (* 2) . digitToInt =<< b)
where [a,b] = sliceHorizontal 2 . reverse \$ show n
digitSum = sum . map (fromIntegral . digitToInt)

isValid :: Integral a => a -> Bool
isValid n = mod (luhnSum n) 10 == 0

makeValid :: Integral a => a -> a
makeValid n = 10*n + mod (10 - mod (luhnSum \$ 10*n) 10) 10
```
2. […] today’s Programming Praxis exercise our goal is to write to functions related to the Luhn credit card […]

3. Graham said

I came up with two versions of my intermediate Luhn sum function: one that
creates a list and modifies it in-place, and another that uses iterators
instead. My solution is available on github.

4. Jussi Piitulainen said

Just numbers; just one recursive branch / two vectors.
First I missed that (- 10 (modulo 30 10)) is 10, not 0.
Then Ikarus thought that (modulo -30 10) => 10. Sigh.

```(define (luhn-digit digits)
(define (modulo n m) (- n (* m (floor (/ n m))))) ;...
(let loop ((digits digits) (neg-sum 0)
(vig '#(0 2 4 6 8 1 3 5 7 9))
(vug '#(0 1 2 3 4 5 6 7 8 9)))
(if (zero? digits)
(modulo neg-sum 10)
(loop (quotient digits 10)
(- neg-sum (vector-ref vig (modulo digits 10)))
vug vig))))

(define (luhn? digits) (= digits (luhn (quotient digits 10))))

(define (luhn digits) (+ (* digits 10) (luhn-digit digits)))

(write (luhn? 49927398716))
(write (luhn? 3020))
(write (luhn? 3129))
(newline)
```
5. arturasl said

Wanted to see if I still remember Linux assembly so I wrote my answer in it: github. It might be possible to make the answer more readable and shorter, but that would take me an additional hour…

6. Mike said
```dd = ((0,0), (1,2), (2,4), (3,6), (4,8),
(5,1), (6,3), (7,5), (8,7), (9,9))

def luhn(ds):
'''
>>> n = "49927398716"
>>> luhn(n[:-1])
6
'''

return -sum(dd[int(d)][~n&1] for n,d in enumerate(ds[::-1])) % 10

def is_valid(ds):
'''
n = "49927398716"
>>> is_valid(n)
True
'''

return luhn(ds[:-1]) == int(ds[-1])

'''
n = "4992739871"
'49927398716'
'''

return ds + str(luhn(ds))
```
7. David said

Factor Language solution.

```USING: kernel math math.parser math.ranges sequences ;
IN: luhn

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

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

: luhn? ( n -- ? )
luhn-sum 10 mod 0 = ;

: make-luhn ( n -- n )
10 * dup luhn-sum 10 mod 10 swap - 10 mod + ;
```

( scratchpad ) 2771 luhn? .
f
( scratchpad ) 2771 make-luhn dup . luhn? .
27714
t
( scratchpad ) 49927398716 luhn? .
t
( scratchpad ) 49927398716 make-luhn dup . luhn? .
499273987168
t

8. […] or Canadian Social Insurance Numbers are validated you can take a look at this Programming Praxis article . It’s all about a simple, tiny, patented (now public domain) algorithm invented by […]

9. My python 3.x solution:

```def luhn_check(num):
''' Number - List of reversed digits '''
digits = [int(x) for x in reversed(str(num))]
check_sum = sum(digits[::2]) + sum((dig//10 + dig%10) for dig in [2*el for el in digits[1::2]])
return check_sum%10 == 0

if __name__ == "__main__":
print(luhn_check(543298376
```
10. ```))
```
11. rohit said

nice solution

12. Rainer said

My try in REXX

```
numeric digits 30
debug = 0

number = '49927398716'

say number 'is' check_luhn(number)

number = '4992739871'
say number 'plus check_digit =' add_check_digit(number)

exit

check_luhn: procedure
parse arg test
test = reverse(test)
summe = 0
ind = 0
do i = 1 to length(test)
ind = ind + 1
ziffer = substr(test,i,1)
say 'Ziffer' ziffer
if even(ind) then do
ziffer = ziffer * 2
if length(ziffer) > 1 then summe = summe + left(ziffer,1)
end
summe = summe + right(ziffer,1)
say 'Summe' summe
end
if (summe//10) > 0 then return 'wrong'
else return 'correct'

parse arg urtest
test = reverse(urtest)
summe = 0
ind = 0
do i = 1 to length(test)
ind = ind + 1
ziffer = substr(test,i,1)
if odd(ind) then do
ziffer = ziffer * 2
if length(ziffer) > 1 then summe = summe + left(ziffer,1)
end
summe = summe + right(ziffer,1)
say 'Summe' summe
end
if (summe//10) > 0 then return urtest||(summe%10*10)+10-summe
else return urtest||0

even: procedure
parse arg number
return \ odd(number)

odd: procedure
parse arg number
return (number//2)

```
13. Khanh Nguyen said
```open System

let rec sum_digit inp =
if inp < 10 then inp else sum_digit (inp / 10) + (inp % 10)

let f (inp: string) =
inp.ToCharArray()
|> List.ofArray
|> List.map (fun x -> (int x) - (int '0'))
|> List.rev
|> List.zip [1.. String.length inp]
|> List.map (fun (i, v) -> if i % 2 = 1 then v*2 else v)
|> List.map sum_digit
|> List.sum

let add_check_digit (inp : string) =
inp + string(10 - (f inp) % 10)
let isValid (inp : string) =
inp = add_check_digit (inp.Remove(String.length inp - 1))

isValid "49927398715"
isValid "49927398716"

```
14. Ben Atwell said

My solution in Python 3.2

number = int(str(number)[::-1])
numString = str(number)
check = False
mySum = 0
for ch in numString:
num = int(ch)
if (check):
num = num * 2
strNum = str(num)
for c in strNum:
num2 = int(c)
mySum += num2
else:
mySum += num
check = not check
return mySum

def validate(number):
if (mySum % 10 == 0):
return True
else:
return False