9

我注意到 Java 浮点精度的一些问题

       Float.parseFloat("0.0065") - 0.001  // 0.0055000000134110451
       new Float("0.027") - 0.001          // 0.02600000000700354575
       Float.valueOf("0.074") - 0.001      // 0.07399999999999999999

我不仅有问题,Float还有Double.

有人可以解释幕后发生的事情,我们如何才能获得准确的数字?在处理这些问题时,处理这个问题的正确方法是什么?

4

7 回答 7

30

问题很简单,float精度有限。它不能完全代表0.0065。(当然,同样如此double:它具有更高的精度,但仍然是有限的。)

使上述问题更加明显的另一个问题是,它0.001是 adouble而不是 a float,因此您float将被提升为 adouble来执行减法,当然此时系统无法恢复 a 丢失的精度double 本来可以代表开始。为了解决这个问题,你会写:

float f = Float.parseFloat("0.0065") - 0.001f;

使用0.001f而不是0.001.

于 2012-10-05T18:33:40.117 回答
6

看看每个计算机科学家应该知道的关于浮点运算的知识。你的结果在我看来是正确的。

如果您不喜欢浮点数的工作方式,请尝试使用BigDecimal之类的方法。

于 2012-10-05T18:32:38.670 回答
5

你得到了正确的结果。没有float确切的 0.027 这样的,也不存在这样的double. 如果您使用or ,您将始终收到这些错误。floatdouble

floatdouble存储为二进制分数:类似于 1/2 + 1/4 + 1/16... 您无法将所有十进制值完全存储为有限精度二进制分数。这在数学上是不可能的。

唯一的选择是使用BigDecimal,您可以使用它来获取精确的十进制值。

于 2012-10-05T18:32:32.440 回答
4

原始数据类型的 Java 教程页面

如果浮点字面量以字母For结尾,则它的类型为浮点型f;否则它的类型是 double 并且可以选择以字母D或. 结尾d

所以我认为你的文字(0.001)是双打的,你从浮点数中减去双打。

试试这个:

System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055

...你会得到:

0.005500000134110451
0.0055

所以F给你的文字添加后缀,你应该会得到更好的结果:

Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F
于 2012-10-05T18:47:57.230 回答
3

我会将您的浮点数转换为字符串,然后使用 BigDecimal。

这个链接解释得很好

new BigDecimal(String.valueOf(yourDoubleValue));

不要使用 BigDecimal 双构造函数,因为你仍然会得到错误

于 2012-10-05T18:54:02.860 回答
1

长话短说,如果您需要任意精度,请使用 BigDecimal 而不是 float 或 double。您将看到各种使用浮点数的这种性质的舍入问题。

顺便说一句,不要使用 BigDecimal 的 float/double 构造函数,因为它会有同样的问题。请改用 String 构造函数。

于 2012-10-05T18:32:50.290 回答
1

浮点数不能准确表示十进制数。如果您需要在 Java 中准确表示数字,则应使用 java.math.BigDecimal 类:

BigDecimal d = new BigDecimal("0.0065");
于 2012-10-05T18:33:52.147 回答