The limit of precision on a double
forces the binary representation to round up to the nearest power of 2
, which increments the exponent in the floating-point representation of the double
value. This occurs because a double's mantissa, including the implied 1
bit, is 53 bits, but a long
has 64 bits.
Section 5.1.2 of the JLS covers what may happen in this widening primitive conversion:
A widening primitive conversion from int to float, or from long to float, or from long to double, may result in loss of precision - that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§4.2.4).
(emphasis mine)
Here, I use Double.doubleToLongBits
to preserve the bits of a double
in a long
, and Long.toHexString
to print out the hex values of the original double
s.
System.out.format("Max(%s): %-5d Min(%s): %-5d -1(%s): %-5d%n",
Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmax),
Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmin),
Long.toHexString(Double.doubleToLongBits(dneg)), Math.getExponent(dneg));
Output:
Max(43e0000000000000): 63 Min(43e0000000000000): 63 -1(bff0000000000000): 0
Max(43d0000000000000): 62 Min(43d0000000000000): 62 -1(43e0000000000000): 63
Max(43c0000000000000): 61 Min(43c0000000000000): 61 -1(43d0000000000000): 62
Max(43b0000000000000): 60 Min(43b0000000000000): 60 -1(43c0000000000000): 61
Max(43a0000000000000): 59 Min(43a0000000000000): 59 -1(43b0000000000000): 60
Max(4390000000000000): 58 Min(4390000000000000): 58 -1(43a0000000000000): 59
Max(4380000000000000): 57 Min(4380000000000000): 57 -1(4390000000000000): 58
Max(4370000000000000): 56 Min(4370000000000000): 56 -1(4380000000000000): 57
Max(4360000000000000): 55 Min(4360000000000000): 55 -1(4370000000000000): 56
Max(4350000000000000): 54 Min(4350000000000000): 54 -1(4360000000000000): 55
Max(433fffffffffffff): 52 Min(433fffffffffffff): 53 -1(4350000000000000): 54
Max(432ffffffffffffe): 51 Min(432ffffffffffffe): 52 -1(433fffffffffffff): 52
The original long
values with more than 53 1
bits are rounded up when converted to a double
, losing precision. The exponent field consists of bits 2
through 12
, visible in the 1st 3 hex digits printed out above.
When the value is shifted below 53 1
bits, double
's precision is now sufficient to hold the value without rounding (the round up is no longer necessary) and the mantissa's bits become visible as 'f' hex digits. There is a discontinuity in the exponent field, going from 435
to 433
, explaining why there is a discontinuity in the result of Math.getExponent
, from 54
to 52
.