Перед прочтением статьи, решил попробовать придумать свой алгоритм c асимптотикой O(log N). Времени понадобилось не очень много. Ниже описание идеи и пример на С++.
Достаточно просто получить вот такую формулу:
, где 
Формула доказывается легко по индукции. При m = 0 формула верна:

Предположим, что формула верна при m = p

Докажем, что формула верна при m = p + 1:

— получили такое же выражение, как и для случая m = p, т.е. при m = p + 1 формула остается верной
Легко получить
через те же числа:
\cdot F_{n-m} + F_{m+1}\cdot F_{n-m-1})
При нечетном N, m можно подобрать так, чтобы выполнялись равенства
и
. Это число равно 
После упрощения получаем такие формулы:



Используя последние формулы можно получить простой рекурсивный алгоритм.
От рекурсии уйти достаточно просто:
UPD Добавил оценку асимптотики с учетом «длинной» арифметики
Достаточно просто получить вот такую формулу:
, где 
Формула доказывается легко по индукции. При m = 0 формула верна:

Предположим, что формула верна при m = p

Докажем, что формула верна при m = p + 1:

— получили такое же выражение, как и для случая m = p, т.е. при m = p + 1 формула остается верной
Легко получить
через те же числа:\cdot F_{n-m} + F_{m+1}\cdot F_{n-m-1})
При нечетном N, m можно подобрать так, чтобы выполнялись равенства
и
. Это число равно 
После упрощения получаем такие формулы:



Используя последние формулы можно получить простой рекурсивный алгоритм.
#include <iostream> using namespace std; void fibonachi_recursive(int n, int& fn, int& fn1) { int gn, gn1; if (n < 2) { fn = n; fn1 = 1; return; } fibonachi_recursive(n / 2, gn, gn1); if (n % 2) { fn = gn1 * gn1 + gn * gn; fn1 = gn1 * gn1 + 2 * gn * gn1; } else { fn = 2 * gn * gn1 - gn * gn; fn1 = gn1 * gn1 + gn * gn; } } int fibonachi(int n) { int fn, fn1; fibonachi_recursive(n, fn, fn1); return fn; } int main() { for (int i = 0; i < 20; i++) cout << fibonachi(i) << " "; return 0; }
От рекурсии уйти достаточно просто:
#include <iostream> using namespace std; unsigned fibonachi(unsigned n) { if (n < 2) return n; unsigned mask = 1, m = n; while (m > 1) { m >>= 1; mask <<= 1; } unsigned fn = 1, fn1 = 1, gn, gn1; while (mask > 1) { mask >>= 1; gn = fn; gn1 = fn1; if (n & mask) { fn = gn1 * gn1 + gn * gn; fn1 = gn1 * gn1 + 2 * gn * gn1; } else { fn = 2 * gn * gn1 - gn * gn; fn1 = gn1 * gn1 + gn * gn; } } return fn; } int main() { for (int i = 0; i < 20; i++) cout << fibonachi(i) << " "; return 0; }
UPD Добавил оценку асимптотики с учетом «длинной» арифметики