Skip to content

Commit 3222181

Browse files
mahbubcsejustokhos
authored andcommitted
Added matrix exponentiation approach for finding fibonacci number. (TheAlgorithms#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
1 parent d1d32e9 commit 3222181

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""
2+
Implementation of finding nth fibonacci number using matrix exponentiation.
3+
Time Complexity is about O(log(n)*8), where 8 is the complexity of matrix multiplication of size 2 by 2.
4+
And on the other hand complexity of bruteforce solution is O(n).
5+
As we know
6+
f[n] = f[n-1] + f[n-1]
7+
Converting to matrix,
8+
[f(n),f(n-1)] = [[1,1],[1,0]] * [f(n-1),f(n-2)]
9+
-> [f(n),f(n-1)] = [[1,1],[1,0]]^2 * [f(n-2),f(n-3)]
10+
...
11+
...
12+
-> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)]
13+
So we just need the n times multiplication of the matrix [1,1],[1,0]].
14+
We can decrease the n times multiplication by following the divide and conquer approach.
15+
"""
16+
from __future__ import print_function
17+
18+
19+
def multiply(matrix_a, matrix_b):
20+
matrix_c = []
21+
n = len(matrix_a)
22+
for i in range(n):
23+
list_1 = []
24+
for j in range(n):
25+
val = 0
26+
for k in range(n):
27+
val = val + matrix_a[i][k] * matrix_b[k][j]
28+
list_1.append(val)
29+
matrix_c.append(list_1)
30+
return matrix_c
31+
32+
33+
def identity(n):
34+
return [[int(row == column) for column in range(n)] for row in range(n)]
35+
36+
37+
def nth_fibonacci_matrix(n):
38+
"""
39+
>>> nth_fibonacci_matrix(100)
40+
354224848179261915075
41+
>>> nth_fibonacci_matrix(-100)
42+
-100
43+
"""
44+
if n <= 1:
45+
return n
46+
res_matrix = identity(2)
47+
fibonacci_matrix = [[1, 1], [1, 0]]
48+
n = n - 1
49+
while n > 0:
50+
if n % 2 == 1:
51+
res_matrix = multiply(res_matrix, fibonacci_matrix)
52+
fibonacci_matrix = multiply(fibonacci_matrix, fibonacci_matrix)
53+
n = int(n / 2)
54+
return res_matrix[0][0]
55+
56+
57+
def nth_fibonacci_bruteforce(n):
58+
"""
59+
>>> nth_fibonacci_bruteforce(100)
60+
354224848179261915075
61+
>>> nth_fibonacci_bruteforce(-100)
62+
-100
63+
"""
64+
if n <= 1:
65+
return n
66+
fib0 = 0
67+
fib1 = 1
68+
for i in range(2, n + 1):
69+
fib0, fib1 = fib1, fib0 + fib1
70+
return fib1
71+
72+
73+
def main():
74+
fmt = "{} fibonacci number using matrix exponentiation is {} and using bruteforce is {}\n"
75+
for ordinal in "0th 1st 2nd 3rd 10th 100th 1000th".split():
76+
n = int("".join(c for c in ordinal if c in "0123456789")) # 1000th --> 1000
77+
print(fmt.format(ordinal, nth_fibonacci(n), nth_fibonacci_test(n)))
78+
# from timeit import timeit
79+
# print(timeit("nth_fibonacci_matrix(1000000)",
80+
# "from main import nth_fibonacci_matrix", number=5))
81+
# print(timeit("nth_fibonacci_bruteforce(1000000)",
82+
# "from main import nth_fibonacci_bruteforce", number=5))
83+
# 2.3342058970001744
84+
# 57.256506615000035
85+
86+
87+
if __name__ == "__main__":
88+
main()

0 commit comments

Comments
 (0)