Implementation of Luhn Formula

30,920

Solution 1

I think the algorithm is not correct.

The second step you need to sum the digits of the products instead of substract 9. Reference: Wikipedia.

In the Wikipedia you have this example:

def luhn_checksum(card_number):
    def digits_of(n):
        return [int(d) for d in str(n)]
    digits = digits_of(card_number)
    odd_digits = digits[-1::-2]
    even_digits = digits[-2::-2]
    checksum = 0
    checksum += sum(odd_digits)
    for d in even_digits:
        checksum += sum(digits_of(d*2))
    return checksum % 10

def is_luhn_valid(card_number):
    return luhn_checksum(card_number) == 0


result = is_luhn_valid(4532015112830366)
print 'Correct:' + str(result)
result = is_luhn_valid(6011514433546201)
print 'Correct:' + str(result)
result = is_luhn_valid(6771549495586802)
print 'Correct:' + str(result)

Result:

>>>Correct:True
>>>Correct:True
>>>Correct:True

Solution 2

This is the most concise python formula for the Luhn test I have found:

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

The above function and other Luhn implementations (in different programming languages) are available in https://www.rosettacode.org/wiki/Luhn_test_of_credit_card_numbers .

Solution 3

I'd keep it simple and easy to read, something like this:

def luhn(value):
    digits = list(map(int,str(value))
    oddSum = sum(digits[-1::-2])
    evnSum = sum([sum(divmod(2 * d, 10)) for d in digits[-2::-2]])
    return (oddSum + evnSum) % 10 == 0

But there's tons of ways to do the same thing. Obviously, you'd have to do it differently to see the actual output, this just sums up the total to determine if the value is valid.

Best!

Solution 4

see this Python recipe

def cardLuhnChecksumIsValid(card_number):
    """ checks to make sure that the card passes a luhn mod-10 checksum """

    sum = 0
    num_digits = len(card_number)
    oddeven = num_digits & 1

    for count in range(0, num_digits):
        digit = int(card_number[count])

        if not (( count & 1 ) ^ oddeven ):
            digit = digit * 2
        if digit > 9:
            digit = digit - 9

        sum = sum + digit

    return ( (sum % 10) == 0 )

Solution 5

There are some errors in your code:

result = divmod(sum_of_digits, 10)

returns a tuple, you need only modulo, that is use

result = sum_of_digits % 10

Second, to check for validity, you don't omit last digit (that is checksum), but include it in computations. Use

reverse_sequence = list(int(d) for d in str(int(number[::-1]))) 

And check for result being zero:

if not result:
    print("[VALID] %s" % number)

Or if you insist on keeping this not needed complexity, check for last digit to be inverse of checksum modulo 10: keep

reverse_sequence = list(int(d) for d in str(int(number[-2::-1])))

but use

if (result + last_digit) % 10 == 0:
    print("[VALID] %s" % number)

For a simplier and shorter code, I can give you a reference to my older answer.

Share:
30,920
JChris
Author by

JChris

Updated on July 22, 2021

Comments

  • JChris
    JChris almost 3 years

    I was trying to implement the Luhn Formula in Python. Here is my code:

    import sys
    
    
    def luhn_check(number):
        if number.isdigit():
            last_digit = int(str(number)[-1])
            reverse_sequence = list(int(d) for d in str(int(number[-2::-1])))
    
            for i in range(0, len(reverse_sequence), 2):
                reverse_sequence[i] *= 2
    
            for i in range(len(reverse_sequence)):
                if reverse_sequence[i] > 9:
                    reverse_sequence[i] -= 9
    
            sum_of_digits = 0
            for i in range(len(reverse_sequence)):
                sum_of_digits += reverse_sequence[i]
    
            result = divmod(sum_of_digits, 10)
    
            if result == last_digit:
                print("[VALID] %s" % number)
            else:
                print("[INVALID] %s" % number)
            quit()
    
        print("[ERROR] \" %s \" is not a valid sequence." % number)
        quit()
    
    
    def main():
        if len(sys.argv) < 2:
            print("Usage: python TLF.py <sequence>")
            quit()
    
        luhn_check(sys.argv[1])
    
    if __name__ == '__main__':
        main()
    

    But it isn't working properly:

    [INVALID] 4532015112830366
    [INVALID] 6011514433546201
    [INVALID] 6771549495586802
    

    and so on...

    But the logic of the code seems OK to me. I followed this workflow:

    The Luhn Formula

    1. Drop the last digit from the number. The last digit is what we want to check against Reverse the numbers

    2. Multiply the digits in odd positions (1, 3, 5, etc.) by 2 and subtract 9 to all any result higher than 9

    3. Add all the numbers together

    4. The check digit (the last number of the card) is the amount that you would need to add to get a multiple of 10 (Modulo 10)