ziv*_*rah 7 floating-point haskell range
我知道漂浮物由于其不精确的性质而导致范围内的奇怪行为.我预计价值不精确的可能性.例如:
[0.1,0.3..1]可能[0.1,0.3,0.5,0.7,0.8999999999999999]代替[0.1,0.3,0.5,0.7,0.9]
然而,除了精度损失之外,我还得到一个额外的元素:
ghci> [0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
Run Code Online (Sandbox Code Playgroud)
这很奇怪,但在这里解释.我想这样可以解决这个问题,我想:
ghci> [0.1,0.3..0.99]
[0.1,0.3,0.5,0.7,0.8999999999999999]
Run Code Online (Sandbox Code Playgroud)
但这有点糟糕.也许有一种更清洁的方式.对于这个简单的例子,当然,我可以使用范围[0.1,0.3..0.9],一切都很好.
但是在一个更复杂的例子中,我可能不会很快知道(或者想弄清楚,如果我是懒惰的)我应该使用的确切上限.那么,我只需要制作一系列整数然后除以10,对吧?不:
ghci> map (/10) [1,3..10]
[0.1,0.3,0.5,0.7,0.9,1.1]
Run Code Online (Sandbox Code Playgroud)
任何浮点函数似乎都会导致此行为:
ghci> map (*1.0) [1,3..10]
[1.0,3.0,5.0,7.0,9.0,11.0]
Run Code Online (Sandbox Code Playgroud)
而非浮动函数则不:
ghci> map (*1) [1,3..10]
[1,3,5,7,9]
Run Code Online (Sandbox Code Playgroud)
虽然看起来不太可能,但我认为可能还有一些懒惰的评估在起作用,并试图首先强制评估范围:
ghci> let list = [1,3..10] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0,11.0]
Run Code Online (Sandbox Code Playgroud)
显然,使用文字列表而不是范围工作正常:
ghci> map (*1.0) [1,3,5,7,9]
[1.0,3.0,5.0,7.0,9.0]
ghci> let list = [1,3,5,7,9] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0]
Run Code Online (Sandbox Code Playgroud)
它不只是映射:
ghci> last [1,3..10]
9
ghci> 1.0 * (last [1,3..10])
11.0
Run Code Online (Sandbox Code Playgroud)
如何将函数应用于范围的结果会影响该范围的实际评估结果?
ziv*_*rah 11
当我写这篇文章时,我自己回答了这个问题.
Haskell使用类型推断,因此当它看到一个浮点函数被映射到一个列表上(或者在该列表的一个元素上使用时,就像在我的示例中使用last),它将推断该列表的类型是浮点因此,评估范围,好像它是,[1,3..10] :: [Float]而不是我想要的,这是[1,3..10] :: [Int]
此时,它使用Float规则进行枚举,如我在问题中链接的帖子中所述.
预期的行为可以像这样强制:
ghci> map (\x -> (fromIntegral x) / 10) ([1,3..10]::[Int])
[0.1,0.3,0.5,0.7,0.9]
Run Code Online (Sandbox Code Playgroud)
依赖于Haskell的类型推断,我们可以删除::[Int]fromIntegral导致我们的lambda表达式具有正确的类型:
ghci> :t (\x -> (fromIntegral x) / 10)
(\x -> (fromIntegral x) / 10)
:: (Fractional a, Integral a1) => a1 -> a
Run Code Online (Sandbox Code Playgroud)