【发布时间】:2023-03-17 06:27:02
【问题描述】:
如果我这样写一个递归阶乘:
fact 0 = 1
fact n = n * (fact (n-1))
ghci 告诉我它的类型为 (Eq p, Num p) => p -> p。
我希望 Haskell 很聪明,并且能够快速实现这个阶乘。因此,如果我写:fact (10 :: Int) 使用Ints 时,所有这些都将是快速数学,如果我写fact (1000 :: Integer),则使用Integers 时,所有或部分计算将是慢速数学。
ghci 在这里很有帮助:
λ: :t fact (2 :: Int)
fact (2 :: Int) :: Int
λ: :t fact (2 :: Integer)
fact (2 :: Integer) :: Integer
我有两个问题:
Q1 : 当我运行时会发生什么
λ: fact (10 :: Int)
>3628800
λ: fact (40 :: Int)
>-7060926325325235253252...
λ: fact (66 :: Int)
>0
很明显,Haskell 无法为较大的参数计算正确的结果,因为它会溢出。所以我对fact 40 的结果并不感到惊讶,我得到了与fact 65 相似的结果。但是从fact 66开始,函数总是返回0。怎么会呢?
Q2:给定一个对 fact 的调用,所有对 fact 的递归调用都将使用相同的类型是否正确,即使在某些调用中 Int 可以替换为 Integer (即整个计算速度较慢)如果编译器能够在运行时在每次调用的基础上在 Int 和 Integer 之间做出决定,那将是不可能的)。
【问题讨论】:
-
因为
0* 任何其他号码都是0。 -
我想这是一个很好的观点,如果
fact 66为 0,那么所有向上的东西也将为 0。但是,fact 66为零有一个重要的原因吗?如果我计算toInteger((fact 65 :: Int)) * 66我会得到一个我不明白为什么它会是 0 作为 Int 的值。 -
这是因为
Int具有固定数量的位,并且每次都省略了较高的位。在某些时候,该值将为零。特别是因为我们经常乘以 2 的幂,因此我们将这些位“移出”最低位。 -
是的,有一个原因:
Numeric.showHex (product [1..66 :: Integer]) "" "10b395943e6086f3f811b267cc58286d7c1eb06b9a4de25bacad2cd8d5dc2b0000000000000000"的最后 64 位 -
@ARRG 比较
toInteger (fact 65 :: Int) * 66和(2^64) * 33 :: Integer可能会有所启发。
标签: haskell