使用F#中的float迭代器列出理解

时间:2011-03-25 07:05:34

标签: f# floating-point list-comprehension

请考虑以下代码:

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?对我来说,这是一个错误的来源。

在线试用:http://tryfs.net/snippets/snippet-3H

4 个答案:

答案 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次。

因此,如果您将范围运算符与浮点数一起使用,则应注意精度问题。 但这同样适用于浮点数的任何其他计算。