Algoritmo eficiente para calcular el

11

El ésimo número de Fibonacci se puede calcular en tiempo lineal utilizando la siguiente recurrencia:n

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

El ésimo número de Fibonacci también puede calcularse como [ φ n / n. Sin embargo, esto tiene problemas con problemas de redondeo incluso paranrelativamente pequeño. Probablemente hayformas de evitar esto,pero prefiero no hacerlo.[φn/5]n

¿Hay una manera eficiente (en el valor logarítmico o mejor) algoritmo para calcular el n ésimo número de Fibonacci que no se basa en la aritmética de punto flotante? Suponga que las operaciones de enteros ( + , - , × , / ) se pueden realizar en tiempo constante.nn+×/

augurar
fuente
55
Como sugerencia, el artículo de Wikipedia sobre los números de Fibonacci tiene muchos métodos.
Seudónimo
cf. stackoverflow.com/questions/14661633/… y enlaces allí y alrededor.
Will Ness

Respuestas:

14

Puede usar la alimentación de matriz y la identidad En su modelo de cómputo, este es un algoritmo O ( log n ) si usa un cuadrado repetido para implementar el encendido.

[1110]n=[Fn+1FnFnFn1].
O(logn)
Yuval Filmus
fuente
1
Es un clasico.
dfeuer
8
También puede usar esta identidad para derivar las recurrencias y F 2 n = F 2 n + 2 F n - 1 F n . F2n1=Fn2+Fn12F2n=Fn2+2Fn1Fn
augurar el
4

Puede leer este artículo matemático: Un algoritmo rápido para calcular grandes números de Fibonacci (Daisuke Takahashi): PDF .

Más simple, implementé varios algoritmos de Fibonacci en C ++ (sin y con GMP) y Python. Fuentes completas en Bitbucket. Desde la página principal también puede seguir enlaces a:

  • La documentación en línea C ++ HTML.
  • Un pequeño documento matemático: números de Fibonacci: varias relaciones para implementar buenos algoritmos

Las fórmulas más útiles son:

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

Ten cuidado con el algoritmo. No debe calcular el mismo valor varias veces. Un algoritmo recursivo simple (en 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)

Olivier Pirson
fuente
2
Bienvenido a la informática . ¿Podría agregar más información a su respuesta? Por el momento, no son más que dos enlaces, por lo que su respuesta no tendrá sentido si esos enlaces mueren o los servidores en los que están no están disponibles. Los enlaces a más información están bien, pero los enlaces aquí son la única información. Además, tenga en cuenta que la pregunta es definitivamente sobre algoritmos, no sobre implementaciones de C ++. Las implementaciones tienden a ocultar los algoritmos detrás de los detalles específicos del idioma.
David Richerby
David, el primer enlace es un enlace a un artículo matemático. El título Un algoritmo rápido [...] responde a la pregunta "¿Existe un algoritmo eficiente (logarítmico en el valor n o mejor) [...]?" El segundo enlace es un enlace a mis diversas implementaciones, en C ++ y Python, y un pequeño documento matemático con varias fórmulas.
Olivier Pirson
2
No, el título del artículo, que es lo que contiene su respuesta, no responde nada. El texto del artículo, que su respuesta no contiene casi nada, parece que probablemente responda la pregunta. Pero Stack Exchange es un sitio de preguntas y respuestas, no una granja de enlaces. (Y no, no estoy sugiriendo que copie y pegue el artículo en su respuesta. Pero se necesita un resumen)
David Richerby,
Si quieres un resumen, ¡escríbelo!
Olivier Pirson
0

O(log2n)

Consulte el libro gratuito Matters Computational y el código pari / gp.

joro
fuente
55
Es mejor resumir las ideas en lugar de solo publicar enlaces.
augurar el