-3

It was about a credit card problem. So, if the number is 16 digit and the first two digits are 51,52,53,54 or 55, the card is mastercard.

At first, I tried (51 <= j <= 55). I thought this condition makes sense. Cause j is an integer. But for some reason, the error said (51 <= j <= 55) is always true(I don't understand this!). So I had to write (j==51 || j==52 || j==53 || j==54 || j==55), which is basically the same as (51 <= j <= 55).

int j = c / pow(10,14);

if(pow(10,15) <= c < pow(10,16) && (j==51 || j==52 || j==53 || j==54 || j==55)) 
{
    printf("MASTERCARD\n");
}

The code above worked well..(I don't know why) And I had to make some changes for j, from double j to int j. I guess it's because that the number 51 to 55 are integers..?

Anyways, the error didn't say anything about pow(10,15) <= c < pow(10,16). Why can't I just use 51 <= j <= 55?

Raebbit
  • 3
  • 2
  • Are you sure of your code? ... How much bits is an `int` in your system? I'think it's 32 bits. The result of pow(10,14) is bigger the 32 bits ... It shall fit into an int64_t (better uint64_t). Try `printf("%lu\n",sizeof(int));` if the result is 4 your code cannot manage correct results. – Sir Jo Black Jan 13 '19 at 13:24
  • if c is 32 bits `int`, it's not able to contains a credit card number. As above said an `int` could be only 32 bits. With 32 bits you may represent number between about -2 billion and +2 billion. An `unsigned int` may represent from 0 to just over +4 billion. A credit card is composed of 16 decimal digit, but the greatest number with all decimal digit you may manage with a 32 bit `int` is 9. (0 to 999999999) – Sir Jo Black Jan 13 '19 at 13:32
  • 1
    @SirJoBlack my suspicion is that `c` is a `double`, which will provide more subtle errors on the last digit. – Matteo Italia Jan 13 '19 at 14:15
  • 1
    @SirJoBlack: in particular, every odd card number beyond 9007199254740992 will be mangled to become even. – Matteo Italia Jan 13 '19 at 14:21
  • @MatteoItalia, I think so. But in this case it should run good because he uses only the 2 High digits of the decimal number, but quite for sure he looses the check digit. (IMHO) it should be better to use `uint64_t` or other ways such string parsing. – Sir Jo Black Jan 13 '19 at 14:23
  • 1
    [Language support for chained comparison operators (x < y < z)](https://stackoverflow.com/q/4090845/995714), [Why do most mainstream languages not support "x < y < z" syntax for 3-way Boolean comparisons?](https://softwareengineering.stackexchange.com/q/316969/98103), [Why does (0 < 5 < 3) return true?](https://stackoverflow.com/q/4089284/995714). Besides, `pow(10, 15)` is better written as `1e15` – phuclv Jan 13 '19 at 14:57
  • 1
    @SirJoBlack c was credit card number and it was long long – Raebbit Jan 13 '19 at 15:32
  • 1
    @phuclv Ah, thank you. I was trying to find 10^15 in C. And I end up finding power function. So, if I use 1e15 ,,, does that mean doesn't need to be included? – Raebbit Jan 13 '19 at 15:35
  • 1
    @rae ... then it's better you use long long also into the function! And I think it's better you keep in mind that pow(10,14) generates a value that's `double` and not `int` nor `long long`. It's not always granted the representation of a `double` is not rounded (in this case it seems ok!) – Sir Jo Black Jan 13 '19 at 16:43
  • @rae For example is not a good idea, considering v as double, to write if (v == 0.0) {}, is a good idea to write if (v < 0.00000001) {} where it need to consider the min value we need. – Sir Jo Black Jan 13 '19 at 16:46

2 Answers2

7

Why can't I just use 51 <= j <= 55

Because that's a "special case" in parsing that is obvious to your mind because you are used to it, but is not obvious at all in C expressions syntax.

If you apply the parsing and precedence rules of C you will get an expression that it's likely not what you want:

51 <= j <= 55

is parsed as

(51 <= j) <= 55

51 <= j is a boolean expression that evaluates to either 1 (if 51 is indeed less or equal than j) or 0 otherwise. Both 0 and 1 are less than 55, so the expression result is always 1 (true).

To make it do what you want, you have to explicitly transform this to

(51 <= j) && (j <= 55)

Other languages such as Python are instead able to make a more "human" sense of such an expression, introducing the concept of chained comparisons, that specifies how to convert a sequence of multiple chained comparisons to a sequence of single comparisons ANDed together, but it's a trick that's outside how "classical" expression evaluators work (and that can lead to surprises).


Incidentally, it looks like you are trying to use floating point numbers to store/manipulate the 16 digits of a credit card number. That's a terrible idea, as double has 53 bits of mantissa, which are slightly less than 16 digits of decimal precision. This means that, for credit card numbers "on the bigger side", the last digit may not be stored correctly. More precisely, every credit card number beyond 9007 1992 5474 0992 with last digit odd will be mangled and rounded to an even number.

So, just use an array of integers and you'll avoid nasty surprises.

More in general, avoid double and floating point if you are interested in the exact values of digits, unless you know exactly what you're doing.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
1

Use (51 <= j) && (j <= 55).

The <= operator produces a boolean result (ie either 1 or 0). If you want to check that j is within the bounds of a range, you need produce a boolean value for both ends, then 'and' the result.

When you chain comparison operators like '<=', they get evaluated from left to right. For what your tried, it doesn't matter what j is as the result of the first <= operator is either 1 or 0, which is always less than 55. Thus the final result is always true.

Some languages may have different rules for chaining comparison operators which is more in line with the way they are used mathematically, but definitely not C!

Graeme
  • 2,971
  • 21
  • 26