繁体   English   中英

奇怪的Java分数行为

[英]Weird Java fraction behavior

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

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

现在,我希望结果是:

test = 0.91

对? 错误!

实际上,这是我在测试中获得的双倍数字:

test = 0.9099999999999999

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

有了浮动,我什至得到了一个奇怪的结果。

任何帮助将不胜感激。

谢谢

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

您看到的是在进行浮点计算时的正常舍入误差。 您必须围绕它进行编码。 因此,例如,您不能可靠地比较相等性,您必须看到两个数字彼此之间的距离很小。 有关更深入但仍可以理解的解释,请参见《浮点指南》

这就是对浮点值进行二进制编码的魔力(请查看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,浮动通常是进行科学或工业操作的方式

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

Java使用称为浮点的东西来表示小数。 他们使用指数表示法。 这就是我的意思:

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

数字(N)表示为: M * 2^E

4.25表示如下:

17 * 2 ^ -2。

0.91不能精确地表示为基数2,但是Java可以很接近:

0.909999999999 ..

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM