37

因此,当我在 Java 中使用 Doubles 进行加法或减法时,它会给我带来奇怪的结果。这里有一些:

如果我添加0.0 + 5.1,它会给我5.1。这是正确的。

如果我添加5.1 + 0.1,它会给我5.199999999999(重复9s 的数量可能会关闭)。那是错误的。

如果我减去4.8 - 0.4,它会给我4.39999999999995(同样,重复9的 s 可能会关闭)。那是错误的。

起初我以为这只是用十进制值添加双精度的问题,但我错了。以下工作正常:

5.1 + 0.2 = 5.3
5.1 - 0.3 = 4.8

现在,添加的第一个数字是保存为变量的双精度数,尽管第二个变量从JTextField. 例如:

//doubleNum = 5.1 RIGHT HERE
//The textfield has only a "0.1" in it.
doubleNum += Double.parseDouble(textField.getText());
//doubleNum = 5.199999999999999
4

2 回答 2

36

在 Java 中,double值是IEEE 浮点数。除非它们是 2 的幂(或 2 的幂之和,例如 1/8 + 1/4 = 3/8),否则即使它们具有很高的精度,也无法精确表示。一些浮点运算会加重这些浮点数中存在的舍入误差。在您上面描述的情况下,浮点错误已经变得足够显着以显示在输出中。

数字的来源是什么并不重要,无论是从 a 解析字符串JTextField还是指定double文字 - 问题在于浮点表示中的继承。

解决方法:

  • 如果你知道你只有这么多小数点,那么使用整数算术,然后转换为小数:

    (double) (51 + 1) / 10
    (double) (48 - 4) / 10
    
  • 使用BigDecimal

  • 如果您必须使用,您可以使用Kahan Summation Algorithmdouble减少浮点错误。

于 2013-03-25T21:57:51.040 回答
2

在 Java 中,双精度数使用 IEEE 754 浮点算法(请参阅Wikipedia 文章),这本质上是不准确的。使用BigDecimal获得完美的小数精度。为了在印刷中四舍五入,仅接受“相当不错”的准确性,使用printf("%.3f", x).

于 2013-03-25T21:59:43.803 回答