请考虑以下代码:
let dl = 9.5 / 11.
let min = 21.5 + dl
let max = 40.5 - dl
let a = [ for z in min .. dl .. max -> z ] // should have 21 elements
let b = a.Length
“a”应该有21个元素,但只有20个元素。缺少“max-dl”值。我知道浮点数不准确,但我希望F#可以解决这个问题。如果没有那么为什么F#支持使用float迭代器的List comprehension?对我来说,这是一个错误的来源。
答案 0 :(得分:2)
转换为小数并查看数字,似乎第21项将“超调”最大值:
let dl = 9.5m / 11.m
let min = 21.5m + dl
let max = 40.5m - dl
let a = [ for z in min .. dl .. max -> z ] // should have 21 elements
let b = a.Length
let lastelement = List.nth a 19
let onemore = lastelement + dl
let overshoot = onemore - max
这可能是由于let dl = 9.5m / 11.m
?
要摆脱这种复合错误,你必须使用另一个数字系统,即Rational。 F#Powerpack附带了一个BigRational类,可以这样使用:
let dl = 95N / 110N
let min = 215N / 10N + dl
let max = 405N / 10N - dl
let a = [ for z in min .. dl .. max -> z ] // Has 21 elements
let b = a.Length
答案 1 :(得分:1)
正确处理浮动精度问题可能会非常棘手。你不应该依赖浮点数相等(这就是列表理解对最后一个元素的暗示)。生成无限流时,浮点列表推导非常有用。在其他情况下,您应该注意最后的比较。
如果你想要固定数量的元素,并包括下端点和上端点,我建议你写这种函数:
let range from to_ count =
assert (count > 1)
let count = count - 1
[ for i = 0 to count do yield from + float i * (to_ - from) / float count]
range 21.5 40.5 21
当我知道应该包括最后一个元素时,我有时会这样做:
let a = [ for z in min .. dl .. max + dl*0.5 -> z ]
答案 2 :(得分:0)
我怀疑问题在于浮点值的精度。 F#每次都将dl添加到当前值并检查当前是否
答案 3 :(得分:0)
运行代码后,执行以下操作:
> compare a.[19] max;;
val it : int = -1
这意味着max大于a。[19]
如果我们以与范围运算符相同的方式进行计算,但是以两种不同的方式进行分组,然后进行比较:
> compare (21.5+dl+dl+dl+dl+dl+dl+dl+dl) ((21.5+dl)+(dl+dl+dl+dl+dl+dl+dl));;
val it : int = 0
> compare (21.5+dl+dl+dl+dl+dl+dl+dl+dl+dl) ((21.5+dl)+(dl+dl+dl+dl+dl+dl+dl+dl));;
val it : int = -1
在此示例中,您可以看到如何在不同的顺序中将相同值的7倍添加到完全相同的值,但如果我们尝试8次,则结果会根据分组而变化。
你这样做了20次。
因此,如果您将范围运算符与浮点数一起使用,则应注意精度问题。 但这同样适用于浮点数的任何其他计算。