forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added matrix exponentiation approach for finding fibonacci number. (T…
…heAlgorithms#1042) * Added matrix exponentiation approach for finding fibonacci number. * Implemented the way of finding nth fibonacci. * Complexity is about O(log(n)*8) * Updated the matrix exponentiation approach of finding nth fibonacci. - Removed some extra spaces - Added the complexity of bruteforce algorithm - Removed unused function called zerro() - Added some docktest based on request * Updated the matrix exponentiation approach of finding nth fibonacci. - Removed some extra spaces - Added the complexity of bruteforce algorithm - Removed unused function called zerro() - Added some docktest based on request * Tighten up main() and add comments on performance
- Loading branch information
1 parent
9fcfe6a
commit 60c608d
Showing
1 changed file
with
88 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
""" | ||
Implementation of finding nth fibonacci number using matrix exponentiation. | ||
Time Complexity is about O(log(n)*8), where 8 is the complexity of matrix multiplication of size 2 by 2. | ||
And on the other hand complexity of bruteforce solution is O(n). | ||
As we know | ||
f[n] = f[n-1] + f[n-1] | ||
Converting to matrix, | ||
[f(n),f(n-1)] = [[1,1],[1,0]] * [f(n-1),f(n-2)] | ||
-> [f(n),f(n-1)] = [[1,1],[1,0]]^2 * [f(n-2),f(n-3)] | ||
... | ||
... | ||
-> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)] | ||
So we just need the n times multiplication of the matrix [1,1],[1,0]]. | ||
We can decrease the n times multiplication by following the divide and conquer approach. | ||
""" | ||
from __future__ import print_function | ||
|
||
|
||
def multiply(matrix_a, matrix_b): | ||
matrix_c = [] | ||
n = len(matrix_a) | ||
for i in range(n): | ||
list_1 = [] | ||
for j in range(n): | ||
val = 0 | ||
for k in range(n): | ||
val = val + matrix_a[i][k] * matrix_b[k][j] | ||
list_1.append(val) | ||
matrix_c.append(list_1) | ||
return matrix_c | ||
|
||
|
||
def identity(n): | ||
return [[int(row == column) for column in range(n)] for row in range(n)] | ||
|
||
|
||
def nth_fibonacci_matrix(n): | ||
""" | ||
>>> nth_fibonacci_matrix(100) | ||
354224848179261915075 | ||
>>> nth_fibonacci_matrix(-100) | ||
-100 | ||
""" | ||
if n <= 1: | ||
return n | ||
res_matrix = identity(2) | ||
fibonacci_matrix = [[1, 1], [1, 0]] | ||
n = n - 1 | ||
while n > 0: | ||
if n % 2 == 1: | ||
res_matrix = multiply(res_matrix, fibonacci_matrix) | ||
fibonacci_matrix = multiply(fibonacci_matrix, fibonacci_matrix) | ||
n = int(n / 2) | ||
return res_matrix[0][0] | ||
|
||
|
||
def nth_fibonacci_bruteforce(n): | ||
""" | ||
>>> nth_fibonacci_bruteforce(100) | ||
354224848179261915075 | ||
>>> nth_fibonacci_bruteforce(-100) | ||
-100 | ||
""" | ||
if n <= 1: | ||
return n | ||
fib0 = 0 | ||
fib1 = 1 | ||
for i in range(2, n + 1): | ||
fib0, fib1 = fib1, fib0 + fib1 | ||
return fib1 | ||
|
||
|
||
def main(): | ||
fmt = "{} fibonacci number using matrix exponentiation is {} and using bruteforce is {}\n" | ||
for ordinal in "0th 1st 2nd 3rd 10th 100th 1000th".split(): | ||
n = int("".join(c for c in ordinal if c in "0123456789")) # 1000th --> 1000 | ||
print(fmt.format(ordinal, nth_fibonacci(n), nth_fibonacci_test(n))) | ||
# from timeit import timeit | ||
# print(timeit("nth_fibonacci_matrix(1000000)", | ||
# "from main import nth_fibonacci_matrix", number=5)) | ||
# print(timeit("nth_fibonacci_bruteforce(1000000)", | ||
# "from main import nth_fibonacci_bruteforce", number=5)) | ||
# 2.3342058970001744 | ||
# 57.256506615000035 | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |