Fibonacci: How to think recursively

Neil Cerutti neilc at norwich.edu
Wed Sep 1 16:19:07 CEST 2010


On 2010-09-01, Albert van der Horst <albert at spenarnc.xs4all.nl> wrote:
> [Didn't you mean: I don't understand what you mean by
> overlapping recursions?  You're right about the base case, so
> clearly the OP uses some confusing terminology.]
>
> I see a problem with overlapping recursions. Unless automatic
> memoizing is one, they are unduely inefficient, as each call
> splits into two calls.
>
> If one insists on recursion (untested code, just for the idea.).
>
> def fib2( n ):
>      ' return #rabbits last year, #rabbits before last '
>      if n ==1 :
>          return (1,1)
>      else
>          penult, ult = fib2( n-1 )
>          return ( ult, ult+penult)
>
> def fub( n ):
>    return fib2(n)[1]
>
> Try fib and fub for largish numbers (>1000) and you'll feel the
> problem.

There are standard tricks for converting a recursive iteration
into a tail-recursive one. It's usually done by adding the
necessary parameters, e.g.:

def fibr(n):
    def fib_helper(fibminus2, fibminus1, i, n):
        if i == n:
            return fibminus2 + fibminus1
        else:
            return fib_helper(fibminus1, fibminus1 + fibminus2, i+1, n)
    if n < 2:
        return 1
    else:
        return fib_helper(1, 1, 2, n)

Once you've got a tail-recursive solution, you can usually
convert it to loop iteration for languages like Python that favor
them. The need for a temporary messed me up.

def fibi(n):
    if n < 2:
        return 1
    else:
        fibminus2 = 1
        fibminus1 = 1
        i = 2
        while i < n: 
            fibminus2, fibminus1 = fibminus1, fibminus2 + fibminus1
            i += 1
        return fibminus2 + fibminus1

It's interesting that the loop iterative solution is, for me,
harder to think up without doing the tail-recursive one first.

-- 
Neil Cerutti



More information about the Python-list mailing list