ham*_*mar 50
这是Haskell公式的直接翻译:
fib n = round $ (phi^n - (1 - phi)^n) / sqrt 5
where phi = (1 + sqrt 5) / 2
Run Code Online (Sandbox Code Playgroud)
这给出了正确的值n = 75,因为它使用Double精确的浮点算法.
但是,我们可以通过使用表单的数字来避免浮点运算a + b * sqrt 5!让我们为他们创建一个数据类型:
data Ext = Ext !Integer !Integer
deriving (Eq, Show)
instance Num Ext where
fromInteger a = Ext a 0
negate (Ext a b) = Ext (-a) (-b)
(Ext a b) + (Ext c d) = Ext (a+c) (b+d)
(Ext a b) * (Ext c d) = Ext (a*c + 5*b*d) (a*d + b*c) -- easy to work out on paper
-- remaining instance methods are not needed
Run Code Online (Sandbox Code Playgroud)
我们免费获得取幂,因为它是根据Num方法实现的.现在,我们必须稍微重新安排配方才能使用它.
fib n = divide $ twoPhi^n - (2-twoPhi)^n
where twoPhi = Ext 1 1
divide (Ext 0 b) = b `div` 2^n -- effectively divides by 2^n * sqrt 5
Run Code Online (Sandbox Code Playgroud)
这给出了一个确切的答案.
Daniel Fischer指出我们可以使用公式phi^n = fib(n-1) + fib(n)*phi并使用形式的数字a + b * phi(即ℤ[φ]).这避免了笨拙的除法步骤,并且仅使用一个取幂.这提供了更好的实现:
data ZPhi = ZPhi !Integer !Integer
deriving (Eq, Show)
instance Num ZPhi where
fromInteger n = ZPhi n 0
negate (ZPhi a b) = ZPhi (-a) (-b)
(ZPhi a b) + (ZPhi c d) = ZPhi (a+c) (b+d)
(ZPhi a b) * (ZPhi c d) = ZPhi (a*c+b*d) (a*d+b*c+b*d)
fib n = let ZPhi _ x = phi^n in x
where phi = ZPhi 0 1
Run Code Online (Sandbox Code Playgroud)
Don*_*art 16
简单来说,来自Haskell维基页面的Binet公式在Haskell中给出:
fib n = round $ phi ^ n / sq5
where
sq5 = sqrt 5
phi = (1 + sq5) / 2
Run Code Online (Sandbox Code Playgroud)
其中包括共享平方根的结果.例如:
*Main> fib 1000
4346655768693891486263750038675
5014010958388901725051132915256
4761122929200525397202952340604
5745805780073202508613097599871
6977051839168242483814062805283
3118210513272735180508820756626
59534523370463746326528
Run Code Online (Sandbox Code Playgroud)
对于任意整数,您需要对转换为浮点值更加小心.请注意,此时Binet的值与递归公式有很大不同:
*Main> let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
*Main> fibs !! 1000
4346655768693745643568852767504
0625802564660517371780402481729
0895365554179490518904038798400
7925516929592259308032263477520
9689623239873322471161642996440
9065331879382989696499285160037
04476137795166849228875
Run Code Online (Sandbox Code Playgroud)
您可能需要更高的精度:-)