Algoritmo efficiente per calcolare il


11

Il -esimo numero di Fibonacci può essere calcolata in tempo lineare utilizzando la seguente ricorrenza:n

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

Il -esimo numero di Fibonacci può anche essere calcolata come [ φ n / n. Tuttavia, questo ha problemi con arrotondamento problemi anche per relativamente piccolon. Probabilmente ci sonomodi per aggirare questo,ma preferirei non farlo.[φn/5]n

Esiste un efficiente (logaritmica del valore di o migliore) algoritmo per calcolare il n -esimo numero di Fibonacci che non si basa su aritmetica in virgola mobile? Supponiamo che le operazioni di numero intero ( + , - , × , / ) possano essere eseguite in tempo costante.nn+×/


5
Come suggerimento, l'articolo di Wikipedia sui numeri di Fibonacci ha molti metodi.
Pseudonimo del

cf. stackoverflow.com/questions/14661633/… e collegamenti all'interno e all'esterno.
Will Ness,

Risposte:


14

È possibile utilizzare la potenza della matrice e l'identità Nel tuo modello di calcolo questo è un algoritmo O ( log n ) se usi la quadratura ripetuta per implementare il potere.

[1110]n=[Fn+1FnFnFn1].
O(logn)

1
È un classico.
Dfeuer,

8
È inoltre possibile utilizzare questa identità per derivare le ricorrenze e F 2 n = F 2 n + 2 F n - 1 F n . F2n1=Fn2+Fn12F2n=Fn2+2Fn1Fn
agosto

4

Puoi leggere questo articolo matematico: un veloce algoritmo per calcolare grandi numeri di Fibonacci (Daisuke Takahashi): PDF .

Più semplice, ho implementato diversi algoritmi di Fibonacci in C ++ (senza e con GMP) e Python. Fonti complete su Bitbucket. Dalla pagina principale è inoltre possibile seguire i collegamenti a:

  • La documentazione online HTML C ++.
  • Un piccolo documento matematico: numeri di Fibonacci - diverse relazioni per implementare buoni algoritmi

Le formule più utili sono:

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

Fai attenzione all'algoritmo. Non è necessario calcolare più volte lo stesso valore. Un semplice algoritmo ricorsivo (in 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
Benvenuti in Informatica . Potresti aggiungere ulteriori informazioni alla tua risposta? Al momento, non sono altro che due collegamenti, quindi la tua risposta diventerà insignificante se quei collegamenti muoiono o i server su cui si trovano non sono disponibili. I collegamenti a ulteriori informazioni vanno bene, ma i collegamenti qui sono le uniche informazioni. Inoltre, tieni presente che la domanda è decisamente sugli algoritmi, non sulle implementazioni C ++. Le implementazioni tendono a oscurare gli algoritmi dietro i dettagli specifici del linguaggio.
David Richerby,

David, il primo collegamento è un collegamento a un articolo matematico. Il titolo Un algoritmo veloce [...] risponde alla domanda "Esiste un algoritmo efficiente (logaritmico nel valore n o migliore) [...]?" Il secondo link è un link alle mie varie implementazioni, in C ++ e Python, e un piccolo documento matematico con diverse formule.
Olivier Pirson,

2
No, il titolo dell'articolo, che è quello che contiene la tua risposta, non risponde a nulla. Il testo dell'articolo, di cui la tua risposta non contiene quasi nessuno, sembra che probabilmente risponda alla domanda. Ma Stack Exchange è un sito di domande e risposte, non una farm di link. (E, no, non sto suggerendo di copiare e incollare l'articolo nella tua risposta. Ma è necessario un riepilogo.)
David Richerby,

Se vuoi un riepilogo, scrivilo!
Olivier Pirson,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.