【发布时间】:2017-09-18 10:02:09
【问题描述】:
我想知道,为什么我简单地添加一些双精度值会在 Java 中导致以下结果:
double a = 1 + 1E-10; // 1.0000000001 (as expected)
double b = 1 + 1E-15; // 1.000000000000001 (as expected)
double c = 1 + 1E-20; // 1.0 (why?)
我认为我至少可以添加一个 Double.MIN_VALUE 的值,它似乎是 4.9E-324。
我在这里做错了什么?
【问题讨论】:
-
“我在这里做错了什么?” - 你忘记了任何浮点数表示的精度问题。
-
技术性更强一点:在IEEE 754 中,一个有 11 位指数和 53 位尾数。指数定义了数字的大小顺序,而尾数定义了数值。例如,在
2.63 x 10^3中,2.63是数值,而3是幅度。如果您添加两个幅度明显不同的值,您可能会遇到问题。精度,这是你观察到的。一般来说,floats 和doubles 工作得很好,当(大多数)组件的数量级大致相同时。 -
谢谢@Turing85,但我还是不明白,为什么我可以用
Double.MIN_VALUE描述一个很小的值,却不能按预期使用。 :P 仅仅是因为另一个值(在这种情况下为 1)的大小有很大不同吗? -
@Thomas 是的。
Double.MIN_VALUE是2^-1074,而1是2^0。 -
@Thomas 如果您知道如何将基数为 10 的表示形式转换为二进制,那么请尝试将
0.3写入二进制。你会注意到这个表示有一个句点(就像以 10 为底的 1/3),因此你会有一个精度错误。二进制中的0.1也是如此。在计算0.3 + 0.1时,舍入误差会被抵消,您会得到预期的结果。在计算0.3 - 0.1时,错误不会被抵消,您会得到意想不到的结果。然而,这个结果在给定的算术中是正确的。