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
?
why
a == b
? I know thatc == 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 not9223372036854775800
?
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.