SICP Exercise 1.19
Question
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 1.2.2: $a\leftarrow a+b$ and $b\leftarrow 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 $T^n$, the $n$th 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 $T_{pq}$ where $T_{pq}$ transforms the pair $(a,b)$ according to $a\leftarrow bq+aq+ap$ and $b\leftarrow bp+aq$.
Show that if we apply such a transformation $T_{pq}$ twice, the effect is the same as using a single transformation $T_{p’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 $T^n$ 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)))))
Answer
(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
(+ (* q q) (* p p))
(+ (* 2 p q) (* q q))
(/ count 2)))
(else
(fib-iter (+ (* b q)
(* a q)
(* a p))
(+ (* b p)
(* a q))
p
q
(- count 1)))))
As specified in the question, let us first see what the result is if we apply $T_{pq}$ twice in a row:
$$ \begin{align} a\leftarrow &bq+aq+ap \newline b\leftarrow &bp+aq \newline a'\leftarrow &(bp+aq)q +(bq+aq+ap)q+(bq+aq+ap)p \newline b'\leftarrow &(bp+aq)p+(bq+aq+ap)q \end{align} $$
We can rewrite $a$ as:
$$ \begin{align} a'\leftarrow &bpq+aqq+bqq+aqq+apq+bpq+apq+app \newline a'\leftarrow &2bpq+bqq+2apq+2aqq+app \end{align} $$
Which we can then bring into the same shape as our original transformation $a\leftarrow bq+aq+ap$:
$$ \begin{align} a'\leftarrow &b(2pq+q^2)+a(2pq+q^2)+a(p^2+q^2) \end{align} $$
This gives us the values for $p'$ and $q'$:
$$ \begin{align} p'&=p^2+q^2 \newline q'&=2pq+q^2 \end{align} $$
We can verify this by using these new values for $b'$:
$$ b'\leftarrow b(p^2+q^2)+a(2pq+q^2) \newline $$
And then rewriting our original definition for $b'$ to come to the exact same equation:
$$ \begin{align} b'\leftarrow &(bp+aq)p+(bq+aq+ap)q \newline b'\leftarrow &bpp+apq+bqq+aqq+apq \newline b'\leftarrow &bpp+bqq+2apq+aqq \newline b'\leftarrow &b(p^2+q^2)+a(2pq+q^2) \newline \end{align} $$ $$ \tag*{$\Box$} $$