2

I've constructed some code to simulate Luhn's algorithm for checking the validity of credit cards. It successfully recognises American Express cards (15 digit numbers beginning in 34 or 37), but when I try Mastercard (16 digits, beginning with 51, 52, 53, 54, or 55), it doesn't recognise them. Visa cards have 13 or 16 digits and start with the digit 4, my code seems to correctly identity the 16 digit cases but not the 13 digit ones. I've gone through my code and double checked my numerical ranges and I can't seem to diagnose exactly why some cards go through but others don't. Any help would be greatly appreciated.

Edit:

I've almost fixed the problem, I've modified it, and now all the card numbers check out, but now it's recognising an invalid number (4111111111111113) as Visa. Here's my updated code:

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

long long number;

int main(void)
{
    long long i = 0;
    long long b;
    long long m = 10;
    long long n = 1;

    number = get_long_long("Number?\n");

    do
    {
        long long a = number % m;
        b = number - a;
        long long c = b % (m * 10);
        long long d = c / m;
        long long e = d * 2;
        if (e < 9)
        {
            i = i + e;
        }
        else
        {
            i = i + (e - 10 + 1);
        }
        
        {
            m = m * 100;
        }
    }
    while (b > 0);

    do
    {
        long long a = number % n;
        b = number - a;
        long long c = b % (n * 10);
        long long d = c / n;
        long long e = d;
        if (e < 9)
        {
            i = i + e;
        }
        else
        {
            i = i + (e - 10 + 1);
        }
        
        {
            n = n * 100;
        }
    }
    while (b > 0);

    int f = i % 10;
    if (((f == 0) && (number > 339999999999999) && (number < 350000000000000)) || ((number > 369999999999999) && (number < 380000000000000)))
    {
        printf("AMEX\n");
    }
    else
    if ((f == 0) && (number > 5099999999999999) && (number < 5600000000000000))
    {
        printf("MASTERCARD\n");
    }
    else
    if (((f == 0) && ((number > 3999999999999) && (number < 5000000000000))) || ((number > 3999999999999999) && (number < 5000000000000000)))
    {
        printf("VISA\n");
    }
    else
    {
        printf("INVALID\n");
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
BlueKhakis
  • 293
  • 1
  • 8
  • 1
    I might be missing something here, but where/how is this only doubling every second digit? – EdmCoff Dec 01 '20 at 16:24
  • @EdmCoff I'm using m and n as inputs for the module operators, which increment by *100 each iteration. Does that make sense? – BlueKhakis Dec 01 '20 at 16:30
  • 1
    Thank you. I did miss that. Why do both loops double the digit? (I assume your second loop should not be doubling the digits). Also, are you sure it's okay to start counting second digits from the back of the number? (e.g. for an even number of digits, like 123456, I assume you want to double 2/4/6, not 5/3/1) – EdmCoff Dec 01 '20 at 17:19
  • @EdmCoff Your observation was spot on- I don't know why I doubled the digit twice. I changed that and now it recognises all cards- however, it's still recognising an invalid sequence (4111111111111113) as Visa. – BlueKhakis Dec 01 '20 at 17:46
  • I see you've corrected the doubling issue, but I don't see a change to account for starting at the back of the number. – EdmCoff Dec 01 '20 at 17:52
  • @EdmCoff by the "back" do you mean the left hand side? I thought my code was starting from the right hand side, is it not? – BlueKhakis Dec 01 '20 at 18:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225371/discussion-between-bluekhakis-and-edmcoff). – BlueKhakis Dec 01 '20 at 18:41

1 Answers1

0

I see that you are having trouble trying to verify the length of some cards. To fix this use a function that automatically checks the length of a long. You can use some logic with the function to properly identify the Visa lengths.

Here is the function to check the length of a long variable.

int get_long_len(long value)
{
    int l = 1;
    while (value > 9)
    {
        l++;
        value /= 10;
    }
    return l;
}

It takes in the long value and returns the length.

  • I was confused at first by what you meant by "length of a long". From reading, I think you mean "the number of decimal digits if the value were printed base 10". That right? – jwd Apr 14 '21 at 23:08
  • @jwd No in C there is a variable type called long which basically is an number that can allow for more digits. An integer can only go up to a I think somewhere around 2 - 3 million while a long variable can let you assign much larger numbers. Essentially I'm saying the "length of a number variable named long" Since credit card numbers are very long it would be better to assign it to long cause sometimes the int might not accept it. –  Apr 15 '21 at 15:41
  • I understand that the type is `long`, which is generally 64 bits rather than 32 for `int`. But Those are binary numbers. Their "length" is a number of bits (in my mind, at least). But I think here you are talking about a "length" as though they were printed as "12345..." ? – jwd Apr 15 '21 at 16:44
  • Yes I am talking about the length as in count of digits like 096's length would be 3. Not the binary digits just counting what you see with C in your IDE. –  Apr 15 '21 at 19:07