Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.5 KiB

  1. If you have ever taken a computer science class you probably
  2. know what the fibonacci sequence is and how to calculate it.
  3. For those who don't know: [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci)
  4. is a sequence of numbers starting with 0,1 whose next number is the sum
  5. of the two previous numbers. After having multiple of my CS classes
  6. give lectures and multiple homeworks on the Fibonacci sequence; I decided
  7. that it would be a good idea to write a blog post going over
  8. the 4 main ways of calculating the nth term of the Fibonacci sequence
  9. and proving their time complexities both mathematically and empirically.
  10. # Slow Recursive Definition
  11. By the definition of the Fibonacci sequence, it is natural to write it as
  12. a recursive definition.
  13. ```Python
  14. def fib(n):
  15. if n == 0 or n == 1:
  16. return n
  17. return fib(n-1) + fib(n-2)
  18. ```
  19. #### Time Complexity
  20. Observing that each call has two recursive calls we can place an upper bound on this
  21. function as O(2^n). However, if we solve this recurrence we can compute the exact value
  22. and place a tight bound for time complexity.
  23. We can write a recurrence for the number of times fib is called:
  24. ```angular2html
  25. T(1) = 1
  26. T(n) = T(n-1) + T(n-2)
  27. a^n = a^{n-1} + a^{n-2}
  28. a^2 = a + 1
  29. a = \frac{1 + sqrt(5)}{2}
  30. T(n) = \frac{1 + sqrt(5)}{2}^n + \frac{1 1 sqrt(5}{2}^n
  31. O(1.618^n)
  32. ```
  33. #### Measured Performance
  34. Here is a graph of the actual performance that I observed for this algorithm.
  35. ![Recursive Definition](media/fibonacci/RecursiveDefinition.png)
  36. # Accumulation Solution
  37. The problem with the previous recursive solution is that you had to recalculate certain
  38. terms of fibonacci a ton of times. A summation variable would help us avoid this problem.
  39. You could write this using a simple loop, however, it is still possible to do this with
  40. recursion.
  41. ```Python
  42. def fibHelper(n, a, b):
  43. if n == 0:
  44. return a
  45. elif n == 1:
  46. return b
  47. return fibHelper(n-1, b, a+b)
  48. def fibIterative(n):
  49. return fibHelper(n, 0, 1)
  50. ```
  51. In this code example fibHelper is a method which accumulates the previous two terms.
  52. The fibIterative is a wrapper method which sets the two initial terms equal to 0 and 1
  53. representing the fibonacci sequence.
  54. Proof in latex that fibHelper
  55. proof in latex that fib iterative = fib
  56. #### Time Complexity
  57. proof in latex for time complexity
  58. #### Measured Performance
  59. Notice how much faster this solution is compared to the original recursive solution for
  60. Fibonacci. Also, I only measured going out to 500 because beyond that I hit the maximum
  61. number of recursive calls for my installation of Python.
  62. ![Iterative Performance](media/fibonacci/Iterative.png)
  63. # Matrix Solution
  64. We can actually get better than linear time for performance while calculating
  65. the Fibonacci sequence recursively.
  66. ![Inductive Proof of Fibonacci Matrix](media/fibonacci/FibonacciMatrix.png)
  67. Without any other tricks, raising a matrix to a power n times would not get
  68. us better than linear performance. However, if we use the [Exponentiation by Squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
  69. method, we can expect to see logarithmic time.
  70. ```Python
  71. def multiply(a,b):
  72. product = [0,0,0]
  73. product[0] = a[0]*b[0] + a[1]*b[1]
  74. product[1] = a[0]*b[1] + a[1]*b[2]
  75. product[2] = a[1]*b[1] + a[2]*b[2]
  76. return product
  77. def power(l, k):
  78. if k == 1:
  79. return l
  80. temp = power(l, k//2)
  81. if k%2 == 0:
  82. return multiply(temp, temp)
  83. else:
  84. return multiply(l, multiply(temp, temp))
  85. def fibPower(n):
  86. l = [1,1,0]
  87. return power(l, n)[1]
  88. ```
  89. #### Time Complexity
  90. latex proof for 9lg(n) performance
  91. #### Measured Performance
  92. ![FibPower Performance](media/fibonacci/FibPower.png)
  93. As expected by our mathmatical calcuations, the algorthem appears to be running in
  94. logarithmic time.
  95. #### Measured Performance With Large Numbers
  96. ![FibPower Performance](media/fibonacci/FibPowerBigPicture.png)
  97. When calculating the fibonacci term for extremely large numbers dispite having a polynomial
  98. time complexity, the space required to compute Fibonacci grows exponentially. Since our
  99. performance is only pseudo-polynomial we see a degrade in our performance when calculating
  100. large terms of the fibonacci sequence.
  101. The one amazing thing to point out here is that despite calculating the 10,000 term of Fibonacci,
  102. this algorithm is nearly 400 times faster than the recursive algorithm when it was calculating
  103. the 30th term of Fibonacci.
  104. # Closed Form Definition
  105. It is actually possible to calculate Fibonacci in constant time using a closed form definition.
  106. latex proof of closed form definition