double 的十进制显示精度损失
Loss of precision in decimal display of double
为什么后面的数值显示有出入?
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
如您所见,toString()
和 %f
转换都丢失了最后一位的精度。但是,我们可以看到最后一位数字实际上是精确的,因为 BigDecimal
转换保留了它。
感谢@user16320675 的评论,我正在回答我自己的问题。原因是数字 988530483551494912L
的精度超出了 double
类型精度的限制,并且 Double.toString()
(以及类似的 %f
)将根据文档仅使用将 double
数字与相邻数字区分开来所需的最小有效数字位数。相邻数字是指与原始数字的两边具有最小可表示差异的数字。
这可以使用 Math.nextAfter
显示相邻数字来演示:
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
因此,正如我们所见,添加更多有效数字没有意义,因为此字符串表示形式已经有足够的数字来区分数字与相邻值。
但是,还有一个问题:它显示了17位有效数字,但16位就足够了。我不确定为什么它会发出额外的最后一位数字。
为什么后面的数值显示有出入?
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
如您所见,toString()
和 %f
转换都丢失了最后一位的精度。但是,我们可以看到最后一位数字实际上是精确的,因为 BigDecimal
转换保留了它。
感谢@user16320675 的评论,我正在回答我自己的问题。原因是数字 988530483551494912L
的精度超出了 double
类型精度的限制,并且 Double.toString()
(以及类似的 %f
)将根据文档仅使用将 double
数字与相邻数字区分开来所需的最小有效数字位数。相邻数字是指与原始数字的两边具有最小可表示差异的数字。
这可以使用 Math.nextAfter
显示相邻数字来演示:
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
因此,正如我们所见,添加更多有效数字没有意义,因为此字符串表示形式已经有足够的数字来区分数字与相邻值。
但是,还有一个问题:它显示了17位有效数字,但16位就足够了。我不确定为什么它会发出额外的最后一位数字。