添加非常小的双值(Java)

添加非常小的双值(Java),java,double,min,addition,Java,Double,Min,Addition,我想知道,为什么我简单地添加一些双值会导致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_值,看起来是4.9E-324 我做错了什么 你在这里没有做错什么。小数精度的概念就在眼前。浮点数

我想知道,为什么我简单地添加一些双值会导致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_值,看起来是4.9E-324


我做错了什么

你在这里没有做错什么。小数精度的概念就在眼前。浮点数总是有可能出错。 常见错误值表示为:

- 1/2E-n <= error <=  1/2E-n

-1/2E-n您在这里没有做错任何事。小数精度的概念就在眼前。浮点数总是有可能出错。
常见错误值表示为:

- 1/2E-n <= error <=  1/2E-n

-1/2E-n正如@Turing85所指出的那样,
double
有11位指数和53位尾数

我们在这里计算的是1.0+1E-20。为了表示这个数字(比1.0更精确),我们至少需要21位精度的十进制数字或71位。这比尾数中的双精度更精确

因此,距离1.0+1E-20最近的可表示的
double
数字是。。。。1.0. 这就是你得到的结果


欢迎来到浮点运算的神秘世界。

正如@Turing85所指出的,
double
有11位指数和53位尾数

我们在这里计算的是1.0+1E-20。为了表示这个数字(比1.0更精确),我们至少需要21位精度的十进制数字或71位。这比尾数中的双精度更精确

因此,距离1.0+1E-20最近的可表示的
double
数字是。。。。1.0. 这就是你得到的结果


欢迎来到浮点运算的神秘世界。

“我在这里做错了什么?”-你忘记了任何浮点数表示法都存在的精度问题。更专业一点的是:一个有11位指数和53位尾数。指数定义数字的大小顺序,尾数定义数值。例如,在
2.63 x 10^3
中,
2.63
是数值,而
3
是幅值。如果添加两个显著不同大小的值,则可能会遇到wrt问题。精确,这就是你观察到的。一般来说,
float
s和
double
s在(大多数)分量的大小顺序大致相同的情况下工作得很好。感谢@Turing85,但我仍然不明白,为什么我可以用
double.MIN\u value
来描述一个非常小的值,但不能按预期使用它:P只是因为另一个值(本例中为1)的大小有很大不同吗?@Thomas Yes
Double.MIN_值
2^-1074
,而
1
2^0
@Thomas如果您知道如何将以10为基数的表示形式转换为二进制,请尝试用二进制编写
0.3
。您会注意到,此表示法有一个句点(就像以10为基数的1/3),因此会出现精度错误。二进制的
0.1
也是如此。当计算
0.3+0.1
时,舍入误差将被抵消,从而得到预期结果。当计算
0.3-0.1
时,错误不会被抵消,您会得到意外的结果。然而,这个结果在给定的算术中是正确的。“我在这里做错了什么?”-你忘记了任何浮点数表示都有精度问题。更专业一点的是:一个有11位指数和53位尾数。指数定义数字的大小顺序,尾数定义数值。例如,在
2.63 x 10^3
中,
2.63
是数值,而
3
是幅值。如果添加两个显著不同大小的值,则可能会遇到wrt问题。精确,这就是你观察到的。一般来说,
float
s和
double
s在(大多数)分量的大小顺序大致相同的情况下工作得很好。感谢@Turing85,但我仍然不明白,为什么我可以用
double.MIN\u value
来描述一个非常小的值,但不能按预期使用它:P只是因为另一个值(本例中为1)的大小有很大不同吗?@Thomas Yes
Double.MIN_值
2^-1074
,而
1
2^0
@Thomas如果您知道如何将以10为基数的表示形式转换为二进制,请尝试用二进制编写
0.3
。您会注意到,此表示法有一个句点(就像以10为基数的1/3),因此会出现精度错误。二进制的
0.1
也是如此。当计算
0.3+0.1
时,舍入误差将被抵消,从而得到预期结果。当计算
0.3-0.1
时,错误不会被抵消,您会得到意外的结果。然而,这个结果在给定的算法中是正确的。