SICP section 1.2.2
June 28th, 2007 at 5:09 amSection 1.2.2
This section presents tree recursion, with Fibonacci numbers as the example. The authors also show how to transform the recursive Fibonacci computation into an iterative one by designing the state variables needed to be passed from call to call. There’s not much to discuss here, but let’s see the solutions to the exercises.
Exercise 1.11
First, lets translate the definition into CL code:
(defun Fr (n)
(cond ((< n 3) n)
(t (+ (Fr (- n 1))
(* 2 (Fr (- n 2)))
(* 3 (Fr (- n 3)))))))
Now, lets apply a transformation similar to what the authors did with Fibonacci. The key idea here is to keep as much state variables as we have recursive calls, and use them as a queue, with the first presenting the most recent computation, and so on:
a <- a + 2b + 3c (this is F(n+1) - the result) b <- a (F(n) - last result) c <- b (F(n-1) - one before last result)
To comply with the definition of F, a, b, c will be initialized to 2, 1, 0 respectively. Now we can write the code:
(defun F-iter (n)
(if (< n 3)
n
(F-iter-aux 2 1 0 n)))
(defun F-iter-aux (a b c count)
(if (= count 2)
a
(F-iter-aux (+ a (* 2 b) (* 3 c))
a
b
(- count 1))))
This technique actually makes a lot of sense if you think of how you’d solve the problem in another programming language using a loop. You would have to keep the state variables for F(n-1), F(n-2), F(n-3) explicitly and update them during the loop. Instead, in this tail-recursive Lisp solution, the state variables are passed along as function arguments, but in fact serve the same purpose.
Exercise 1.12
If we design a function that returns the number in the Pascal triangle on some row row and column col, the code is straightforward (rows and columns are numbered from 1):
(defun pascal (row col)
(cond ((= row 1) 1)
((= row col) 1)
((= col 1) 1)
(t (+ (pascal (1- row) col)
(pascal (1- row) (1- col))))))
Note that this function will return incorrect results for nonexistent cells of the Pascal triangle. I think it is safe to assume that the function that calls pascal in order to actually draw the triangle won’t pass in invalid values.
Exercise 1.13
I will post the proof using pure ASCII to ensure viewability on all browsers. Also, I will define qr5 as the square root of 5, which appears frequently in the proof.
fi = (1 + qr5)/2 psi = (1 - qr5)/2 As the hint suggests, I will try to prove the lemma: (*) Fib(n) = (fi^n - psi^n)/qr5 To prove by induction, I'll first prove the base cases: Fib(0) = (fi^0 - psi^0)/qr5 = 0 Fib(1) = (fi^1 - psi^1)/qr5 fi - psi = qr5 => Fib(1) = qr5/qr5 = 1 Done. Now the induction step. Assuming that the lemma (*) is true for n-1 and n-2, I will prove that it's true for n: Fib(n) = Fib(n-1) + Fib(n-2) = (fi^(n-1) - psi^(n-1) + fi^(n-2) - psi^(n-2)) / qr5 = ((fi+1)*fi^(n-2) - (psi+1)*psi(n-2)) / qr5 But fi is the renown Golden Ratio, so: fi^2 = fi+1 If you check with a calculator, you'll see that the same can be said of psi: (2) psi^2 = psi+1 So if we substitute fi+1 and psi+1: (fi^2*fi^(n-2) - psi^2*psi^(n-2)) / qr5 = (fi^n - psi^n) / qr5 Q.E.D. hint Now, to use this hint for the final proof, just notice that psi = -0.618, so when n becomes large, psi becomes negligible, and so Fib(n) can be approximated well by: fi^n/qr5 Q.E.D.
Related posts:

July 6th, 2007 at 10:57
Hi Eli,
i’ve been doing these exercises on paper since i don’t have a scheme interpreter right here. For the Pascal’s Triangle i came up with a solution quite similar to yours (besides that i start counting from zero). The only big difference is the initial test, is it necessary to test that you’re in the first row? I mean, the first level matches the other 2 conditions (first col and row = col).
July 6th, 2007 at 11:25
It is necessary for the case of a wrong column in row 1 (say, column 2). Without the test, it goes into an infinite loop (instead of just giving a wrong answer)
April 23rd, 2008 at 05:16
Hi,
I just started reading SICP as well. Looks like your version of the pascal function gives some wrong answers, e.g. (pascal 2 4) gives 2 instead of 0.
Here’s mine in Scheme
(define (pascal x y)
(cond ((= 1 x) 1)
April 23rd, 2008 at 05:23
sorry somehow it got cut off, and my x = your col and vice versa
(define (pascal x y)
(cond ((= 1 x) 1)
((> x y) 0)
(else (+ (pascal (- x 1) (- y 1))
(pascal x (- y 1))))))
May 13th, 2008 at 18:27
Anh,
My solution gives correct values for all the elements inside the triangle. As far as my understanding goes, there is no required value for elements outside the triangle, and the exercise in SICP doesn’t enforce anything specific.
Your solution is shorter and gives 0 for outside the triangle.
April 4th, 2009 at 01:34
Did anyone take them up on their challenge on page 41, about implementing count-change iteratively? I have a solution, but I’m not very happy about it.
June 17th, 2009 at 20:27
Hello, I stumbled on your site searching for solutions to the exercises in sicp to compare to mine. To be brief i just want to say great job, I am thankful for the time you spent in providing such a useful site. Now to the point.
I am questioning your proof in exercise 1.13. Does this proof assert that Fib(n) is the closest integer to (fi^n)/5?
June 19th, 2009 at 07:00
@Devon,
Fib(n) is the closest integer to (fi^n)/5 only when n is relatively large
June 19th, 2009 at 15:12
Thank you for your speedy response. I was misled by the problem posed: “Prove that Fib(n) is the closest integer to (fi^n)/qr5
August 6th, 2009 at 01:42
@eliben,
I’m pretty sure that Fib(n) is always the closest integer to (fi^n)/sqrt(5)
(I was able to prove it). I’d be interested if you could provide a counterexample as it would mean I made a mistake in my proof.
February 3rd, 2010 at 13:28
Terrible.
It begins like that
Fib(n)=Fib(n-1)+Fib(n-2)
Use mathematical induction method:
Easily know, Fib(0),Fib(1) is integer=>Fib(2) = Fib(0) + Fib(1) is integer too.
Assume Fib(k) (k<n) is integer,
So Fib(k+1) = Fib(k-1)+Fib(k-2) is integer.
continue…
February 3rd, 2010 at 13:28
It proves that all Fib(n) is integer.
fi = (1 + qr5)/2,
psi = (1 – qr5)/2 =>|psi|=0.0743|psi^n||psi^n|/qr5<0.07/qr5<0.5
Fib(n)=Fib(n) = (fi^n – psi^n)/qr5
so |Fib(n) – fi^n/qr5|=|psi^n/qr5|<0.5
It proves the distances from Fib(n) to fi^n/qr5 is less than 0.5. And Fib(n) is integer proven above. We can say Fib(n) is closest interger to fi^n/qr5
February 3rd, 2010 at 13:33
OK. Sorry for submit serveral times. The reply always was mixed and shorten. You can delete the first two wrong reply of mine.