Home > Software design >  Unusual behavior with Luhn's algorithm in C
Unusual behavior with Luhn's algorithm in C

Time:07-05

I've been doing a CS50 course and stumbled upon this "Credit" problem. At the moment I'm testing it and due to insufficient cases provided in worksheet, I went to the recommended PayPal testing card numbers: https://developer.paypal.com/api/nvp-soap/payflow/integration-guide/test-transactions/#standard-test-cards Particularly:

  • Mastercard 5555555555554444
  • Mastercard 5105105105105100
  • Mastercard 5199999999999991
  • Mastercard 5299999999999990

These refuse to cooperate. My program calculates the Luhn's value for them, and it's not close to being a multiplier of 10; am I missing something, because other providers are working perfectly fine.

Results from code check:

:( identifies 5555555555554444 as MASTERCARD
    expected "MASTERCARD\n", not "114\nINVALID\n..."
:( identifies 5105105105105100 as MASTERCARD
    expected "MASTERCARD\n", not "47\nINVALID\n"

My code:

#include <stdio.h>
#include <cs50.h>

int get_sum_from_second_to_last(long temp_number);

int get_sum_from_odd_digits(long temp_number);

int length(long temp_number);

int return_first_n_digits(int n, long temp_number, int length);

int main()
{
    int final_sum = 0;
    long number = 0;
    do
    {
        number = get_long("Number: ");
    }
    while(number<0);
    final_sum = get_sum_from_second_to_last(number)   get_sum_from_odd_digits(number);
    printf("%i\n", final_sum);
    if(final_sum % 10 == 0)
    {
        if(length(number) == 15 && (return_first_n_digits(2, number, length(number)) == 34 || return_first_n_digits(2, number, length(number)) == 37))
        {
            printf("AMEX\n");
        }
        else
        {
            if((length(number) == 16 || length(number) == 13) && return_first_n_digits(1, number, length(number)) == 4)
            {
                printf("VISA\n");
            }
            else
            {
                if(length(number) == 16 && (return_first_n_digits(2, number, length(number)) == 51 || return_first_n_digits(2, number, length(number)) == 52 || return_first_n_digits(2, number, length(number)) == 53 || return_first_n_digits(2, number, length(number)) == 54 || return_first_n_digits(2, number, length(number)) == 55))
                {
                    printf("MASTERCARD\n");
                }
                else
                {
                    printf("This card provider recognition is not supported\n");
                }
            }
        }
    }
    else
    {
        printf("INVALID\n");
    }
}

int get_sum_from_second_to_last(long temp_number)
{
    int digit_current = 0;
    int counter = 1;
    int sum = 0;
    do
    {
        digit_current = temp_number % 10;
        if(counter%2 == 0)
        {
            if((digit_current*2)!=0)
            {
                sum = sum   (digit_current*2)   (digit_current*2)/10;
            }
            else
            {
                sum = sum   digit_current*2;
            }
        }
        temp_number = temp_number/10;
        counter  = 1;
    }
    while(temp_number);
    return sum;
}

int get_sum_from_odd_digits(long temp_number)
{
    int digit_current = 0;
    int counter = 1;
    int sum = 0;
    do
    {
        digit_current = temp_number % 10;
        if(counter%2 != 0)
        {
            sum = sum   digit_current;
        }
        temp_number = temp_number/10;
        counter  = 1;
    }
    while(temp_number);
    return sum;
}

int length(long temp_number)
{
    int counter = 0;
    do
    {
        temp_number = temp_number/10;
        counter  ;
    }
    while(temp_number);
    return counter;
}

int return_first_n_digits(int n, long temp_number, int length)
{
    int i;
    for(i = 0; i < length - n; i  )
    {
        temp_number = temp_number/10;
    }
    return temp_number;
}

CodePudding user response:

The issue appears to be in your function for summing up the even numbered digits in the int get_sum_from_second_to_last function. In that function, the digits are multiplied by a factor of two. Then according to information on how the Luhn's algorithm is supposed to work, if the result is a two-digit number, those digits are then supposed to be added together to derive a single digit. It appears that doesn't always happen with the current testing within that function. Since the value of multiplying one digit by "2" can only result in two-digit numbers from "10" to "18", one can effectively derive the summation of the digits by just subtracting the value of "9" from the calculated result.

With that, I offer up the following code snippet as an alternative summation of the even-numbered digits.

int get_sum_from_second_to_last(long temp_number)
{
    int digit_current = 0;
    int counter = 1;
    int sum = 0;
    do
    {
        digit_current = temp_number % 10;
        if(counter%2 == 0)
        {
            if((digit_current*2) > 9)
            {
                sum = sum   (digit_current * 2 - 9);
            }
            else
            {
                sum = sum   digit_current * 2;
            }
        }
        temp_number = temp_number/10;
        counter  = 1;
    }
    while(temp_number);

    printf("Even digit sum: %d\n", sum);

    return sum;
}

FYI, you can leave out the printf() call. I added that just for some visual clarification.

With that change, I tested out the four sample numbers in your narrative and they all produced a valid MASTERCARD result.

Number: 5299999999999990
Even digit sum: 64
Current digit: 0
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 2
Odd digit sum: 56
Final sum: 120
MASTERCARD

As a further test, I actually tested out a number for AMEX and for VISA and those worked as well.

I hope that clarifies things.

Regards.

  • Related