-1

我在 Java 的 double 变量中看到了一个非常奇怪的行为,因为我试图简单地将小分数添加到 double 中,我看到了一个完全奇怪的结果。

double test = 0;
test += 0.71;
test += 0.2;

现在我希望结果是:

test = 0.91

对?错误的!

实际上,这是我在测试替身中得到的数字:

test = 0.9099999999999999

现在虽然这非常接近,但这是一个非常奇怪的分数损失,从长远来看,它会在我的程序中导致严重的错误。

有了一个浮点数,我得到了一个更奇怪的结果。

任何帮助将不胜感激。

谢谢

4

4 回答 4

4

一点也不奇怪。0.91、0.71 和 0.2 不能表示为 IEEE754 浮点值,因为它们在以二进制表示时会有一个重复的小数部分。这种情况完全类似于试图用有限位数表示以 10 为底的 1/3。你不能这样做。

您看到的是进行浮点计算时正常的舍入误差。你必须围绕它编写代码。因此,例如,您无法可靠地比较相等性,您必须看到这两个数字彼此之间存在一些小的增量。有关更深入但仍然可以理解的解释,请参阅浮点指南

于 2012-04-25T10:16:20.393 回答
1

这就是浮点值二进制编码的神奇之处(查找 IEEE754:http ://en.wikipedia.org/wiki/IEEE_754-2008 )。如果你想确保永远不会有这种事情,你可能正在寻找 BigDecimal :

http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html

基本规则 :

  • 处理浮点数时不要使用相等测试(你必须测试间隙)
  • 您显示的整数(通常使用 DecimalFormat)
  • 不要在金融应用中使用浮点数
  • 浮点数通常是科学或工业操作的方式,只要您了解 IEEE754
于 2012-04-25T10:11:34.627 回答
1

double只能近似大多数小数值。这意味着如果您想获得预期的结果,您需要使用一些舍入。或者您可以使用 BigDecimal 来为您解决这个问题。

double test = 0;
test += 0.71;
test += 0.2;
System.out.printf("%.2f%n", test);

印刷

0.91

为了自己的利益

System.out.println("0.71 is actually " + new BigDecimal(0.71));
System.out.println("0.2 is actually " + new BigDecimal(0.2));
System.out.println("0.71+0.2 is actually " + new BigDecimal(0.71 + 0.2));
System.out.println("0.91 is actually " + new BigDecimal(0.91));
System.out.println("0.71+0.2 == 0.91 is " + (0.71 + 0.2 == 0.91));

印刷

0.71 is actually 0.70999999999999996447286321199499070644378662109375
0.2 is actually 0.200000000000000011102230246251565404236316680908203125
0.71+0.2 is actually 0.9099999999999999200639422269887290894985198974609375
0.91 is actually 0.91000000000000003108624468950438313186168670654296875
0.71+0.2 == 0.91 is false
于 2012-04-25T10:15:35.607 回答
0

Java 使用一种叫做浮点的东西来表示小数。他们使用指数符号。这就是我的意思:

有一个乘数 (M) 和一个介于 1023 和 -1022 (E) 之间的指数。

数字 (N) 表示如下:M * 2^E.

4.25 表示如下:

17 * 2^-2。

0.91 不能精确地以基数 2 表示,但 Java 可以非常接近:

0.909999999999..

因此,不可能将这些数字准确地加在一起。

于 2016-01-31T18:13:28.603 回答