Scala迭代和范围中的精度错误



我正在尝试构建一个包含范围和步长的Double集合。当我使用Array.iterate方法时,我会得到奇怪的浮点错误,比如:

scala> Array.iterate[Double](0.0, 10)(0.1+)
res0: Array[Double] = Array(0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999)

很奇怪,一个小范围和一个小步骤会导致如此不精确。我知道我还有其他方法可以做到这一点(例如Array.iterate[Int](0, 10)(1+).map(i => i.toDouble / 10.0)),但我对内置的收集方法会表现得如此糟糕感到困惑。这是有原因的吗?还是我是个傻瓜,做得不对?

这是浮点运算基本限制的症状,与集合无关:

scala> 0.2 + 0.1
res0: Double = 0.30000000000000004

有很多帖子解释了为什么会发生这种情况:

  • 每个计算机科学家都应该知道浮点运算
  • 为什么浮点计算如此不准确
  • 为什么浮点数字不准确

尝试使用BigDecimal:

scala> val r = BigDecimal(0) to BigDecimal(1) by BigDecimal(0.1)
scala> println(r)
NumericRange(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0)

最新更新