Search code examples
loopsschemelispfibonaccisicp

fibonacci sequence using iterative process in SICP, cannot completely understand


Here is an iterative example of a procedure computing the fibonacci sequence in SICP. The idea is:

  • a = fib(n+1) = a+b
  • b = fib(n) = a
(define (fib n) 
  (fib-iter 1 0 n))
(define (fib-iter a b count)
  (if (= count 0)
      b
      (fib-iter (+ a b) a (- count 1))))

Looking at it deeper, I don't understand why continuing the computation towards fib(n+1) is necessary. I found we could have written.

;; a and b are first and second integers respectively
;; in the recursive call, b would be replaced by a+b because it is the next number in the sequence
;; so now a will be replaced by the previous value of b because it is the previous value.
(define (fib2 n) 
  (fib-iter 1 0 n))
(define (fib-iter a b count)
  (if (= count 0)
      b
      (fib-iter b (+ a b) (- count 1))))

Now, I really think the first example, the one continuing up to n+1 is really redundant. I don't understand why is that necessary. What's wrong with my proposed iterative example?


Solution

  • Bot procedures produce correct result. However, the first one retains the relationship between a and b: a is Fib(i+1) and b is Fib(i) where i=n-count. The second method uses the first iteration to swap a and b around, thus introducing one redundant iteration. This can be seen by taking the trace of procedures:

    > (define (fib n) 
      (fib-iter 1 0 n))
    
    (define (fib-iter a b count)
      (if (= count 0)
          b
          (fib-iter (+ a b) a (- count 1))))
    > (trace fib-iter)
    > (fib 3)
    >(fib-iter 1 0 3)
    >(fib-iter 1 1 2)
    >(fib-iter 2 1 1)
    >(fib-iter 3 2 0)
    <2
    2
    > (define (fib-iter a b count)
      (if (= count 0)
          b
          (fib-iter b (+ a b) (- count 1))))
    > (trace fib-iter)
    > (fib 3)
    >(fib-iter 1 0 3)
    >(fib-iter 0 1 2)
    >(fib-iter 1 1 1)
    >(fib-iter 1 2 0)
    <2
    2
    

    What you actually want is something like this:

    > (define (fib n)
      (if (zero? n)
          0
          (fib-iter 0 1 (- n 1))))
    
    (define (fib-iter a b count)
      (if (zero? count)
          b
          (fib-iter b (+ a b) (- count 1))))
    
    > (trace fib-iter)
    > (fib 3)
    >(fib-iter 0 1 2)
    >(fib-iter 1 1 1)
    >(fib-iter 1 2 0)
    <2
    2
    

    Notice, there is one less iteration. However, I'm doing extra work in procedure fib.