我似乎有一个距离公式,直接运行时工作正常,但不是作为一个函数运行时.我有:
data Point = Point Int Int
deriving (Ord, Eq, Show)
distance :: Point -> Point -> Double
distance (Point x1 y1) (Point x2 y2) =
sqrt $ fromIntegral $ ((x2 - x1) ^ 2) + ((y2 - y1) ^ 2)
Run Code Online (Sandbox Code Playgroud)
distance (Point 0 0) (Point 357356081635 896342957994)以ghci 运行产生NaN.但是,替换并直接运行会sqrt $ fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2)产生一个有用的数值结果:9.649528835269391e11.
为什么?(谢谢,QuickCheck,找到这个!)
想一想.
你正在做正方形和减法Int- 所以你会溢出并得到负值而不是传递给平方根:
> let x1 = 0 :: Int
> let y1 = 0 :: Int
> let x2 = 357356081635 :: Int
> let y2 = 896342957994 :: Int
> ((x2-x1) ^ 2) + ((y2 - y1) ^ 2)
-2233181682604143571
Run Code Online (Sandbox Code Playgroud)
你可以看到你得到一个负数.
第二部分(在ghci中)足够聪明,可以采用正确的类型,因为你没有以任何方式限制它(尝试:t)
> :t fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2)
fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2) :: Num b => b
> :t sqrt $ fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2)
sqrt $ fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2) :: Floating a => a
> sqrt $ fromIntegral $ (357356081635 ^ 2) + (896342957994 ^ 2) :: Double
9.649528835269391e11
Run Code Online (Sandbox Code Playgroud)
你可以通过引入fromIntegral内部来完成这项工作:
> sqrt $ (fromIntegral x2 - fromIntegral x1)^2 + (fromIntegral y2 - fromIntegral y1) ^ 2
9.649528835269391e11
Run Code Online (Sandbox Code Playgroud)
Piezoid在下面的优秀评论中添加了这个:
要评估具有多态文字的表达式,ghci必须选择一种类型.在这种情况下,大数字用Integer表示,Integer是任意精度
整数的类型(以一些开销为代价).:set -fwarn-type-defaults当这种行为出现时,使用会在ghci中警告你.使用双打,如本答案中所建议的,是一个更好的解决方案,因为结果是Double.此外,函数hypot还有一个更好的计算路径:Wikipedia.
| 归档时间: |
|
| 查看次数: |
153 次 |
| 最近记录: |