3

I am trying to finish an assignment in C for the CS50 course in which I must implement Luhn's algorithm to validate a credit card number. Here is a quick example to elaborate:


credit card number: 4003600000000014.
Now for every other digit, starting with the number’s second-to-last digit:

1-0-0-0-0-6-0-4

Let’s multiply each of the digits by 2:

1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2

That gives us:

2 + 0 + 0 + 0 + 0 + 12 + 0 + 8

Now let’s add those products’ digits (i.e., not the products themselves) together:

2 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 8 = 13

Now let’s add that sum (13) to the sum of the digits that weren’t multiplied by 2 (starting from the end):

13 + 4 + 0 + 0 + 0 + 0 + 0 + 3 + 0 = 20

Yup, the last digit in that sum (20) is a 0, so the number is valid.


I figured out how to extract each number in the credit card individually (I know my way is boring and probably not practical), so the next step is to multiply every other number by two and add (the products' digits, not the digits themselves) and this is what I need help of how to do it? MY code:

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

int main(void)
{
    long credit_card_number;
    do
    {
        credit_card_number = get_long("Enter your credit card number: ");

    }
    while (credit_card_number < 1 || credit_card_number > 9999999999999999);

    //American Express uses 15-digit numbers. American Express numbers start with 34 or 37
    //MasterCard uses 16-digit numbers. MasterCard numbers start with 51, 52, 53, 54, or 55.
    //Visa uses 13- and 16-digit numbers. Visa numbers start with 4.
    // checksum

    long last_number;
    long credit_card_without_last_number;
    long second_to_last_number;
    long credit_card_without_second_number;
    long third_number;
    long credit_card_without_third_number;
    long fourth_number;
    long credit_card_without_fourth_number;
    long fifth_number;
    long credit_card_without_fifth_number;
    long sixth_number;
    long credit_card_without_sixth_number;
    long seventh_number;
    long credit_card_without_seventh_number;
    long eighth_number;
    long credit_card_without_eighth_number;
    long ninth_number;
    long credit_card_without_ninth_number;
    long tenth_number;
    long credit_card_without_tenth_number;
    long eleventh_number;
    long credit_card_without_eleventh_number;
    long twelfth_number;
    long credit_card_without_twelfth_number;
    long thirteenth_number;
    long credit_card_without_thirteenth_number;
    long fourteenth_number;
    long credit_card_without_fourteenth_number;
    long fifteenth_number;
    long credit_card_without_fifteenth_number;
    long sixteenth_number;

    long multiply_digits;

    //separating each number starting from the last (right)in its own variable.
    last_number = credit_card_number % 10;
    credit_card_without_last_number = credit_card_number / 10;

    second_to_last_number = credit_card_without_last_number % 10;
    credit_card_without_second_number = credit_card_without_last_number / 10;

    third_number = credit_card_without_second_number % 10;
    credit_card_without_third_number = credit_card_without_second_number / 10;

    fourth_number = credit_card_without_third_number % 10;
    credit_card_without_fourth_number = credit_card_without_third_number / 10;

    fifth_number = credit_card_without_fourth_number % 10;
    credit_card_without_fifth_number = credit_card_without_fourth_number / 10;

    sixth_number = credit_card_without_fifth_number % 10;
    credit_card_without_sixth_number = credit_card_without_fifth_number / 10;

    seventh_number = credit_card_without_sixth_number % 10;
    credit_card_without_seventh_number = credit_card_without_sixth_number / 10;

    eighth_number = credit_card_without_seventh_number % 10;
    credit_card_without_eighth_number = credit_card_without_seventh_number / 10;

    ninth_number = credit_card_without_eighth_number % 10;
    credit_card_without_ninth_number = credit_card_without_eighth_number / 10;

    tenth_number = credit_card_without_ninth_number % 10;
    credit_card_without_tenth_number = credit_card_without_ninth_number / 10;

    eleventh_number = credit_card_without_tenth_number % 10;
    credit_card_without_eleventh_number = credit_card_without_tenth_number / 10;

    twelfth_number = credit_card_without_eleventh_number % 10;
    credit_card_without_twelfth_number = credit_card_without_eleventh_number / 10;

    thirteenth_number = credit_card_without_twelfth_number % 10;
    credit_card_without_thirteenth_number = credit_card_without_twelfth_number / 10;

    fourteenth_number = credit_card_without_thirteenth_number % 10;
    credit_card_without_fourteenth_number = credit_card_without_thirteenth_number / 10;

    fifteenth_number = credit_card_without_fourteenth_number % 10;
    credit_card_without_fifteenth_number = credit_card_without_fourteenth_number / 10;

    sixteenth_number = credit_card_without_fifteenth_number % 10;

    //Here I need the help to multiply these numbers by two and then add each product's
    //digits to the rest of the unused numbers.
    multiply_digits = (second_to_last_number*2)+(fourth_number*2)+(sixth_number*2)+(eighth_number*2)+(tenth_number*2)+(twelfth_number*2)+(fourteenth_number*2)+(sixteenth_number*2);

}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Bryce
  • 71
  • 8
  • Your program would be much simpler using a loop. To add the digits of the product, calculate the product first, then if it is <10 simply add it, if it is >=10 add product -10 + 1. (A digit multiplied by 2 must be less than 20, so the first digit can only be 1 or 0.) Entering the credit card number as a string instead of a number might also simplify processing it digit-by-digit. – Bodo Apr 29 '20 at 15:56
  • You should consider reading the card number as a string so that the digits are simply encoding as ASCII characters. It makes the processing much (much, much) easier. Writing the variable names out like that cries for an array. Also notice that a `long` is not guaranteed to be able to hold more than 9 decimal digits (it could be a 32-bit value). For safety, if you're going to use numbers, you need to use `long long` which is guaranteed to be at least 64 bits long. – Jonathan Leffler May 03 '20 at 15:35

3 Answers3

1

Try doing this instead

int main(){
    long cNo = 4003600000000014;
    int arr[16];

    for(int i=0; i<16; i++){
        arr[15-i] = cNo % 10;
        cNo /= 10;
    }

    int multipliedSum = 0;
    for(int i=0; i<16; i++){
        if(i%2==1)
            multipliedSum += arr[i];
        else{
            if(arr[i]*2<10){
                multipliedSum += (arr[i]*2);
            }else{
                int num = arr[i]*2;
                while(num){
                    multipliedSum += num%10;
                    num/=10;
                }
            } 
        }
    }

    printf("valid = %s\n",multipliedSum%10==0?" True": " False");
}

You will get the following

valid = True

Bodo
  • 9,287
  • 1
  • 13
  • 29
Jackson
  • 1,213
  • 1
  • 4
  • 14
  • Instead of storing all digits in an array and then processing the digits in a separate loop, you could do everything in the second loop: `for(int i=0; i<16; i++){ long digit = cNo % 10; cNo /= 10; if(i%2) multiplied sum += digit; else ...` and replace all `arr[i]` with `digit`. (Admittedly your solution is nearer to the original code.) – Bodo Apr 29 '20 at 16:49
  • I didnt do that because it seems he has some extra manipulation involved like subtraction of some sort. Thus i left it a little more modularized. Anyway thanks for pointing out. – Jackson Apr 29 '20 at 16:51
1

A general algorithm for adding digits (assuming an integer type):

  1. Initialize your sum to 0: sum = 0
  2. Extract the lowest digit from the number using the % modulus operator: digit = number % 10
  3. Add the value of that digit to the sum: sum += digit (shorthand for sum = sum + digit)
  4. Divide the number by 10: number /= 10 (shorthand for number = number / 10
  5. If the number is non-zero after dividing by 10, go back to 2
  6. End

The modulus operator % returns the integer remainder of an integer division - 123 / 10 == 12 rem 3. So the remainder of dividing the number by 10 is the least significant decimal digit of the number. Notice that integer division gives you an integer result - 123 / 10 == 12, not 12.3.

You'll want to put this in a separate function, so you can write something like

int sumdig( int v )
{
  ...
}

int main( void )
{
   int value = 123;
   int sum = sumdig( value ); // sumdig will return 1 + 2 + 3, or 6
   ...
}

When you find yourself creating a bunch of separate variables of the same type with the same name except for some tacked-on ordinal (var1, var2, var3 or first_thing, second_thing, third_thing), that's a real strong hint you want to use an array. You can use an array to store the individual digits of your card number:

int number[16];

and use the % 10 method as described above to extract the individual digits:

long tmp = credit_card_number; // use a temporary so we preserve the original card number
for ( int i = 0; i < 16; i++ )
{
  number[i] = tmp % 10;
  tmp /= 10;
}

This means that the least significant (rightmost) card number digit will be stored in number[0] and the most significant (leftmost) card number digit will be stored in number[15], so be aware of that. For the purposes of validating the number it doesn't matter, but if you want to display the contents of the array you'll have to take that into account.

Using an array makes it easier to extract subsets of digits:

for ( int i = 1; i < 16; i += 2 ) // hit every other element starting at element 1
{
  number[i] *= 2; // multiply these digits by 2
}

That loop above executes the "1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2" portion of your algorithm.

You should be able to figure out the rest from there. Hope this helps.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Hint: to extract one digit from a number, mod it by 10. So say that you want to figure out the sum of the digits of a number, say 123456, you will do the following: (pseudocode)

number=123456;
sum=0;
loop if number is not 0{
sum+=number % 10;
number-=number % 10;
number=(int)(number/10);
}

Now try to implement it as a function, say digit(), and when you are trying to add some numbers digit-wise, say 123 and 456, just do digit(123)+digit(456) instead.

user12986714
  • 741
  • 2
  • 8
  • 19
  • extracting the digits might already work although it is implemented in a strange way. If I understood correct, the main point of the question is for every other digit how to add the one or two digits of the product individually instead of adding the product as a whole. – Bodo Apr 29 '20 at 16:03
  • So extract the digits that one do not want to add as a whole; and add the extracted digits :-) – user12986714 Apr 29 '20 at 16:11
  • I don't understand what you mean with your comment. My comment was a hint that you don't answer the main point of the question, you only suggest to improve the processing of the digits. So I suggest to extend your proposal to include a solution for multiplying every other digit with 2 and adding the product digit-wise. – Bodo Apr 29 '20 at 16:22
  • @Bodo Thank you. Would you think that after edit it answers the question? Or maybe I misunderstood what the question is... – user12986714 Apr 29 '20 at 16:27
  • Citation from the question: *so the next step is to multiply every other number by two and add (the products' digits, not the digits themselves) and this is what I need help of how to do it* Look at the example. *Let’s multiply each of the digits by 2:* `... 6•2 ...` *That gives us:* `... 12 ...` *Now let’s add those products’ digits (i.e., not the products themselves) together:* `... + 1 + 2 ...` – Bodo Apr 29 '20 at 16:41