k314159
k314159

Reputation: 11062

Loss of precision in decimal display of double

Why is there a discrepancy in the display of the following value?

double x = (double)988530483551494912L;
System.out.printf("%f%n", x);           -> 988530483551494910.000000
System.out.println(Double.toString(x)); -> 9.8853048355149491E17
System.out.println(new BigDecimal(x));  -> 988530483551494912

As you can see, both toString() and the %f conversion lose the precision of the last digit. However, we can see that the last digit is actually precise, because the BigDecimal conversion preserves it.

Upvotes: 3

Views: 332

Answers (1)

k314159
k314159

Reputation: 11062

Thanks to @user16320675's comment, I'm answering my own question. The reason is that the number 988530483551494912L has precision beyond the limit of the double type's precision, and Double.toString() (and similarly %f) will, as per documentation, only use the minimum number of significant digits required to distinguish a double number from adjacent numbers. Adjacent numbers are those that have the smallest representable difference from the original, on either side of it.

This can be demonstrated using Math.nextAfter to show the adjacent numbers:

import static java.lang.Math.nextAfter;
double x = (double)988530483551494912;
System.out.println(nextAfter(x, Double.MIN_VALUE));  ==> 9.8853048355149478E17
System.out.println(x);                               ==> 9.8853048355149491E17
System.out.println(nextAfter(x, Double.MAX_VALUE));  ==> 9.8853048355149504E17

So, as we can see, there is no point in adding any more significant figures because this string representation already has enough digits to distinguish the number from adjacent values.

However, a question still remains: it shows 17 significant figures, but 16 would be sufficient. I'm not sure why it issues an extra final digit.

Upvotes: 1

Related Questions