我使用scala Range.by来分割一个范围以获得一个数组,但它错过了一些特殊存储桶数的最后一个,例如100.我很困惑,并演示如下:
object SplitDemo extends App {
val min = 0.0
val max = 7672.142857142857
val bucketNum = 100
def splitsBucket1(min: Double, max: Double, num: Int) = (min to max by ((max - min) / num)).toArray
def splitsBucket2(min: Double, max: Double, num: Int): Array[Double] = {
val rst = Array.fill[Double](num + 1)(0)
rst(0) = min
rst(num) = max
val step = (max-min)/num
for(i <- 1 until num) rst(i) = rst(i-1)+step
rst
}
val split1 = splitsBucket1(min, max, bucketNum)
println(s"Split1 size = ${split1.size}, %s".format(split1.takeRight(4).mkString(",")))
val split2 = splitsBucket2(min, max, bucketNum)
println(s"Split2 size = ${split2.size}, %s".format(split2.takeRight(4).mkString(",")))
}
输出正在跟随
Split1尺寸= 100,7365.257142857143,7441.978571428572,7518.700000000001,7595.421428571429
拆分2尺寸= 101,7441.978571428588,7518.700000000017,7595.421428571446,7672.142857142857
当num = 100时,split1 错过了最后一个,但是split2没有(这是我的期望)。当num是其他num时,e.t。 130,split1和split2得到样本结果 是什么原因可以说明差异?
答案 0 :(得分:2)
看一下,max
在分割并乘以它后如何以不同方式出现:
scala> 7672.142857142857 / 100 * 100
res1: Double = 7672.142857142858
此数字大于max
,因此不适合该范围:
scala> max / bucketNum * bucketNum > max
res2: Boolean = true
它比在step
中添加splitsBucket2
100次更正确:
scala> var result = 0.0
result: Double = 0.0
scala> for (_ <- 0 until 100) result += (max - min) / bucketNum
scala> result
res4: Double = 7672.142857142875
这比max
和max / bucketNum * bucketNum
都要大。您可以通过明确指定splitBuckets2
来在rst(num) = max
中避免这种情况。
您可以尝试以下拆分实现:
def splitsBucket3(min: Double, max: Double, num: Int): Array[Double] = {
val step = (max - min) / num
Array.tabulate(num + 1)(min + step * _)
}
保证具有正确数量的元素,并且具有比splitsBucket2
更少的数值精度问题。