Browse Source

Finished first draft of the Fibonacci blog post.

pull/2/head
jrtechs 6 years ago
parent
commit
7abc9097d0
2 changed files with 102 additions and 2 deletions
  1. +102
    -2
      blogContent/posts/programming/EverythingFibonacci.md
  2. BIN
      blogContent/posts/programming/media/fibonacci/FibonacciMatrix.png

+ 102
- 2
blogContent/posts/programming/EverythingFibonacci.md View File

@ -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

BIN
blogContent/posts/programming/media/fibonacci/FibonacciMatrix.png View File

Before After
Width: 1330  |  Height: 822  |  Size: 61 KiB

Loading…
Cancel
Save