P.H.
P.H.

Reputation: 25

Use if-else to evaluate the starting number and the length of a number in C

I am a beginner of C.
I try to use if-else to evaluate if a number starts with 4 and has certain digit. It is fine when I test it with card_num = 4000000000000000, but I have no clue why it goes to else when I test with other numbers that start with 4 and have same length, such as card_num = 4003600000000014. These two numbers are supposed to have same result.
Please help me! Thanks!

    int main(void)
    {
    
        long card_num;
        card_num = 4003600000000014;
    
        if ( (card_num / 1e12 == 4 || card_num / 1e15 == 4) )
        {
            printf("Valid\n");
        }
        else
        {
            printf("Invalid\n");
        }
    
    }

Upvotes: 0

Views: 967

Answers (5)

Eric Postpischil
Eric Postpischil

Reputation: 223747

1e15 is a double constant, so using it in an expression results in floating-point arithmetic being used. When card_num is 4003600000000014, the result of card_num / 1e15 is approximately 4.003600000000014 (approximate because of floating-point), so card_num / 1e15 == 4 is of course false, causing program control to flow to the else.

You could solve the instant issue by using floor(card_num / 1e15) == 4, but that is not a good idea. Do not use floating-point arithmetic for manipulating integers (at least until you learn thoroughly about floating-point arithmetic and have good reason for this).

You could also solve the instant issue by using card_num / 1000000000000000 == 4, but that is not a great idea. Avoid using numeric types for manipulating credit card identifiers. Credit card “numbers” are actually strings of digits; they are not intended to represent numbers. E.g., credit card 4003600000000014 is not the four-quadrillionth-and-some card issued, the “4” is a code for the issuer. Aside from the digits not being intended to represent numbers, there are so many of them that they cause problems with the standard C numeric types.

Preferably, you should read the credit card “number” as a string (and then check that the user entered only digits, and an acceptable number of digits, for it). If you must read it as a number, convert it to a string (perhaps with sprintf, or snprintf if you want to practice writing safe code) immediately after reading it and work with it as a string.

Upvotes: 1

Dominique
Dominique

Reputation: 17565

As you are a beginner, let me give you some tips: you say that you are working on a collection of digits, meaning a cardnumber, and you want to do some calculation on that. What type will you use for that?

In case you are doing mathematical calculations, then using a number type (like int or long) might be a good idea.
In case you might be using "text-alike" functionalities, then it might be useful working with a string or an array of characters.

What do you mean by "text-alike" functionalities?
Well, imagine you want to do something with a certain digit (like the third one). You might get that digit using the following calculation:

(cardnumber / 1E13) MOD 10

Why 1E13? Because I imagine your number being 15 digits long, and division by 1E13 is what you need to find the third digit.

Wouldn't it be far more easy to do this:

cardnumber[3]

In other words, just access the third digit.

Luckily, in your case, you only need the first digit, so the integer division by 1E15 gives you what you need.

So, choosing a number type is ok for this particular case.

Then, there's the thing about which number type: as you mention your cardnumber have a size of about 1E15, while the maximum long number seems to be about 2E9, so this is not a good type for this. It seems, however, that long long, with a maximum of about 9E18, is more suited for this.

As far as the second part of your if-condition, the division by 1E12: as your number has a length of 15 digits (the first one never being zero, I guess), this condition is useless.

Upvotes: 0

Hassan Ramadan
Hassan Ramadan

Reputation: 1

Using long built-in datatype with values not exist on [−2,147,483,647, +2,147,483,647] range causes an overflow, so you have to use long long datatype to wide your range to [−9,223,372,036,854,775,807, +9,223,372,036,854,775,807] range.

You can also use the unsigned keyword before the datatype to shift the range to positive values only (e.g. unsigned long long's range is [0, +18,446,744,073,709,551,615] ).

Upvotes: 0

AKX
AKX

Reputation: 169338

The maximum value for a long is may be, depending on your architecture, 2,147,483,647, and 4,003,600,000,000,014 is way more than that.

(Credit) card numbers aren't something you do math on, so store it as a string and do those operations on the string instead.

Upvotes: 0

Enrico
Enrico

Reputation: 120

Convert your long into string using sprintf:

char bigbuff[12];
long num = 4003600;
sprintf(bigbuff, "%ld", num);

Now bigbuff[0] contains the first digit (as character) and strlen(num) gives the length of your initial number.

Upvotes: 0

Related Questions