-1

I tried to make a C program that checks if a bank card is valid.

According to Luhn’s algorithm, you can determine if a credit card number is (syntactically) valid as follows:

Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products' digits together.

Add the sum to the sum of the digits that weren’t multiplied by 2.

If the total’s last digit is 0 (or, put more formally, if the total modulo 10 is congruent to 0), the number is valid!

That’s kind of confusing, so let’s try an example with my AmEx: 378282246310005.

For the sake of discussion, let’s first underline every other digit, starting with the number’s second-to-last digit:

378282246310005

Okay, let’s multiply each of the underlined digits by 2:

7•2 + 2•2 + 2•2 + 4•2 + 3•2 + 0•2 + 0•2

That gives us:

14 + 4 + 4 + 8 + 6 + 0 + 0

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

1 + 4 + 4 + 4 + 8 + 6 + 0 + 0 = 27

Now let’s add that sum (27) to the sum of the digits that weren’t multiplied by 2:

27 + 3 + 8 + 8 + 2 + 6 + 1 + 0 + 5 = 60

Yup, the last digit in that sum (60) is a 0, so my card is legit!

So, validating credit card numbers isn’t hard, but it does get a bit tedious by hand

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

int length(long long n);
int num_at(int x,long long y);
long long flip(double a);

int main(void)
{
    //int total2=0;
    //printf("Number: ");
    //int i=get_int();
    long long ll=get_long_long();
    //if (ll<=0)
    //{
    //    printf("INVALID\n");
    //}
    //for (int i=1;2*i<length(ll);i++)
    //{
    //    total2=total2+2*num_at(i,ll);
    //}
    //int total1=0;
//for (int i=0;2*i<length(ll);i++)
//{
//    total1=total1+num_at(i,ll);
//}
//int total=total1+total2;
//printf("%i\n",total);
printf("%lli\n",flip(ll));
}

int length(long long n)/* length of number */
{
    long long x=1;
    int len=0;
    while(n-n%x!=0)/* x % y means x mod y*/
    {
        len++;
        x=x*10;
    }
        return len;
}
int num_at(int x,long long y)/* digit at specific spot in number */
{
    int digit=0;//the digit at position z(see below)
    int z=1;
    for(z=x;z>=0;z--)
    {
        digit=y%10;
        y=y-y%10;
        y=y/10;
    }
    return digit;
}
long long flip(double a)//flips a
{
    long long b=0;
    for(int y=0;y<length(a);y++)
    {
        b=b*10;
        b=b+(a%pow(10.0,y+1)-a%pow(10.0,y))/pow(10.0,y);
    }
    return b;
}

The error when compiling is:

credit.c:99:15: error: invalid operands to binary expression ('double' and 'double')
    b=b+(a%pow(10.0,y+1)-a%pow(10.0,y))/pow(10.0,y);
         ~^~~~~~~~~~~~~~
credit.c:99:31: error: invalid operands to binary expression ('double' and 'double')
    b=b+(a%pow(10.0,y+1)-a%pow(10.0,y))/pow(10.0,y);
                         ~^~~~~~~~~~~~
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
wang ray
  • 27
  • 1
  • 10

4 Answers4

1

You cannot perform the modulus operation on double(or floats). This is for the simple reason that remainders are defined only for integer arithmetic. What would be the remainder if I divide 2.3 by 0.4??

So to do what you want you need to cast the double ( a and the result of pow) as long long.

So you can do ((long long) a) % (long long) pow( ... ) and it should be fine.

In the future you should look at the error messages (and also the warnings).

Here it clearly says invalid operands to binary expression and % operator is marked.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
1

pow returns a double and % operator is defined only for integers. I think that should solve your problem.

klbm9999
  • 31
  • 1
  • 9
1

Algo should be more simple that you write it. I'm not a C programmer but:

// transform LL to char []
int len = length(ll);
char card[len];
sprintf(card, "%lld", ll);
int sum =0;
for(i=0;i < len; i++)
{
    int num = card[i] - '0';
    if(i % 2 == 0)
    { sum += num; }
    else
    { 
        int tmp = num * 2; 
        sum += (tmp / 10);
        sum += (tmp % 10);
    }
}

if(sum % 10)
{ 
     // card valid 
}

Is more readable in my opinion. (Sorry if typo, this post was written with an old smartphone...)

EDIT I know you like using loops but your num_at could also be enhanced :

int num_at(int pos, long long x)
{
     return (x / (int)pow(10, pos)) % 10;
}
Arnaud F.
  • 8,252
  • 11
  • 53
  • 102
0

How do you expect to do a modulo operation (%) between two double values?

What is 10.3 % 5.2, exactly?

The error message is simply saying, "You cannot do double-modulo-double"

abelenky
  • 63,815
  • 23
  • 109
  • 159