如何解决列表中的浮点数错误[haskell]

时间:2012-04-26 06:43:46

标签: list haskell floating-point

  

可能重复:
  Haskell ranges and floats

例如,当我输入

[0.1, 0.3 ..1]

我明白了:

[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]

我期待:

[0.1,0.3,0.5,0.7,0.9]

3 个答案:

答案 0 :(得分:3)

尝试

map (/10) [1, 3 .. 10]

代替。


问题是浮点数使用二进制分数,而二进制分数不能精确地表示小数分数。因此,您会收到错误并且错误会累积起来。

二进制分数不能完全代表1/5,就像小数部分不能完全代表1/3一样---我们能做的最好就是0.33333 ....

[0.1, 0.3 .. 1]

的简写
[0.1,
 0.1 + 0.2,
 0.1 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2 + 0.2,
 0.1 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2]

另一个问题是当下一个元素超过一半时,列表将在等于或超过限制 的第一个元素后停止超过限制的步骤,这就是您拥有1.0999999999999999元素的原因。

答案 1 :(得分:1)

这是如何在计算机中表示浮点数的问题。具有浮点数的简单算术通常不会按预期运行。重复算术会累积“舍入误差”,这意味着当您重复添加数字时,结果会逐渐变差(例如)。

在某些情况下,您可以使用不同的数字表示来避免这些问题。例如,如果您只关心有理数,则可以使用Rational类型。所以你可以这样做:

[0.1,0.3..1] :: [Rational]

导致:

[1 % 10,3 % 10,1 % 2,7 % 10,9 % 10,11 % 10]

这是正确的答案,没有舍入错误;每个数字只表示为两个Integer的比率。根据您的具体情况,这可能是比使用浮点数更好的选择。

这仍然超过了上限,但是比从浮点数得到的舍入误差更容易处理。

请注意,对于性能关键的浮点数可能会更快。

答案 2 :(得分:1)

表达式[e1, e2 .. e3]被评估为enumFromThenTo e1 e2 e3,浮点数表示(来自The Haskell 98 Report):

  

对于Float和Double,enumFrom系列的语义由上面的Int规则给出,除了当元素变为大于e3+i/2的正增量i时,或者当它们变得小于i时,列表终止对于否定的我是e3+i/2

这意味着对于浮点数,[e1, e2 .. e3]的最后一个元素通常大于e3,最多可以e3+(e2-e1)/2 - ε