There is a clever algorithm for computing the Fibonacci numbers in a logarithmic number of steps. Recall the transformation of the state variables a and b in the
fib-iter
process of section 1.2.2: a ← a + b and b ← a. Call this transformation T, and observe that applying T over and over again n times, starting with 1 and 0, produces the pair Fib(n + 1) and Fib(n). In other words, the Fibonacci numbers are produced by applying Tn, the nth power of the transformation T, starting with the pair (1,0). Now consider T to be the special case of p = 0 and q = 1 in a family of transformations Tpq, where Tpq transforms the pair (a,b) according to a ← bq + aq + ap and b ← bp + aq. Show that if we apply such a transformation Tpq twice, the effect is the same as using a single transformation Tp'q' of the same form, and compute p' and q' in terms of p and q. This gives us an explicit way to square these transformations, and thus we can compute Tn using successive squaring, as in the fast-expt
procedure. Put this all together to complete the following procedure, which runs in a logarithmic number of steps:(define (fib n) (fib-iter 1 0 0 1 n)) (define (fib-iter a b p q count) (cond ((= count 0) b) ((even? count) (fib-iter a b ; compute p' ; compute q' (/ count 2))) (else (fib-iter (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1)))))
We're given the transformation:
Tpq(a, b) = ((bq + aq + ap), (bp + aq))If we apply the transformation Tpq to itself then we get the following:
Tpq(Tpq(a, b)) = Tpq((bq + aq + ap), (bp + aq)) = (((bp + aq)q + (bq + aq + ap)q + (bq + aq + ap)p), ((bp + aq)p + (bq + aq + ap)q)) = ((bpq + aq2 + bq2 + aq2 + apq + bpq + apq + ap2), (bp2 + apq + bq2 + aq2 + apq)) = ((b(q2 + 2pq) + a(q2 + 2pq) + a(p2 + q2)), (b(p2 + q2) + a(q2 + 2pq)))Now if we define p' and q' as:
p' = p2 + q2 q' = q2 + 2pq...then this gives:
Tpq(Tpq(a, b)) = ((bq' + aq' + ap'), (bp' + aq'))...which is of the same form as the transform Tpq, and so we can define Tp'q'(a, b) as:
Tp'q'(a, b) = ((bq' + aq' + ap'), (bp' + aq')) = ((b(q2 + 2pq) + a(q2 + 2pq) + a(p2 + q2)), (b(p2 + q2) + a(q2 + 2pq)))We can now simply plug the mappings for p' and q' into the template procedure above to give:
(define (fib n) (fib-iter 1 0 0 1 n)) (define (fib-iter a b p q count) (cond ((= count 0) b) ((even? count) (fib-iter a b (+ (square p) (square q)) (+ (* 2 p q) (square q)) (/ count 2))) (else (fib-iter (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1)))))Finally, we can check it works as expected:
> (fib 0) 0 > (fib 1) 1 > (fib 2) 1 > (fib 3) 2 > (fib 4) 3 > (fib 5) 5 > (fib 6) 8 > (fib 7) 13 > (fib 8) 21
Yeah, but WHY does it work? Why is the Tpq transformation the way it is? How did the authors of this book know its correct form?
ReplyDeleteI don't know either. But I can assure you that you are not the only one confused here by this problem. :)
DeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
Delete