例如,当我输入
时[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]
答案 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 - ε
。