Reputation: 25
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
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
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
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
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
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