我在Java的双变量中看到了一个非常奇怪的行为,因为我试图简单地将小分数添加到双精度中,我看到一个完全奇怪的结果。
double test = 0;
test += 0.71;
test += 0.2;
现在我希望结果是:
test = 0.91
右?错!
实际上,这是我在测试中获得的数字:
test = 0.9099999999999999
现在虽然非常接近,但这是一个非常奇怪的分数损失,从长远来看,它会导致我的程序出现严重错误。
随着浮动,我甚至得到了更奇怪的结果。
非常感谢任何帮助。
由于
答案 0 :(得分:4)
根本没什么奇怪的。 0.91,0.71和0.2不能表示为IEEE754浮点值,因为它们在以二进制表示时将具有重复的小数部分。这种情况完全类似于试图用有限数字的数字表示基数10的1/3。你不能这样做。
您所看到的是进行浮点计算时正常的舍入误差。你必须围绕它编码。因此,例如,您无法可靠地比较相等性,您必须看到这两个数字在彼此的某个小的delta内。有关更深入但仍可理解的解释,请参阅The Floating Point Guide。
答案 1 :(得分: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
基本规则:
答案 2 :(得分: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
答案 3 :(得分:0)
Java使用称为浮点的东西来表示小数。它们使用指数表示法。这就是我的意思:
有乘数(M),指数介于1023和-1022(E)之间。
数字(N)表示如下:M * 2^E
。
4.25表示如下:
17 * 2 ^ -2。
0.91不能完全用基数2表示,但Java可以非常接近:
0.909999999999 ..
因此,无法准确地将这些数字加在一起。