-4

为什么Scala中乘法0.3和3的结果是0.89999999999999?

4

5 回答 5

7

浮点计算是相当复杂的主题。

这与浮点数的二进制表示有关,它不能保证每个可能的数字(显然)都有精确的表示,这可能导致操作错误,是的,这些错误可以传播。

这是有关该主题的链接,虽然它不是最简单的东西,但如果您想了解该主题,它可以为您提供一个很好的视角。

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

底线问题是,对于给定的浮点数,一个有理数,该数字的二进制表示可能需要比给定语言中可用的精度更高的精度。

例如,如果您使用 24 位来存储双精度数,但浮点值的二进制表示需要 25 位才能准确表示,则会出现舍入误差。

编辑:

正如 Péter Török 在评论中指出的那样,大多数已知的编程语言对常见的数据类型使用相同的表示,float-> 32 位,double-> 64 位,因此无论语言如何,通常都可以考虑数据类型来计算精度。

于 2013-02-07T11:13:41.683 回答
6

不仅在 Scala 中如此,在任何使用 IEEE 浮点数标准的语言/平台中都是如此。

红宝石中的示例:

0.1.9.2p320 :001 > 0.3 * 3
 => 0.8999999999999999

或 Python:

>>> 0.3 * 3
0.8999999999999999
于 2013-02-07T11:11:55.070 回答
3

这几乎与 Scala 无关!

原因与计算机如何表示浮点数有关。计算机使用二进制表示,而不是十进制表示,因此诸如 0.3 之类的数字不能精确表示,而是使用可以简洁地以 2 为基数表示的近似值。结果是对这些数字执行的操作可能会稍微超出您期望的答案。有关更多详细信息,请参阅浮点数

如有必要,您可以通过实现类之Fraction类的东西来解决这个问题,该类使用自己的算法来精确地执行这些计算。

于 2013-02-07T11:16:02.560 回答
2

如果需要精确值,请使用 BigDecimal。

BigDecimal(3)*0.3会给你0.9

于 2013-02-07T13:42:27.923 回答
0

这是常用浮点值表示的副作用。

我经常遇到这个问题并制作一个简单的函数,将数字“四舍五入”到最接近的大于期望精度的值。它在 C 中为:

int64_t __pow10_arr[18] = { 1l, 10l, 100l, 1000l, 10000l, 100000l,
                            1000000l, 10000000, 100000000l, 1000000000l, 10000000000l, 100000000000l,
                            1000000000000l, 10000000000000l, 100000000000000l, 1000000000000000l, 10000000000000000l, 100000000000000000l };

double roundToNfractions ( double val, uint8_t n )
{
  val *= __pow10_arr[n];
  val += 0.5;
  val = (uint64_t) val;
  val /= __pow10_arr[n];
  return val;
}

效率不是很高,但可以解决问题,因为您可以安全地编写 printf("%.2d", val);,并且您总是会得到类似的结果,3.00而不是2.99;

于 2013-02-07T11:17:30.137 回答