Scala Range.Double缺少最后一个元素

时间:2016-05-25 15:23:08

标签: scala floating-point double range

我正在尝试在[numBinslower范围内创建一个均匀分布的upper个数字列表。当然,存在浮点问题,这种方法并不是最好的。然而,使用Range.Double的结果让我感到惊讶,因为缺少的元素根本不接近上限。

设定:

val lower = -1d
val upper = 1d
val numBins = 11
val step = (upper-lower)/numBins   // step = 0.18181818181818182

问题:

scala>   Range.Double(lower, upper, step)
res0: scala.collection.immutable.NumericRange[Double] = NumericRange(-1.0, -0.8181818181818182, -0.6363636363636364, -0.45454545454545453, -0.2727272727272727, -0.0909090909090909, 0.09090909090909093, 0.27272727272727276, 0.4545454545454546, 0.6363636363636364)

问题:列表似乎是一个简短的元素。 0.8181818181818183更进一步,并且小于1.

解决方法:

Scala>   for (bin <- 0 until numBins) yield lower + bin * step
res1: scala.collection.immutable.IndexedSeq[Double] = Vector(-1.0, -0.8181818181818181, -0.6363636363636364, -0.4545454545454546, -0.2727272727272727, -0.09090909090909083, 0.09090909090909083, 0.2727272727272727, 0.4545454545454546, 0.6363636363636365, 0.8181818181818183)

此结果现在包含预期的元素数,包括0.818181 ..

1 个答案:

答案 0 :(得分:1)

我认为问题的根本原因是toString NumericRange的实施中的一些功能

217  override def toString() = { 
218     val endStr = if (length > Range.MAX_PRINT) ", ... )" else ")" 
219     take(Range.MAX_PRINT).mkString("NumericRange(", ", ", endStr) 
220   } 

UPD:不是toString。其他一些方法(如mapforeach)会从返回的集合中剪切最后一个元素。

无论如何,通过查看您已收集的size收藏集 - 您会发现 - 所有元素都在那里。

您在解决方法示例中所做的工作 - 使用了不同的基础数据类型。