Search code examples
c++doublelong-long

confuse in "double to long long" in c++


my code:

int main()
{
long long a = pow(2,63) - 1;
long long b = pow(2,63);
double c  = pow(2,63) - 1;
double d = pow(2,63);
printf("%lld %lld \n%f %f \n%lld %lld\n", a, b, c, d, (long long)c, (long long)d);

return 0;
}

and the excute result is (codeblock with gcc in win7 x64):

9223372036854775807 9223372036854775807
9223372036854775800.000000 9223372036854775800.000000
-9223372036854775808 -9223372036854775808

Question:

Why a == b ?

I know that c == d because of the precision of double.

But why (long long)c and (long long)d is not 9223372036854775800 ?

And why (long long)c != a and (long long)d != b?


Solution

  • why a == b? I know that c == d because of the precision of double.

    For exactly the same reason. There are no overloads of pow for integer types, so the arithmetic is done using double. Since double typically has 52 bits of significance, adding or subtracting 1 to a value as large as 263 will have no effect.

    why (long long)c and (long long)d is not 9223372036854775800?

    Because long long is a 64-bit signed type, and the maximum representable value is 263-1. c and d might both have the value 263 (or even a slightly larger value), which is out of range. On a typical 2s-complement platform, this is likely to overflow to give a value around -263, as you observe. But note that this is undefined behaviour; you cannot rely on anything if a floating point conversion overflows.

    why (long long)c != a and (long long)d != b?

    I don't know; for me, a and b have the same large negative values. It looks like some quirk of your implementation caused a and b to end up with the value 263-1 rather than the expected 263. As always when dealing with floating-point numbers, you should expect small rounding errors like that.

    You could get the exact result by using integer arithmetic:

    long long a = (1ULL << 63) - 1;
    unsigned long long b = 1ULL << 63;
    

    Note the use of unsigned arithmetic since, as mentioned above, the signed (1LL << 63) would overflow.