Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import time, random
- class MatrixFibonacci:
- A = [[1, 1],
- [1, 0]]
- def __init__(self):
- self.__memo = {}
- # умножение матриц
- # ожидаются матрицы в виде списка список размером 2x2
- def __multiply_matrices(self, M1, M2):
- a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
- a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
- a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
- a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
- r = [[a11, a12], [a21, a22]]
- return r
- # возведение матрицы в степень
- # ожидается p равная степени двойки
- def __get_matrix_power(self, M, p):
- if p == 1:
- return M
- if p in self.__memo:
- return self.__memo[p]
- K = self.__get_matrix_power(M, int(p/2))
- R = self.__multiply_matrices(K, K)
- self.__memo[p] = R
- return R
- # получение n-го числа Фибоначчи
- # в качестве n ожидается неотрицательное целое число
- def get_number(self, n):
- if n == 0:
- return 0
- if n == 1:
- return 1
- # разложение переданной степени на степени, равные степени двойки
- # т.е. 62 = 2^5 + 2^4 + 2^3 + 2^2 + 2^0 = 32 + 16 + 8 + 4 + 1
- powers = [ int(pow(2, b)) for (b, d) in enumerate(reversed(bin(n-1)[2:])) if d == '1' ]
- # тоже самое, но менее pythonic: http://pastebin.com/h8cKDkHX
- matrices = [ self.__get_matrix_power(MatrixFibonacci.A, p) for p in powers ]
- while len(matrices) > 1:
- M1 = matrices.pop()
- M2 = matrices.pop()
- R = self.__multiply_matrices(M1, M2)
- matrices.append(R)
- return matrices[0][0][0]
- class IterationFibonacci:
- def __init__(self):
- pass
- # получение n-го числа Фибоначчи
- # в качестве n ожидается неотрицательное целое число
- def get_number(self, n):
- if n == 0:
- return 0
- a = 0
- b = 1
- c = 1
- for i in range(n-1):
- c = a + b
- a = b
- b = c
- return c
- def benchmark():
- random.seed()
- for around in range(10, 1010, 10):
- ifib = IterationFibonacci()
- mfib = MatrixFibonacci()
- ti = 0
- tm = 0
- count = 10000
- for _ in range(count):
- n = random.randint(around-5, around+5)
- t = time.time()
- ifib.get_number(n)
- t1 = time.time() - t
- ti += t1
- t = time.time()
- mfib.get_number(n)
- t2 = time.time() - t
- tm += t2
- print("{0}\t{1}\t{2}".format(around, ti, tm))
- benchmark()
Advertisement
Add Comment
Please, Sign In to add comment