|
@ -1,6 +1,17 @@ |
|
|
|
|
|
If you have ever taken a computer science class you probably |
|
|
|
|
|
know what the fibonacci sequence is and how to calculate it. |
|
|
|
|
|
For those who don't know: [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci) |
|
|
|
|
|
is a sequence of numbers starting with 0,1 whose next number is the sum |
|
|
|
|
|
of the two previous numbers. After having multiple of my CS classes |
|
|
|
|
|
give lectures and multiple homeworks on the Fibonacci sequence; I decided |
|
|
|
|
|
that it would be a good idea to write a blog post going over |
|
|
|
|
|
the 4 main ways of calculating the nth term of the Fibonacci sequence |
|
|
|
|
|
and proving their time complexities both mathematically and empirically. |
|
|
|
|
|
|
|
|
|
|
|
# Slow Recursive Definition |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
By the definition of the Fibonacci sequence, it is natural to write it as |
|
|
|
|
|
a recursive definition. |
|
|
|
|
|
|
|
|
```Python |
|
|
```Python |
|
|
def fib(n): |
|
|
def fib(n): |
|
@ -9,9 +20,42 @@ def fib(n): |
|
|
return fib(n-1) + fib(n-2) |
|
|
return fib(n-1) + fib(n-2) |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
#### Time Complexity |
|
|
|
|
|
|
|
|
|
|
|
Observing that each call has two recursive calls we can place an upper bound on this |
|
|
|
|
|
function as O(2^n). However, if we solve this recurrence we can compute the exact value |
|
|
|
|
|
and place a tight bound for time complexity. |
|
|
|
|
|
|
|
|
|
|
|
We can write a recurrence for the number of times fib is called: |
|
|
|
|
|
```angular2html |
|
|
|
|
|
T(1) = 1 |
|
|
|
|
|
T(n) = T(n-1) + T(n-2) |
|
|
|
|
|
a^n = a^{n-1} + a^{n-2} |
|
|
|
|
|
a^2 = a + 1 |
|
|
|
|
|
a = \frac{1 + sqrt(5)}{2} |
|
|
|
|
|
|
|
|
|
|
|
T(n) = \frac{1 + sqrt(5)}{2}^n + \frac{1 1 sqrt(5}{2}^n |
|
|
|
|
|
|
|
|
|
|
|
O(1.618^n) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Measured Performance |
|
|
|
|
|
|
|
|
|
|
|
Here is a graph of the actual performance that I observed for this algorithm. |
|
|
![Recursive Definition](media/fibonacci/RecursiveDefinition.png) |
|
|
![Recursive Definition](media/fibonacci/RecursiveDefinition.png) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Accumulation Solution |
|
|
|
|
|
|
|
|
|
|
|
The problem with the previous recursive solution is that you had to recalculate certain |
|
|
|
|
|
terms of fibonacci a ton of times. A summation variable would help us avoid this problem. |
|
|
|
|
|
You could write this using a simple loop, however, it is still possible to do this with |
|
|
|
|
|
recursion. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Python |
|
|
```Python |
|
|
def fibHelper(n, a, b): |
|
|
def fibHelper(n, a, b): |
|
|
if n == 0: |
|
|
if n == 0: |
|
@ -25,9 +69,41 @@ def fibIterative(n): |
|
|
return fibHelper(n, 0, 1) |
|
|
return fibHelper(n, 0, 1) |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
In this code example fibHelper is a method which accumulates the previous two terms. |
|
|
|
|
|
The fibIterative is a wrapper method which sets the two initial terms equal to 0 and 1 |
|
|
|
|
|
representing the fibonacci sequence. |
|
|
|
|
|
|
|
|
|
|
|
Proof in latex that fibHelper |
|
|
|
|
|
|
|
|
|
|
|
proof in latex that fib iterative = fib |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Time Complexity |
|
|
|
|
|
|
|
|
|
|
|
proof in latex for time complexity |
|
|
|
|
|
|
|
|
|
|
|
#### Measured Performance |
|
|
|
|
|
|
|
|
|
|
|
Notice how much faster this solution is compared to the original recursive solution for |
|
|
|
|
|
Fibonacci. Also, I only measured going out to 500 because beyond that I hit the maximum |
|
|
|
|
|
number of recursive calls for my installation of Python. |
|
|
|
|
|
|
|
|
![Iterative Performance](media/fibonacci/Iterative.png) |
|
|
![Iterative Performance](media/fibonacci/Iterative.png) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Matrix Solution |
|
|
|
|
|
|
|
|
|
|
|
We can actually get better than linear time for performance while calculating |
|
|
|
|
|
the Fibonacci sequence recursively. |
|
|
|
|
|
|
|
|
|
|
|
![Inductive Proof of Fibonacci Matrix](media/fibonacci/FibonacciMatrix.png) |
|
|
|
|
|
|
|
|
|
|
|
Without any other tricks, raising a matrix to a power n times would not get |
|
|
|
|
|
us better than linear performance. However, if we use the [Exponentiation by Squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) |
|
|
|
|
|
method, we can expect to see logarithmic time. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```Python |
|
|
```Python |
|
|
def multiply(a,b): |
|
|
def multiply(a,b): |
|
|
product = [0,0,0] |
|
|
product = [0,0,0] |
|
@ -52,7 +128,31 @@ def fibPower(n): |
|
|
return power(l, n)[1] |
|
|
return power(l, n)[1] |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
#### Time Complexity |
|
|
|
|
|
|
|
|
|
|
|
latex proof for 9lg(n) performance |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Measured Performance |
|
|
![FibPower Performance](media/fibonacci/FibPower.png) |
|
|
![FibPower Performance](media/fibonacci/FibPower.png) |
|
|
|
|
|
As expected by our mathmatical calcuations, the algorthem appears to be running in |
|
|
|
|
|
logarithmic time. |
|
|
|
|
|
|
|
|
|
|
|
#### Measured Performance With Large Numbers |
|
|
|
|
|
![FibPower Performance](media/fibonacci/FibPowerBigPicture.png) |
|
|
|
|
|
|
|
|
|
|
|
When calculating the fibonacci term for extremely large numbers dispite having a polynomial |
|
|
|
|
|
time complexity, the space required to compute Fibonacci grows exponentially. Since our |
|
|
|
|
|
performance is only pseudo-polynomial we see a degrade in our performance when calculating |
|
|
|
|
|
large terms of the fibonacci sequence. |
|
|
|
|
|
|
|
|
|
|
|
The one amazing thing to point out here is that despite calculating the 10,000 term of Fibonacci, |
|
|
|
|
|
this algorithm is nearly 400 times faster than the recursive algorithm when it was calculating |
|
|
|
|
|
the 30th term of Fibonacci. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Closed Form Definition |
|
|
|
|
|
|
|
|
|
|
|
It is actually possible to calculate Fibonacci in constant time using a closed form definition. |
|
|
|
|
|
|
|
|
![FibPower Performance](media/fibonacci/FibPowerBigPicture.png) |
|
|
|
|
|
|
|
|
latex proof of closed form definition |