You are on page 1of 6

Fibonacci Sequence: From Solving the Recurrence

Relation in Exponential Time to The Logarithmic Time


Implementation

Ihab McShea
Misr University for Science and Technology
1 Fibonacci Numbers
Fibonacci1 sequence is a sequence of integers, characterized by the fact that
every number is the combination of the two numbers that precede the specic
number in the sequence:
0,1,1,2,3,5,8,13,21,34,55, ...
The Fibonacci sequence can be treated as a recursive function, where as
we have mentioned each function of n is the combination of the previous two
functions, f(n) = f(n-1) + f(n-2), so a sample recursion chart when you run the
function (the naive way) to get the 7th Fibonacci number is as follows:

The gure is actually not a complete one, but the point of that chart is to say
that to get the seventh Fibonacci number we have to recursively call the function
~ 25 times, we will discuss later how to reduce that time. The follwing code (in
Python) is the implementation of the naive Fibonacci sequence algorithm:
def Fib(n ):
1 (1175-1250) was an Italian mathematician, often called the most talented mathematician
of the middle ages.

1
i f n==0:
return 0
e l i f n==1:
return 1
else :
return Fib(n 1) + Fib(n 2)

Solving the recurrence relation for

the naive Fibonacci Algorithm:

As we have seen in the implementation, recursion chart and description above,


we get the nth Fibonacci number from the following recurrence relation:
f(n) = f(n-1) + f(n-2)
A linear recurrence has the form:
T(n) = a1T(n-1) + a2(n-2) + ... + ak(n-k) = P a T (n i) for a xed
k

aiand k, where k is the order. i=1 i

Let's try guessing the solution to the recurrence formula, let's say it's some-
thing raised to n, an exponential function:
f(n) = for some constant
n

We replace the previous recurrence relation:


n n1 n2

=> = + 1 (by dividing both sides by )


= +
2 n2

Reformulating: 1 = 0, a good old quadratic equation. You can get


2

the solution to that, can't you?



1 5
=
2
So we have two solutions to, a positive and a negative; does the positive
remind you of anything? Yes, the golden ratio.
And since this is a linear recurrence the solution can be any combination
of the roots of the equation 1 = 0, we'll worry about the boundary
2

conditions in a minute.
F(n) = c1( ) + c2( )

1+ 5 n

1 5 n

Taking the boundary conditions into considerations:


2 2

F(0) = 0 = c1( ) + c2( )



1+ 5 0

1 5 0

c1+ c2=0 2 2

c1 = - c 2
F(1) = 1 = c1( ) + c2( )

1+ 5 1

1 5 1

= c1 ( ) - c1 ( )
2 2
1+ 5 1 1 5 1

Taking c1as common


2
factor
2

=c1( ) = c1 ( 5)

2 5
2

2
c1 = , c2 =
1 1

So, the nal equation


5 5
should look something like this:
f(n) = ( )n - ( )

1 1+ 5

1 1 5 n

And obviously as n gets bigger and bigger the term ( ) diminishes as it


5 2 5 2

1 5

converges to zero, sonthe equation might look something like this:


2

f(n) = ( ) + (n), |(n) | for n 4



1 1+ 5 1

So the running time of this naive Fibonacci algorithm is roughly O( ),


5 2 10
n

where = , so exponential time; that's way this algorithm is naive, and in



1+ 5

the next sections we'll explore ways to reduce its running time from exponential
2

time to maybe polynomail time and perhaps linear logarithmic time.


Speeding Up Fibonacci Sequence Algorithm using
Dynamic Programming
If you are not familiar with the term dynamic programming (also known as
dynamic optimization) is a method for solving a complex problem by breaking
(dividing) it into a collection of subproblems, solving each of those subproblems
just once, and storing their solutions ideally, using a memory based data
structure. Next time we need a previously computed problem, we simply refer
to the data structure we used to store our previously computed result to return
it for us rather than re-solving the problem like we have seen in the naive
implementation of the Fibonacci algorithm.
Ideally for this DP algorithm to get a specic Fibonacci number we are going
to use a dictionary data structure (implemented through a hash table or a search
tree) to store our previously computed Fibonacci numbers so we don't have to
call the function so many times like we have seen in gure 1. Let's take a look
on the code (in Python):
def fib (n ):
memo = {}
i f n in memo:
return memo[n]
e l i f n==0:
return 0
e l i f n==2 or n==1:
return 1
else :
f = fib (n 1) + fib (n 2)
memo[n] = f
return f

3
3.1 Case Study for b(7):

4
See? A little lighter, actually, much lighter. Assuming n-bit registers for
each entry of memo/dictionary data structure:
T(n) = T(n-1) + c
Where c is the the time needed to add n-bit numbers to the memo.
T(n) ~ O(n )
2

Can we get the Fibonacci algorithm to run in O(log2 (n))


time?
Yes, there are many dierent ways we can run the Fibonacci algorithm that
took in its naive form an exponential time, and in the previously mentioned
DP form a polynomial time (quadratic time to be specic) in logarithmic time.
We'll explore an idea built on a Linear Algebraic basis.
First of all, let's see take a look at this interesting recurrence formula:
If n is even, f(n) = [ 2*f(k-1) + f(k)] * f(k)
If n is odd, (k = (n+1)/2), f(n) = f(k)* f(k) + f(k-1)*f(k-1)
Where does this recurrence equation come from?
( 11 10 )n = ( f (nf (n)
1) f (n)
)
Taking the determinant of both
f (n 1)
sides, we get:
(-1)n = (f(n-1)*f(n-1)) - f(n) 2
And since AnAm = An+m for any square matrix A, the following identities
can be derived:
FmFn+1 + Fm-1Fn = Fm+n
Putting m =n,
Fn 2 + Fn-12 = F2n-1
F2n = (Fn-1 + Fn+1)Fn = (2Fn-1 + Fn)Fn
To prove this, we have to put k = when n is even, and k =
n n+1

A basic C++ implementation of this is as follows:


2 2

int f [1000] = {0}; //An array for memoization


int fib ( int n){
i f (n ==0)
return 0;
i f (n == 1 | | n ==2)
return ( f [n] = 1);
i f ( f [n ])
return f [n ] ;
int k = (n & 1) ? (n+1)/2 : n/2;
//Applying the formula mentioned above
f [n] = (n & 1) ? ( fib (k) fib (k) + fib (k 1) fib (k 1)):
(2 fib (k 1) + fib (k)) fib (k );
return f [n ] ;

You might also like