List 如何解决列表中的浮点数出错[haskell]
可能重复:List 如何解决列表中的浮点数出错[haskell],list,haskell,floating-point,List,Haskell,Floating Point,可能重复: 例如,当我输入 [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] 试一试 相反 问题是浮点数使用二进制分数,而二进制分数不能精确表示十进制分数。因此,您会得到错误,并且错误会不断累积 二进制分数不能精确地表示1/5,就像十进制分数不能精确地表示1/3一样——我们能做的最好的是0.33333 [0.1,0.3..1]是
例如,当我输入
[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]
试一试
相反
问题是浮点数使用二进制分数,而二进制分数不能精确表示十进制分数。因此,您会得到错误,并且错误会不断累积 二进制分数不能精确地表示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.099999999999999
元素。试试看
相反
问题是浮点数使用二进制分数,而二进制分数不能精确表示十进制分数。因此,您会得到错误,并且错误会不断累积 二进制分数不能精确地表示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.099999999999999
元素。这是计算机中浮点数的表示方式问题。带有浮点数的简单算术运算通常不符合预期。重复的算术运算会累积“舍入误差”,这意味着当你重复添加数字时,结果会越来越差(例如)
在某些情况下,可以通过使用不同的数值表示来避免这些问题。例如,如果您只关心有理数,那么可以使用rational
类型。所以你可以做:
[0.1,0.3..1] :: [Rational]
其结果是:
[1 % 10,3 % 10,1 % 2,7 % 10,9 % 10,11 % 10]
这是正确答案,没有舍入误差;每个数字仅表示为两个Integer
s的比率。根据您的具体情况,这可能是比使用浮点数更好的选择
这仍然超出了上限,但这比从浮点数得到的舍入误差更容易处理
请注意,对于某些性能关键型浮点数可能会更快。这是一个浮点数在计算机中如何表示的问题。带有浮点数的简单算术运算通常不符合预期。重复的算术运算会累积“舍入误差”,这意味着当你重复添加数字时,结果会越来越差(例如) 在某些情况下,可以通过使用不同的数值表示来避免这些问题。例如,如果您只关心有理数,那么可以使用
rational
类型。所以你可以做:
[0.1,0.3..1] :: [Rational]
其结果是:
[1 % 10,3 % 10,1 % 2,7 % 10,9 % 10,11 % 10]
这是正确答案,没有舍入误差;每个数字仅表示为两个Integer
s的比率。根据您的具体情况,这可能是比使用浮点数更好的选择
这仍然超出了上限,但这比从浮点数得到的舍入误差更容易处理
请注意,对于某些性能关键的浮点数可能会更快。表达式
[e1,e2..e3]
的计算结果为enumfromthen到e1 e2 e3
,这对于浮点数意味着(从):
对于Float和Double,上面Int的规则给出了enumFrom族的语义,但当元素大于正增量i的e3+i/2
或小于负增量i的e3+i/2
时,列表终止
这意味着,对于浮点数,
[e1,e2..e3]
的最后一个元素通常大于e3
,并且可以高达e3+(e2-e1)/2-ε
表达式[e1,e2..e3]
的计算结果为enumFromThenTo e1 e2 e3
,这对于浮点数意味着(from):
对于Float和Double,上面Int的规则给出了enumFrom族的语义,但当元素大于正增量i的e3+i/2
或小于负增量i的e3+i/2
时,列表终止
这意味着,对于浮点数,[e1,e2..e3]
的最后一个元素通常大于e3
,并且可以达到e3+(e2-e1)/2-ε
读,我可以理解0.89999,因为浮点数不能精确表示。但是为什么生成的列表的值1.099999超过了值1。但是[1,3..10]会导致[1,3,5,7,9]。没有值11,这是第一个超过限制的元素。@RolandXuDouble
的真正规则是它将一直持续到数字超过结束条件的一半。比较一下[1,4..6]:[Int]
,[1,4..6]:[Double]
,和[1.6,4.6..6]::[Double]
。这是Haskell规范中的一个bug,由一些好心的人引入。让最后一个元素超过上限是完全错误的,IMO.map((/10).fromInteger)[1,3..10]
会更健壮。我可以理解0.89999,因为浮点不能精确表示。但是为什么生成的列表的值1.099999超过了值1。但是[1,3..10]会导致[1,3,5,7,9]。没有值11,这是第一个超过限制的元素。@RolandXuDouble
的真正规则是它将一直持续到数字超过结束条件的一半。比较[1,4..6]