Search code examples
cloopsfor-loopformulacs50

CS50 pset1 Credit error in checksum calculation


This is my first post on here so please tell me if i made any mistakes. I tried to find an answer to my question on here but i couldn't find anything fitting.

so i have a problem in my code for the 'Credit' problem set of CS50x's week 1. In the problemset the user has to enter a creditcard number that we have to verify as either VISA, MASTERCARD or AMEX. Otherwise the output should be INVALID.

The verification should work like this:

4 0 0 3 6 0 0 0 0 0 0 0 0 0 1 4

every second digit, starting from the second to last digit (the bold ones), is multiplied by 2 and added together. If however the multiplied digit has 2 digits, those two digits are added seperatly like:

2 * 6 = 12 so twelve will be 1 + 2

after that you take the other half of the digits (without multiplying them) and add them together so in the end you have something like

8 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 2 = 13 (for the digits displayed in bold)

and

0 + 3 + 0 + 0 + 0 + 0 + 0 + 4 = 7 (for the other half of the digits)

You add both together to get 20 (which in the problem set is called the checksum. If the last digit of the calculated number is a 0 the card is valid and after that you just have to check some conditions to tell if its an AMEX, VISA or MASTERCARD.

Conditions for the different creditcards:

American Express = 15 Digits, starting with 34 or 37

VISA = 13 or 16 Digits, starting with 4

MasterCard = 16 Digits, starting with 51, 52, 53, 54 or 55

(Sorry for the long introduction)

I tried to make a formular for this calculation but for some reason it doesn't work for all of the numbers we get to test it. I tried a lot of things to change the calculation and the conditions at the end of my code but everytime i fix one problem, another one appears and right now it feels like i thought myself into a rabbit hole so maybe i'm just too blind to see the obvious.

We only use the libraries <stdio.h> - <cs50.h> - <math.h> so far.

    long checkcredit = store;
    int sum1 = 0;
    int sum2;
    for (int duo = 0; checkcredit > 0; duo++, checkcredit /= 10)
    {
        if (duo % 2 == 0)
        {
            sum1 += (checkcredit % 10);
        }
        else
        {
            sum2 = (checkcredit % 10) * 2;
            if (sum2 >10)
            {
                sum2 = (checkcredit % 10) + 1;
            }
        }
    }
    sum1 +=sum2;
    sum1 = sum1 % 10;

This is the part in which i think the problem is since i printed out the sum1 (the calculated verification number of the long digit) and it sometimes has the wrong output.

store is the original value of the creditcard number (for example 4003600000000014)

checkcredit is just a duplication of store to work with without changing the original store value

sum1 is for the number is displayed in bold (the once that get multiplied by 2 before adding)

sum2 is for the other half of the number

duo is a digit counter for the calculation to see if i the current digit is multiplied or not (thanks to a coworker of mine who gave the hint that i could try it that way, my old version was like 4 times longer

in the end i just add sum1 and sum2 together to get the "Checksum"

There is no compiler error whatsoever, just the Check50 output

Results for cs50/problems/2021/x/credit generated by check50 v3.2.2

:) credit.c exists

:) credit.c compiles

:( identifies 378282246310005 as AMEX expected "AMEX\n", not "INVALID\n"

:( identifies 371449635398431 as AMEX expected "AMEX\n", not "INVALID\n"

:( identifies 5555555555554444 as MASTERCARD expected "MASTERCARD\n", not "INVALID\n"

:( identifies 5105105105105100 as MASTERCARD expected "MASTERCARD\n", not "INVALID\n"

:( identifies 4111111111111111 as VISA expected "VISA\n", not "INVALID\n"

:( identifies 4012888888881881 as VISA expected "VISA\n", not "INVALID\n"

:) identifies 4222222222222 as VISA

:) identifies 1234567890 as INVALID

:) identifies 369421438430814 as INVALID

:) identifies 4062901840 as INVALID

:) identifies 5673598276138003 as INVALID

:) identifies 4111111111111113 as INVALID

:) identifies 4222222222223 as INVALID

like i said i think that the error i made is in this part of the code (i even think it has something to do with the condition in the for loop) but i can't figure out what is wrong there.

Just in case the whole code is here:

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

int main(void)
{
    //Ask user for credit card number
    long store;
    do
    {
        store = get_long("Number: ");
    }
    while (store < 0);

    //calculating the amount of digits 
    long cnumber = store;
    int digits;

    for (digits = 0 ; cnumber > 0 ; digits++)
    {
        cnumber/=10;
    }

    //calculating the checksum
    long checkcredit = store;
    int sum1 = 0;
    int sum2;
    for (int duo = 0; checkcredit > 0; duo++, checkcredit /= 10)
    {
        if (duo % 2 == 0)
        {
            sum1 += (checkcredit % 10);
        }
        else
        {
            sum2 = (checkcredit % 10) * 2;
            if (sum2 >10)
            {
                sum2 = (checkcredit % 10) + 1;
            }
            //sum1 += sum2;
        }
    }
    sum1 +=sum2;
    //printf("%i ", sum1);
    sum1 = sum1 % 10;

    //conditions for varification of the card
    if (sum1 == 0)
    {
        if (digits != 13 && digits != 15 && digits != 16)
        {
            printf("INVALID\n");
        }
        else if (digits == 16 || digits == 13)
        {
            if (digits == 16 && (store >= 51e14 && store <56e14))
            {
                printf("MASTERCARD\n");
            }
            else if ((digits == 13 || digits == 16) && ((store <= 4e13 && store < 5e13)||(store >= 4e15 && store < 5e15)))
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }    
        else if (digits == 15)
        {
            if((store >= 34e13 && store < 35e13)||(store >= 37e13 && store < 38e13))
            {
                printf("AMEX\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }
    }
    else
    {
        printf("INVALID\n");
    }
}

Please ignore the conditions part at the end, i just prototyped it together to check if it works (which it does if i ignore the checksum condition)

I'm sorry for the long post and i am really thankful for everyone who takes the time to look over this and help a beginner to learn from his mistakes.

-Wannabree


Solution

  • The handling of sum2 is wrong in that it does not sum up something, but overwrites sum2 each time. A possible remedy is to initialize int sum2 = 0; and change

            {
                sum2 = (checkcredit % 10) * 2;
                if (sum2 >10)
                {
                    sum2 = (checkcredit % 10) + 1;
                }
            }
    

    to

                sum2 += "\0\2\4\6\x8\1\3\5\7\x9"[checkcredit % 10];