1

I'm learning c, and am confused as my code seems to evaluate ( 1e16 - 1 >= 1e16 ) as true when it should be false. My code is below, it returns

9999999999999999 INVALIDBIG\n

when I would expect it not to return anything. I thought any problems with large numbers could be avoided by using long long.

int main(void)
{
    long long z;

    z = 9999999999999999;

    if ( z >= 1e16 || z < 0 )
    {
        printf("%lli INVALIDBIG\n",z);
    }
}
strawman
  • 21
  • 2

2 Answers2

3

1e16 is a double type literal value, and floats/doubles can be imprecise for decimal arithmetic/comparison (just one of many common examples: decimal 0.2). Its going to cast the long-long z upwards to double for the comparison, and I'm guessing the standard double representation can't store the precision needed (maybe someone else can demonstrate the binary mantissa/sign representations)

Try changing the 1e16 to (long double)1e16, it doesn't then print out your message. (update: or, as the other question-commenter added, change 1e16 to an integer literal)

Breezer
  • 483
  • 3
  • 10
1

The doubles and floats can hold limited number of digits. In your case the double numbers with values 9999999999999999 and 1e16 have identical 8 bytes of hex representation. You can check them byte by byte:

long long z = 9999999999999999;
double dz1 = z;
double dz2 = 1e16;

/* prints 0 */
printf("memcmp: %d\n", memcmp(&dz1, &dz2, sizeof(double)));

So, they are equal.

Smaller integers can be stored in double with perfect precision. For example, see Double-precision floating-point format or biggest integer that can be stored in a double

The maximum integer that can be converted to double exactly is 253 (9007199254740992).

Community
  • 1
  • 1
Orest Hera
  • 6,706
  • 2
  • 21
  • 35