关于数学:为什么浮点数似乎在Java中添加不正确?

Why do floats seem to add incorrectly in Java?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicates:
Is JavaScript's Math broken?
Java floating point arithmetic

我有当前代码

1
2
3
for(double j = .01; j <= .17; j+=.01){
            System.out.println(j);
        }

输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0.01
0.02
0.03
0.04
0.05
0.060000000000000005
0.07
0.08
0.09
0.09999999999999999
0.10999999999999999
0.11999999999999998
0.12999999999999998
0.13999999999999999
0.15
0.16
0.17

有人能解释为什么会这样吗?你怎么解决这个问题?除了写舍入函数?


浮点是Java中的实际数的近似值,这是因为它们存储的方式。如果需要精确的值,请使用bigdecimal。


它们工作正常。有些十进制值不能精确地用二进制浮点表示,并四舍五入到最接近的值。有关详细信息,请参阅我对此问题的回答。这个问题被问及Perl,但是答案同样适用于Java,因为它是对所有的浮点表示都没有无限精度的限制(即所有的浮点表示)。


正如@kaleb brasee所建议的,当精度是必须的时候,可以使用bigdecimal。这里有一个链接,可以很好地解释有关在爪哇使用HTTP://FirStReaveSt.T.S.CO.UK/Java/TrAPS/JavaaDouLyTrAP.HTML的浮点操作的细微细节的链接。

还有一个与使用bigdecimal有关的问题的链接。强烈建议同时阅读这两个问题。它真的帮助了我。享受吧,博罗。


正如其他人所指出的,只有两个幂的组合数字才可以(双精度)浮点格式精确表示。

如果需要以任意精度存储任意数字,请使用bigdecimal。

如果问题只是一个显示问题,那么您可以通过显示数字的方式来解决这个问题。例如:

String.format("%.2f", n)

将数字格式化为2个小数位。


当我们"用手"处理浮点数时(即字面上写在纸上或输入计算机时),我们人类习惯于用"基数10"来思考。正因为如此,我们才有可能写下17%的精确表示。我们只写0.17(或1.7e-1等)。试图表示第三个这样一个微不足道的事情,不能完全用这个系统完成,因为我们必须写0.3333333…有无限多的3秒,这是不可能的。

处理浮点的计算机不仅有有限的位来表示数字的尾数(或有效位),而且还限制在2的基础上表示尾数。这意味着大多数百分比(我们人类使用的基10浮点约定总是可以精确地写入,例如"0.17")对于计算机来说是不可能精确存储的。在计算机中,0%、25%、50%、75%和100%这样的分数可以精确地表示为浮点数,因为它由两个部分(2e-1)或四分之一(2e-4)组成,这与数字表示法非常吻合。百分比值,比如17%甚至是微不足道的(对我们人类而言!!)就像10%或1%一样,计算机完全不可能存储这些数字,因为对于二进制浮点系统来说,这些数字是人类(以10为基数)浮点系统的"三分之一"。

但是,如果仔细选择浮点值,则它们总是由1/2^n的整数组成,其中n可能是10(表示1/1024的整数),则它们始终可以准确存储,而不会出错,作为浮点值。所以,如果你试图将17/1024存储在一台计算机中,它会顺利进行。实际上,即使使用"人的基数10"的十进制系统,也可以毫无错误地存储它(但是,如果按照必须处理的实际数字的数目来计算的话,您可能会疯掉)。

这就是为什么有些游戏在一个360度旋转的单位中表示角度,而这个单位是256个角度单位。可以用0到1之间的浮点数表示而不损失(其中1表示旋转一整圈)。


这是因为IEEE754的限制,二进制格式可以最大限度地利用32位。


这是因为在数学意义上,浮点值本质上与实数不同。

在计算机中,只有固定数量的位可以用来表示值。这意味着它可以保存有限数量的值。但是实数是无限的,因此并非所有的实数都能精确地表示出来。但通常情况下,这个值很接近。你可以在这里找到更详细的解释。


在计算机上用双重表示是正常的。你会失去一些东西,然后你会得到这样的结果。更好的解决方案是这样做:

1
2
3
for(int j = 1; j <= 17; j++){
    System.out.println(j/100.0);
}