对数次递归计算Fibonacci数列

翻了翻博客,距上一次更新差不多快一个月了。在摸黑起床又摸黑睡觉的忙了半个月之后,又迷上了两个APP(Hunters 2Mini Motor Racing),也就懒得更新了。

今天在朋友的博客上看到一篇文章对数步计算斐波那契数列(不知为什么当时首先想到的是当年奎哥的口头禅“小技巧”,看来“中毒”颇深,呵呵!),觉得挺有意思的便来证明一下。

根据Fibonacci数列的定义,很直观的可以通过重复下面这个过程来进行计算

`{(a larr a + b),(b larr a):}`

这个过程很容易转化为矩阵形式:

`((a),(b)) larr ((1,1),(1,0))((a),(b))`

更一般的,考虑线性变换

`f_(p,q) = ((p+q,q),(q,p))`

显然,Fibonacci数列的每一次迭代可表示为`f_(0,1)`。下面考虑一般化的情形,计算第n个Fibonacci数的过程可表示为

$f^n := (f_{p,q})^n = \overbrace{f \cdot f \cdots f}^{n个}$

通过矩阵运算可知

`f^2 = ((p+q,q),(q,p))((p+q,q),(q,p)) = ((p^2+2pq+2q^2,2pq+q^2),(2pq+q^2,p^2+q^2)) = ((p'+q',q'),(q',p')) := f_(p',q')`

其中`{(p' = p^2 + q^2),(q' = 2pq + q^2):}`

所以`f^n`可分解为

`f^n = {(f * f^(n-1), text{if n is odd}), ((f^2)^(n/2) = f_(p',q')^(n/2), text{if n is even}):}`

于是也就有了下面这样的递归实现(这里我再转一下,不过是R的)

fibonacci <- function(n, a, b, p, q) {
  if(n==0)
    return(b)
  if(n%%2==0)
    return(fibonacci(n/2,a,b,p*p+q*q,2*p*q+q*q))
  return(fibonacci(n-1,a*p+a*q+b*q,a*q+b*p,p,q))
}
# 计算前10个数
mapply(fibonacci,n=1:10,MoreArgs=list(a=1,b=0,p=0,q=1))
 [1]  1  1  2  3  5  8 13 21 34 55

Published: May 10 2012

blog comments powered by Disqus