9

I know about weird stuff with precision errors, but I can't fathom,

Why is (long)9223372036854665200d giving me 9223372036854665216 ?

Pacerier
  • 86,231
  • 106
  • 366
  • 634

5 Answers5

35

9223372036854665200d is a constant of type double. However, 9223372036854665200 does not fit in a double without loss of precision. A double only has 52 bits of mantissa, whereas the number in question requires 63 bits to be represented exactly.

The nearest double to 9223372036854665200d is the number whose mantissa equals 1.1111111111111111111111111111111111111111111110010100 in binary and whose exponent is 63 (decimal). This number is none other than 9223372036854665216 (call it U).

If we decrease the mantissa one notch to 1.1...0011, we get 9223372036854664192 (call it L).

The original number is between L and U and is much closer to U than it is to L

Finally, if you think that this truncation of the mantissa ought to result in a number that ends in a bunch of zeros, you're right. Only it happens in binary, not in decimal: U in base-16 is 0x7ffffffffffe5000 and L is 0x7ffffffffffe4c00.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • From your explanation, when we cast it to long we should get `9223372036854665000` and not `9223372036854665216` right? – Pacerier Oct 18 '11 at 17:29
  • 1
    @Pacerier: I don't see how what you're saying follows from what I've said. I've expanded the answer anyhow. – NPE Oct 18 '11 at 17:39
16

Because doubles don't have that much precision. Why are you doing such a strange thing? Change the d to l.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • But this doesn't explain why I'm getting `9223372036854665216` instead of `9223372036854665000` after converting it to long.. – Pacerier Oct 18 '11 at 17:30
  • 3
    @Pacerier 'Doubles don't have that much precision' explains it completely actually. A double has 53 bits of precision, which is 15.9 decimal digits, which is less than your number. – user207421 Oct 18 '11 at 18:02
6

Doubles have 52-53 bit precision, whereas a long has 64 bit precision (for integers only). The loss of precision in a double is used to represent the exponent, which allows a double to represent larger/smaller numbers than a long can.

Your number is 19 digits long, whereas a double can only store roughly 16 digits of (decimal) integer data. Thus the final number ends up being rounded.

Reference: Double - Wikipedia

ty1824
  • 1,210
  • 10
  • 11
5

Because doubles have limited precision. Your constant has more significant digits than a double can keep track of, so it loses them.

Kevin
  • 53,822
  • 15
  • 101
  • 132
3

You are assuming that limited precision means that it is represented in decimal so is limited to 15 or 16 digits. Actually it is represented in binary and limited to 53 bits of precision. double takes the closest representable value.

double d = 9223372036854665200d;
System.out.println(d +" is actually\n" + new BigDecimal(d)+" so when cast to (long) is\n"+(long) d);

prints

9.2233720368546652E18 is actually 
9223372036854665216 so when cast to (long) is 
9223372036854665216
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130