为什么这个精度失败的例子显示双精度而不是浮点数?

时间:2014-04-10 12:58:48

标签: java floating-point double floating-point-precision

关于为什么浮点不应该用于货币操作的问题有一个很好的讨论,并且Bloch的Effective Java给出了一个可爱的例子here

我正在玩这个并注意到一些奇怪的东西。如果数字是双倍的:

System.out.println(1.03d - .42d); 
//prints out 0.6100000000000001.

但是,如果数字是浮点数:

System.out.println(1.03f - .42f); 
//prints out 0.61.

为什么浮子也不会以同样的方式失败?两种类型都容易出现同样的问题,但是导致行为差异的原因是什么?

1 个答案:

答案 0 :(得分:5)

这里涉及八个有趣的值(每种类型四个)。他们的确切值是:

双倍值

1.03d:  1.0300000000000000266453525910037569701671600341796875
0.42d:  0.419999999999999984456877655247808434069156646728515625
Result: 0.6100000000000000976996261670137755572795867919921875
0.61d:  0.60999999999999998667732370449812151491641998291015625

浮动值

1.03f:  1.0299999713897705078125
0.42f:  0.4199999868869781494140625
Result: 0.61000001430511474609375
0.61f:  0.61000001430511474609375

请注意,最接近的double到1.03是如何更多而不是1.03,而最接近的0.42是而不是0.42 ...所以减法的结果与精确(十进制)减法的差别在于这两个误差的总和。

最接近的float到1.03,最接近的float到0.42都小于原始值,因此错误会在某种程度上相互抵消。这就是double结果“感觉”比float结果更不准确的原因。 float结果恰好接近0.61,因为您可以表示为float,因此字符串表示只是“0.61”。由于 比减法结果更接近double到0.61,因此字符串表示必须区分两者。