Эффективный алгоритм для вычисления

11

- го числа Фибоначчи может быть вычислен в линейное время с использованием следующего повторения:n

def fib(n):
    i, j = 1, 1
    for k in {1...n-1}:
        i, j = j, i+j
    return i

- го числа Фибоначчи также может быть вычислена как [ ф п / n. Тем не менее, это имеет проблемы с проблемами округления даже для относительно небольшихn. Наверное, естьспособы обойти это,но я бы не стал этого делать.[φn/5]n

Существует ли эффективный (логарифмический по значению или лучше) алгоритм для вычисления n- го числа Фибоначчи, которое не зависит от арифметики с плавающей запятой? Предположим, что целочисленные операции ( + , - , × , / ) могут выполняться за постоянное время.nn+×/

augurar
источник
5
В качестве предложения, статья в Википедии о числах Фибоначчи имеет много методов.
псевдоним
ср stackoverflow.com/questions/14661633/… и ссылки в нем и вокруг.
Уилл Несс

Ответы:

14

Вы можете использовать матричное питание и тождество В вашей модели вычислений это алгоритм O ( log n ) , если вы используете многократное возведение в квадрат для реализации питания.

[1110]n=[Fn+1FnFnFn1].
O(logn)
Юваль Фильмус
источник
1
Это классика.
dfeuer
8
F2n1=Fn2+Fn12F2n=Fn2+2Fn1Fn
4

Вы можете прочитать эту математическую статью: Быстрый алгоритм для вычисления больших чисел Фибоначчи (Daisuke Takahashi): PDF .

Проще говоря, я реализовал несколько алгоритмов Фибоначчи на C ++ (без и с GMP) и Python. Полные источники на Bitbucket. На главной странице вы также можете перейти по ссылкам на:

  • C ++ HTML онлайн документация.
  • Небольшой математический документ: числа Фибоначчи - несколько отношений для реализации хороших алгоритмов

Наиболее полезные формулы:

  • F2n=Fn+12Fn12=2FnFn1+Fn2
  • F2n+1=Fn+12+Fn2

Будьте осторожны с алгоритмом. Вы не должны вычислять одно и то же значение несколько раз. Простой рекурсивный алгоритм (в Python):

def fibonacci_pair(n):
    """Return (F_{n-1}, F_n)"""
    if n != 0:
        f_k_1, f_k = fibonacci_pair(n//2)  # F_{k-1},F_k with k = n/2

        return ((f_k**2 + f_k_1**2,
                 ((f_k*f_k_1)*2) + f_k**2) if n & 1 == 0  # even
                else (((f_k*f_k_1)*2) + f_k**2,
                      (f_k + f_k_1)**2 + f_k**2))
    else:
        return (1, 0)

O(logn)

Оливье Пирсон
источник
2
Добро пожаловать в информатику . Пожалуйста, не могли бы вы добавить больше информации к вашему ответу? На данный момент это всего лишь две ссылки, поэтому ваш ответ станет бессмысленным, если эти ссылки умрут или серверы, на которых они работают, недоступны. Ссылки на дополнительную информацию в порядке, но ссылки здесь являются единственной информацией. Также обратите внимание, что вопрос совершенно точно касается алгоритмов, а не реализаций C ++. Реализации имеют тенденцию затемнять алгоритмы, лежащие в основе специфичных для языка деталей.
Дэвид Ричерби
Дэвид, первая ссылка - это ссылка на математическую статью. Заголовок Быстрый алгоритм [...] отвечает на вопрос "Существует ли эффективный (логарифмический по значению n или лучше) алгоритм [...]?" Вторая ссылка - это ссылка на мои различные реализации на C ++ и Python, а также небольшой математический документ с несколькими формулами.
Оливье Пирсон
2
Нет, заголовок статьи, в котором содержится ваш ответ, ничего не отвечает. Текст статьи, который ваш ответ не содержит почти никаких, кажется , что это , вероятно , делает ответ на вопрос. Но Stack Exchange - это сайт вопросов и ответов, а не ферма ссылок. (И нет, я не предлагаю вам скопировать и вставить статью в свой ответ. Но необходимо краткое изложение.)
Дэвид Ричерби,
Если вы хотите резюме, напишите это!
Оливье Пирсон
0

O(log2n)

Проверьте бесплатную книгу Matters Computational и pari / gp code.

Joro
источник
5
Лучше обобщать идеи, чем просто размещать ссылки.
Авгурар