Чи існує якийсь алгоритм для обчислення n-го числа Фібоначчі за підлінійний час?
Чи існує якийсь алгоритм для обчислення n-го числа Фібоначчі за підлінійний час?
Відповіді:
Число n
Фібоначчі задано формулою
f(n) = Floor(phi^n / sqrt(5) + 1/2)
де
phi = (1 + sqrt(5)) / 2
Припускаючи , що примітивні математичні операції ( +
, -
, *
і /
) є O(1)
ви можете використовувати цей результат для обчислення n
го числа Фібоначчі в O(log n)
час ( O(log n)
через потенціювання у формулі).
У C #:
static double inverseSqrt5 = 1 / Math.Sqrt(5);
static double phi = (1 + Math.Sqrt(5)) / 2;
/* should use
const double inverseSqrt5 = 0.44721359549995793928183473374626
const double phi = 1.6180339887498948482045868343656
*/
static int Fibonacci(int n) {
return (int)Math.Floor(Math.Pow(phi, n) * inverseSqrt5 + 0.5);
}
phi^n / sqrt(5) + 1/2
where phi = (1 + sqrt(5)) / 2
. Це факт. По-друге, я розумію думку, яку роблять інші щодо довжини відповіді, O(n)
але я додав зауваження до своєї відповіді, припускаючи, що примітивні математичні операції займають постійний час (я знаю, що це не так, якщо ви не обмежите вхідні дані). Моя думка полягає в тому, що ми можемо знайти n-те число Фібоначчі в O(log n)
арифметичних операціях.
Випливаючи з посилання Пілсі на піднесення степенів до матриці, такого як для матриці
М = [1 1] [1 0]
тоді
fib ( n ) = M n 1,2
Підвищення матриць до степенів за допомогою багаторазового множення не дуже ефективно.
Два підходи до степенування матриці - це розділити і завоювати, що дає M n на етапах O ( ln n ), або розкладання власних значень, яке є постійним часом, але може спричинити помилки через обмежену точність з плаваючою точкою.
Якщо ви хочете, щоб точне значення було більшим за точність вашої реалізації з плаваючою комою, вам доведеться використовувати підхід O (ln n), заснований на цьому відношенні:
M n = ( M n / 2 ) 2, якщо n парне = M · M n -1, якщо n непарне
Власне розкладання на M знаходить дві матриці U та Л такий , що Λ є діагональним і
M = U Λ U -1 M n = ( U Λ U -1 ) n = U Λ U -1 U Λ U -1 U Λ U -1 ... n разів = U Λ Λ Λ ... U -1 = U Λ n U -1Підняти діагональну матрицю Λ до n- ї ступеня - це просте питання підняття кожного елемента в Λ до n- ої, отже, це дає O (1) метод підняття M до n- ї ступеня. Однак значення в Λ , швидше за все, не будуть цілими числами, тому трапиться певна помилка.
Визначення Λ для нашої матриці 2x2 як
Λ = [λ 1 0] = [0 λ 2 ]
Щоб знайти кожен λ , вирішуємо
| M - λ I | = 0
який дає
| M - λ I | = -λ (1 - λ) - 1 λ² - λ - 1 = 0
за допомогою квадратної формули
λ = (-b ± √ (b² - 4ac)) / 2a = (1 ± √5) / 2 {λ 1 , λ 2 } = {Φ, 1-Φ} де Φ = (1 + √5) / 2
Якщо ви прочитали відповідь Джейсона, ви можете зрозуміти, куди це піде.
Розв'язування власних векторів X 1 і X 2 :
якщо X 1 = [ X 1,1 , X 1,2 ] M . X 1 1 = λ 1 X 1 X 1,1 + X 1,2 = λ 1 X 1,1 X 1,1 = λ 1 X 1,2 => X 1 = [Φ, 1] X 2 = [1-Φ, 1]
Ці вектори дають U :
U = [ X 1,1 , X 2,2 ] [ X 1,1 , X 2,2 ] = [Φ, 1-Φ] [1, 1]
Інвертування U за допомогою
A = [ab] [cd] => A -1 = (1 / | A |) [d -b] [-ca]
отже U -1 задано як
U -1 = (1 / (Φ - (1 - Φ)) [1 Φ-1] [-1 Φ] U -1 = (√5) -1 [1 Φ-1] [-1 Φ]
Перевірка осудності:
UΛU -1 = (√5) -1 [Φ 1-Φ]. [Φ 0]. [1 Φ-1] [1 1] [0 1-Φ] [-1 Φ] нехай Ψ = 1-Φ, інше власне значення оскільки Φ є коренем з λ²-λ-1 = 0 так -ΨΦ = Φ²-Φ = 1 і Ψ + Φ = 1 UΛU -1 = (√5) -1 [Φ Ψ]. [Φ 0]. [1 -Ψ] [1 1] [0 Ψ] [-1 Φ] = (√5) -1 [Φ Ψ]. [Φ -ΨΦ] [1 1] [-Ψ ΨΦ] = (√5) -1 [Φ Ψ]. [Φ 1] [1 1] [-Ψ -1] = (√5) -1 [Φ²-Ψ² Φ-Ψ] [Φ-Ψ 0] = [Φ + Ψ 1] [1 0] = [1 1] [1 0] = М
Отже, перевірка осудності зберігається.
Тепер у нас є все необхідне для обчислення M n 1,2 :
M n = U Λ n U -1 = (√5) -1 [Φ Ψ]. [Φ n 0]. [1 -Ψ] [1 1] [0 Ψ n ] [-1 Φ] = (√5) -1 [Φ Ψ]. [Φ n -ΨΦ n ] [1 1] [-Ψ n Ψ n Φ] = (√5) -1 [Φ Ψ]. [Φ n Φ n -1 ] [1 1] [-Ψ n -Ψ n -1 ] як ΨΦ = -1 = (√5) -1 [Φ n +1 -Ψ n +1 Φ n -Ψ n ] [Φ n -Ψ n Φ n -1 -Ψ n -1 ]
так
fib ( n ) = M n 1,2 = (Φ n - (1-Φ) n ) / √5
Що узгоджується з формулою, наведеною в іншому місці.
Ви можете отримати його із відношення рекуррентності, але в інженерних обчисленнях та моделюванні обчислення власних значень та власних векторів великих матриць є важливою діяльністю, оскільки воно забезпечує стабільність та гармоніку систем рівнянь, а також дозволяє ефективно піднімати матриці до високих ступенів.
Якщо вам потрібна точна цифра (яка є "bignum", а не int / float), то я боюся, що
Це неможливо!
Як зазначено вище, формула чисел Фібоначчі:
FIB п = підлогу (фі п / √5 + 1 / 2 )
fib n ~ = phi n / √5
Скільки цифр fib n
?
numDigits (fib n) = log (fib n) = log (phi n / √5) = log phi n - log √5 = n * log phi - log √5
numDigits (fib n) = n * const + const
це O ( n )
Оскільки запитуваний результат має значення O ( n ), його неможливо обчислити менш ніж за час O ( n ).
Якщо вам потрібні лише нижчі цифри відповіді, тоді можна обчислити за підлінійний час, використовуючи метод піднесення степенів до матриці.
O(n*log n)
для сортування на основі порівняння послідовності n
чисел, де кожне число має O(log n)
цифри?
Про це стосується одна з вправ у SICP , на яку є відповідь, описана тут.
В імперативному стилі програма виглядала б приблизно так
Функція Fib ( кол ) a ← 1 b ← 0 p ← 0 q ← 1 Тоді як count > 0 Do If Even ( count ) Тоді p ← p ² + q ² q ← 2 pq + q ² count ← count ÷ 2 Інакше a ← bq + aq + ap b ← bp + aq count ← count - 1 End If Кінець поки Повернення b Функція завершення
twisted
фреймворком).
if even(count)
правильний. Послідовність починається з нуля (нульове число Фібоначчі дорівнює нулю): 0,1,1,2,3,5,8,13, ...
Ви можете зробити це, також підставивши матрицю цілих чисел. Якщо у вас є матриця
/ 1 1 \
M = | |
\ 1 0 /
тоді (M^n)[1, 2]
буде дорівнює n
числом Фібоначчі, якщо []
є індексом матриці і ^
є піднесенням степеня матриці. Для матриці фіксованого розміру піднесення до позитивної інтегральної потужності може бути здійснено за час O (log n) так само, як і для дійсних чисел.
РЕДАГУВАТИ: Звичайно, залежно від типу відповіді, яку ви хочете, можливо, вам вдасться уникнути за допомогою алгоритму постійного часу. Як показують інші формули, число n
Фібоначчі зростає в геометричній прогресії n
. Навіть із 64-розрядними цілими числами без підпису вам знадобиться лише таблиця підстановки з 94 записами, щоб охопити весь діапазон.
ДРУГЕ РЕДАГУВАННЯ: Спершу виконати експоненцію матриці з власним розкладом - це рівнозначно розв’язанню JDunkerly нижче. Власні значення цієї матриці - це (1 + sqrt(5))/2
і (1 - sqrt(5))/2
.
У Вікіпедії є рішення із закритою формою http://en.wikipedia.org/wiki/Fibonacci_number
Або в c #:
public static int Fibonacci(int N)
{
double sqrt5 = Math.Sqrt(5);
double phi = (1 + sqrt5) / 2.0;
double fn = (Math.Pow(phi, N) - Math.Pow(1 - phi, N)) / sqrt5;
return (int)fn;
}
|1 - phi|^n / sqrt(5) < 1/2
коли n
є цілим невід’ємним числом.
Для справді великих ця рекурсивна функція працює. Він використовує такі рівняння:
F(2n-1) = F(n-1)^2 + F(n)^2
F(2n) = (2*F(n-1) + F(n)) * F(n)
Вам потрібна бібліотека, яка дозволяє працювати з великими цілими числами. Я використовую бібліотеку BigInteger з https://mattmccutchen.net/bigint/ .
Почніть з масиву чисел Фібоначчі. Використовувати fibs [0] = 0, fibs [1] = 1, fibs [2] = 1, fibs [3] = 2, fibs [4] = 3 тощо. У цьому прикладі я використовую масив перших 501 (рахуючи 0). Перші 500 ненульових чисел Фібоначчі ви можете знайти тут: http://home.hiwaay.net/~jalison/Fib500.html . Потрібно трохи редагувати, щоб перевести його у потрібний формат, але це не надто складно.
Тоді ви можете знайти будь-яке число Фібоначчі, використовуючи цю функцію (в С):
BigUnsigned GetFib(int numfib)
{
int n;
BigUnsigned x, y, fib;
if (numfib < 501) // Just get the Fibonacci number from the fibs array
{
fib=(stringToBigUnsigned(fibs[numfib]));
}
else if (numfib%2) // numfib is odd
{
n=(numfib+1)/2;
x=GetFib(n-1);
y=GetFib(n);
fib=((x*x)+(y*y));
}
else // numfib is even
{
n=numfib/2;
x=GetFib(n-1);
y=GetFib(n);
fib=(((big2*x)+y)*y);
}
return(fib);
}
Я перевірив це для 25 000-го числа Фібоначчі тощо.
Ось моя рекурсивна версія, яка повторює журнал (n) разів. Я думаю, що це найпростіше читати в рекурсивній формі:
def my_fib(x):
if x < 2:
return x
else:
return my_fib_helper(x)[0]
def my_fib_helper(x):
if x == 1:
return (1, 0)
if x % 2 == 1:
(p,q) = my_fib_helper(x-1)
return (p+q,p)
else:
(p,q) = my_fib_helper(x/2)
return (p*p+2*p*q,p*p+q*q)
Це працює, тому що ви можете обчислювати fib(n),fib(n-1)
за допомогою, fib(n-1),fib(n-2)
якщо n непарна, а якщо n парне, ви можете обчислювати fib(n),fib(n-1)
за допомогою fib(n/2),fib(n/2-1)
.
Базовий і непарний випадки прості. Щоб вивести парний випадок, починайте з a, b, c як послідовних значень Фібоначчі (наприклад, 8,5,3) і запишіть їх у матрицю з a = b + c. Примітка:
[1 1] * [a b] = [a+b a]
[1 0] [b c] [a b]
З цього ми бачимо, що матриця перших трьох чисел Фібоначчі, помножена на матрицю будь-яких трьох послідовних чисел Фібоначчі, дорівнює наступній. Отже, ми знаємо, що:
n
[1 1] = [fib(n+1) fib(n) ]
[1 0] [fib(n) fib(n-1)]
Так:
2n 2
[1 1] = [fib(n+1) fib(n) ]
[1 0] [fib(n) fib(n-1)]
Спрощення правої сторони веде до парного випадку.
за допомогою R
l1 <- (1+sqrt(5))/2
l2 <- (1-sqrt(5))/2
P <- matrix(c(0,1,1,0),nrow=2) #permutation matrix
S <- matrix(c(l1,1,l2,1),nrow=2)
L <- matrix(c(l1,0,0,l2),nrow=2)
C <- c(-1/(l2-l1),1/(l2-l1))
k<-20 ; (S %*% L^k %*% C)[2]
[1] 6765
Арифметика з фіксованою точкою неточна. Код С # Джейсона дає неправильну відповідь на n = 71 (308061521170130 замість 308061521170129) і далі.
Для правильної відповіді використовуйте обчислювальну систему алгебри. Sympy - це така бібліотека для Python. Інтерактивна консоль знаходиться за адресою http://live.sympy.org/ . Скопіюйте та вставте цю функцію
phi = (1 + sqrt(5)) / 2
def f(n):
return floor(phi**n / sqrt(5) + 1/2)
Тоді обчисліть
>>> f(10)
55
>>> f(71)
308061521170129
Ви можете спробувати перевірити phi
.
Окрім точної настройки за допомогою математичних підходів, одним з найкращих оптимальних рішень (я вважаю) є використання словника, щоб уникнути повторюваних обчислень.
import time
_dict = {1:1, 2:1}
def F(n, _dict):
if n in _dict.keys():
return _dict[n]
else:
result = F(n-1, _dict) + F(n-2, _dict)
_dict.update({n:result})
return result
start = time.time()
for n in range(1,100000):
result = F(n, _dict)
finish = time.time()
print(str(finish - start))
Ми починаємо з тривіального словника (перші два значення послідовності Фібоначчі) і постійно додаємо значення Фібоначчі до словника.
Перші 100000 значень Фібоначчі (процесор Intel Xeon E5-2680 @ 2,70 ГГц, 16 ГБ оперативної пам'яті, Windows 10-64 бітна ОС) зайняли близько 0,7 секунди
дивіться тут алгоритм поділу та завоювання
Посилання має псевдокод для піднесення степенів до матриці, згаданий у деяких інших відповідях на це питання.
Ви можете скористатися дивним рівнянням квадратного кореня, щоб отримати точну відповідь. Причина полягає в тому, що $ \ sqrt (5) $ випадає в кінці, вам просто потрібно відстежувати коефіцієнти за власним форматом множення.
def rootiply(a1,b1,a2,b2,c):
''' multipy a1+b1*sqrt(c) and a2+b2*sqrt(c)... return a,b'''
return a1*a2 + b1*b2*c, a1*b2 + a2*b1
def rootipower(a,b,c,n):
''' raise a + b * sqrt(c) to the nth power... returns the new a,b and c of the result in the same format'''
ar,br = 1,0
while n != 0:
if n%2:
ar,br = rootiply(ar,br,a,b,c)
a,b = rootiply(a,b,a,b,c)
n /= 2
return ar,br
def fib(k):
''' the kth fibonacci number'''
a1,b1 = rootipower(1,1,5,k)
a2,b2 = rootipower(1,-1,5,k)
a = a1-a2
b = b1-b2
a,b = rootiply(0,1,a,b,5)
# b should be 0!
assert b == 0
return a/2**k/5
if __name__ == "__main__":
assert rootipower(1,2,3,3) == (37,30) # 1+2sqrt(3) **3 => 13 + 4sqrt(3) => 39 + 30sqrt(3)
assert fib(10)==55
Ось однорядковий рядок, який обчислює 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) = F (2) = 1
Тепер phi ^ n = F (n-1) + F (n) phi.
Доведення за допомогою індукції: phi ^ 1 = 0 + 1 * phi = F (0) + F (1) phi. І якщо phi ^ n = F (n-1) + F (n) phi, то phi ^ (n + 1) = F (n-1) phi + F (n) phi ^ 2 = F (n-1) phi + F (n) (phi + 1) = F (n) + (F (n) + F (n-1)) phi = F (n) + F (n + 1) phi. Єдиним хитрим кроком у цьому розрахунку є той, який замінює phi ^ 2 на (1 + phi), що випливає, оскільки phi - це золотий перетин.
Також числа форми (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
функцію можна замінити на стандартну pow
функцію Python (яка зручно включає третій аргумент, z
який обчислює результат за модулем z
. X
Вибраним є 2<<i
.
Я натрапив на деякі методи розрахунку Фібоначчі з ефективною часовою складністю, ось деякі з них -
Метод 1 - Динамічне програмування Зараз тут підструктура є загальновідомою, отже я прямо перейду до рішення -
static int fib(int n)
{
int f[] = new int[n+2]; // 1 extra to handle case, n = 0
int i;
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
Версію, оптимізовану для простору, можна зробити наступним чином -
static int fib(int n)
{
int a = 0, b = 1, c;
if (n == 0)
return a;
for (int i = 2; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return b;
}
Спосіб 2- (Використання потужності матриці {{1,1}, {1,0}})
Це O (n), яке спирається на той факт, що якщо n разів помножити матрицю M = {{1,1}, {1,0}} на себе (іншими словами, обчислити потужність (M, n)), то ми отримуємо (n + 1) число Фібоначчі як елемент у рядку та стовпці (0, 0) в результуючій матриці. Це рішення мало б O (n) час.
Матричне подання дає наступний замкнутий вираз для чисел Фібоначчі: фібоначіматриця
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
/*multiplies 2 matrices F and M of size 2*2, and
puts the multiplication result back to F[][] */
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
/*function that calculates F[][] raise to the power n and puts the
result in F[][]*/
static void power(int F[][], int n)
{
int i;
int M[][] = new int[][]{{1,1},{1,0}};
// n - 1 times multiply the matrix to {{1,0},{0,1}}
for (i = 2; i <= n; i++)
multiply(F, M);
}
Це можна оптимізувати для роботи в O (Logn) часовій складності. Ми можемо зробити рекурсивне множення, щоб отримати потужність (M, n) у попередньому методі.
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
static void power(int F[][], int n)
{
if( n == 0 || n == 1)
return;
int M[][] = new int[][]{{1,1},{1,0}};
power(F, n/2);
multiply(F, F);
if (n%2 != 0)
multiply(F, M);
}
Метод 3 (O (log n) Time) Нижче наведено ще одну цікаву формулу рецидиву, яку можна використовувати для пошуку n-го числа Фібоначчі за O (log n) часу.
Якщо n рівне, тоді k = n / 2: F (n) = [2 * F (k-1) + F (k)] * F (k)
Якщо n непарна, то k = (n + 1) / 2 F (n) = F (k) * F (k) + F (k-1) * F (k-1) Як працює ця формула? Формулу можна отримати з наведеного вище матричного рівняння. фібонациматрикс
Беручи визначник з обох сторін, отримуємо (-1) n = Fn + 1Fn-1 - Fn2 Більше того, оскільки AnAm = An + m для будь-якої квадратної матриці A, можна отримати наступні тотожності (вони отримані з двох різних коефіцієнтів матричний продукт)
FmFn + Fm-1Fn-1 = Fm + n-1
Поставивши n = n + 1,
FmFn + 1 + Fm-1Fn = Fm + n
Поставивши m = n
F2n-1 = Fn2 + Fn-12
F2n = (Fn-1 + Fn + 1) Fn = (2Fn-1 + Fn) Fn (Джерело: Wiki)
Щоб довести формулу, яку потрібно довести, нам просто потрібно зробити наступне. Якщо n парне, ми можемо поставити k = n / 2 Якщо n непарне, ми можемо поставити k = (n + 1) / 2
public static int fib(int n)
{
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
// If fib(n) is already computed
if (f[n] != 0)
return f[n];
int k = (n & 1) == 1? (n + 1) / 2
: n / 2;
// Applyting above formula [See value
// n&1 is 1 if n is odd, else 0.
f[n] = (n & 1) == 1? (fib(k) * fib(k) +
fib(k - 1) * fib(k - 1))
: (2 * fib(k - 1) + fib(k))
* fib(k);
return f[n];
}
Метод 4 - Використання формули У цьому методі ми безпосередньо реалізуємо формулу для n-го члена ряду Фібоначчі. Час O (1) Простір O (1) Fn = {[(√5 + 1) / 2] ^ n} / √5
static int fib(int n) {
double phi = (1 + Math.sqrt(5)) / 2;
return (int) Math.round(Math.pow(phi, n)
/ Math.sqrt(5));
}
Посилання: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html
Спочатку слід зазначити, що числа Фібоначчі (F(n))
дуже швидко зростають n
і не можуть бути представлені в 64-бітах для n
розміру більше 93. Тож програма для їх обчислення для таких n
потреб використовує додаткові механізми для роботи з цими великими числами. Тепер, враховуючи лише підрахунок (великої кількості) операцій, алгоритм їх послідовного обчислення вимагатиме лінійної кількості операцій.
Ми можемо скористатися наведеною нижче інформацією про числа Фібоначчі:
F(2m) = 2*F(m)*F(m+1) − (F(m))^2
F(2m+1) = (F(m))^2 + (F(m+1))^2
(такий символ, як A ^ 2, позначає квадрат A).
Отже, якщо ми знаємо F(m)
і F(m+1)
, ми можемо безпосередньо обчислити F(2m)
і F(2m+1)
.
Розглянемо двійкове представлення n
. Зверніть увагу, що, починаючи з x = 1
, ми можемо зробити це x = n
шляхом ітеративного подвоєння та, можливо, додавання 1 до x
. Це можна зробити, перебираючи біти n
, і перевіряючи, чи воно дорівнює 0 або 1.
Ідея полягає в тому, що ми можемо підтримувати F(x)
синхронізацію з x
. У кожній такій ітерації, коли ми подвоюємо x
і, можливо, додаємо 1 x
, ми також можемо обчислити нове значення, F(x)
використовуючи попереднє значення F(x)
та F(x+1)
, з наведеними вище рівняннями.
Оскільки кількість ітерацій буде логарифмічним n
, загальна (велика кількість) операцій також є логарифмічною n
.
Для отримання додаткової інформації див. Розділ "Покращений алгоритм" цієї статті .