Вот одна строка, которая вычисляет F (n), используя целые числа размера O (n), в O (log n) арифметических операциях:
for i in range(1, 50):
print(i, pow(2<<i, i, (4<<2*i)-(2<<i)-1)//(2<<i))
Разумно использовать целые числа размера O (n), поскольку это сопоставимо с размером ответа.
Чтобы понять это, пусть phi - золотое сечение (наибольшее решение для x ^ 2 = x + 1), а F (n) - n-ое число Фибоначчи, где F (0) = 0, F (1 ) = Р (2) = 1
Теперь phi ^ n = F (n-1) + F (n) phi.
Доказательство по индукции: phi ^ 1 = 0 + 1 * phi = F (0) + F (1) phi. И если фи ^ п =
F (n-1) + F (n) фи, затем фи ^ (n + 1) = F (n-1) фи + F (n) фи ^ 2 = F (n-1) фи +
F (n) (phi + 1) = F (n) + (F (n) + F (n-1)) phi = F (n) + F (n + 1) phi. Единственный сложный шаг в этом расчете - это тот, который заменяет фи ^ 2 на (1 + фи), что следует из-за того, что фи - это золотое сечение.
Также числа вида (a + b * phi), где a, b целые числа, замкнуты при умножении.
Доказательство: (p0 + p1 * phi) (q0 + q1 * phi) = p0q0 + (p0q1 + q1p0) phi + p1q1 * phi ^ 2 =
p0q0 + (p0q1 + q1p0) phi + p1q1 * (phi + 1) = (p0q0 + p1q1) +
(P0q1 + q1p0 + p1q1) * фита.
Используя это представление, можно вычислить phi ^ n в O (log n) целочисленных операциях, используя возведение в степень путем возведения в квадрат. Результатом будет F (n-1) + F (n) phi, из которого можно прочитать n-е число Фибоначчи.
def mul(p, q):
return p[0]*q[0]+p[1]*q[1], p[0]*q[1]+p[1]*q[0]+p[1]*q[1]
def pow(p, n):
r=1,0
while n:
if n&1: r=mul(r, p)
p=mul(p, p)
n=n>>1
return r
for i in range(1, 50):
print(i, pow((0, 1), i)[1])
Обратите внимание, что большая часть этого кода представляет собой стандартную функцию возведения в квадрат в квадрате.
Чтобы добраться до строки, начинающей этот ответ, можно заметить, что, представляя phi достаточно большим целым числом X
, можно выполнить (a+b*phi)(c+d*phi)
как целочисленную операцию (a+bX)(c+dX) modulo (X^2-X-1)
. Затем функцию pow
можно заменить стандартной функцией Python pow
(которая обычно включает в себя третий аргумент z
, который вычисляет результат по модулю z
. Выбранный X
равен 2<<i
.