web-dev-qa-db-fra.com

Connaître le nième numéro de fibonacci pour le très grand 'n'

Je me demandais comment on peut trouver le nième terme de la séquence de fibonacci pour une très grande valeur de n disons, 1000000. En utilisant l'équation de récurrence primaire fib(n)=fib(n-1)+fib(n-2), il faut 2-3 minutes pour trouver le 50ème terme! 

Après avoir googlé, j'ai appris à connaître la formule de Binet, mais elle n'est pas appropriée pour les valeurs de n> 79, comme il est dit ici

Existe-t-il un algorithme pour le faire, tout comme pour la recherche de nombres premiers?

48
kunal18

Vous pouvez utiliser la méthode d’exponentiation matricielle (méthode de récurrence linéaire) . Vous trouverez des explications et une procédure détaillées dans this blog. Le temps d'exécution est O (journal n).

Je ne pense pas qu'il y ait une meilleure façon de faire cela.

47
Wayne Rooney

Vous pouvez gagner beaucoup de temps en utilisant memoization . Par exemple, comparez les deux versions suivantes (en JavaScript):

Version 1 : récursivité normale

var fib = function(n) {
  return n < 2 ? n : fib(n - 1) + fib(n - 2);
};

Version 2 : mémoisation

A. utiliser la librairie nderscore

var fib2 = _.memoize(function(n) {
  return n < 2 ? n : fib2(n - 1) + fib2(n - 2);
});

B. sans bibliothèque

var fib3 = (function(){
    var memo = {};
    return function(n) {
        if (memo[n]) {return memo[n];}
        return memo[n] = (n <= 2) ? 1 : fib3(n-2) + fib3(n-1);
    };
})();

La première version prend plus de 3 minutes pour n = 50 (sur Chrome), tandis que la seconde ne prend que moins de 5 ms! Vous pouvez vérifier cela dans le jsFiddle .

Ce n’est pas surprenant de savoir si la complexité temporelle de la version 1 est exponentielle (O (2N/2)), tandis que la version 2 est linéaire (O (N)).

Version 3 : multiplication de matrices

De plus, nous pouvons même réduire la complexité temporelle à O (log (N)) en calculant la multiplication de N matrices.

matrix

F n  désigne le n ème terme de la séquence de Fibonacci.

31
Hui Zheng

Utilisez les identités de récurrence http://en.wikipedia.org/wiki/Fibonacci_number#Other_identities pour trouver n- ème nombre dans log(n) étapes. Vous devrez utiliser des entiers de précision arbitraires pour cela. Vous pouvez également calculer la réponse précise modulo par un facteur en utilisant l’arithmétique modulaire à chaque étape.

recurrence formula 1

recurrence formula 2

recurrence formula 3

Remarquant que 3n+3 == 3(n+1), nous pouvons concevoir une fonction simple-récursive qui calcule deux nombres de Fibonacci séquentiels à chaque étape, divisant la n par 3 et choisissant la formule appropriée en fonction de la valeur restante. IOW calcule une paire @(3n+r,3n+r+1), r=0,1,2 à partir d'une paire @(n,n+1) en une étape. Il n'y a donc pas de double récursivité ni de mémorisation.

Un code Haskell est ici .

update:

F(2n-1) =   F(n-1)^2    + F(n)^2   ===   a' = a^2 + b^2 
F(2n)   = 2 F(n-1) F(n) + F(n)^2   ===   b' = 2ab + b^2 

semble conduire à un code plus rapide. Utiliser "Identités de séquence Lucas" pourrait être le plus rapide ( ceci est dû à l'utilisateur: primo =, qui cite cette implémentation ).

13
Will Ness

La plupart des gens vous ont déjà donné un lien expliquant la découverte du nombre de Nth Fibonacci, de la manière dont l'algorithme Power fonctionne de la même manière avec des modifications mineures.

Quoi qu'il en soit, ceci est ma solution O (log N).

package algFibonacci;

import Java.math.BigInteger;

public class algFibonacci {
    // author Orel Eraki
    // Fibonacci algorithm
    // O(log2 n)
    public static BigInteger Fibonacci(int n) {

        int num = Math.abs(n);
        if (num == 0) {
            return BigInteger.ZERO;
        }
        else if (num <= 2) {
            return BigInteger.ONE;
        }

        BigInteger[][] number = { { BigInteger.ONE, BigInteger.ONE }, { BigInteger.ONE, BigInteger.ZERO } };
        BigInteger[][] result = { { BigInteger.ONE, BigInteger.ONE }, { BigInteger.ONE, BigInteger.ZERO } };

        while (num > 0) {
            if (num%2 == 1) result = MultiplyMatrix(result, number);
            number = MultiplyMatrix(number, number);
            num/= 2;
        }

        return result[1][1].multiply(BigInteger.valueOf(((n < 0) ? -1:1)));
    }

    public static BigInteger[][] MultiplyMatrix(BigInteger[][] mat1, BigInteger[][] mat2) {
        return new BigInteger[][] {
            {
                mat1[0][0].multiply(mat2[0][0]).add(mat1[0][1].multiply(mat2[1][0])), 
                mat1[0][0].multiply(mat2[0][1]).add(mat1[0][1].multiply(mat2[1][1]))
            },
            {
                mat1[1][0].multiply(mat2[0][0]).add(mat1[1][1].multiply(mat2[1][0])), 
                mat1[1][0].multiply(mat2[0][1]).add(mat1[1][1].multiply(mat2[1][1]))
            }
        };
    }

    public static void main(String[] args) {
        System.out.println(Fibonacci(8181));
    }
}
4
Orel Eraki

Pour calculer les nombres de Fibonacci, l’algorithme récursif est l’un des pires moyens… .. Il suffit de simplement ajouter les deux nombres précédents dans un cycle for (méthode itérative) pour prendre le 50e élément.

2
Bartis Áron

Voici une version en python pour calculer le nième nombre de Fibonacci dans O (log (n))

def fib(n):
    if n == 0: 
        return 0

    if n == 1: 
        return 1

    def matmul(M1, M2):
        a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
        a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
        a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
        a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
        return [[a11, a12], [a21, a22]]

    def matPower(mat, p):
        if p == 1: 
            return mat

        m2 = matPower(mat, p//2)
        if p % 2 == 0:
            return matmul(m2, m2)
        else: 
            return matmul(matmul(m2, m2),mat)

    Q = [[1,1],[1,0]]

    q_final = matPower(Q, n-1)
    return q_final[0][0]
2

Pour calculer des éléments arbitrairement grands de la séquence de Fibonacci, vous devrez utiliser la solution de forme fermée - la formule de Binet, et utiliser des calculs mathématiques à précision arbitraire pour fournir une précision suffisante pour calculer la réponse.

Le simple fait d'utiliser la relation de récurrence, cependant, devrait pas nécessiter 2 à 3 minutes pour calculer le 50ème terme - vous devriez pouvoir calculer les termes en milliards en quelques secondes sur n'importe quelle machine moderne. On dirait que vous utilisez la formule entièrement récursive, ce qui conduit à une explosion combinatoire de calculs récursifs. La formule simple itérative est beaucoup plus rapide.

À savoir: la solution récursive est:

int fib(int n) {
  if (n < 2)
    return 1;
  return fib(n-1) + fib(n-2)
}

... et asseyez-vous et regardez la pile déborder.

La solution itérative est:

int fib(int n) {
  if (n < 2)
    return 1;
  int n_1 = 1, n_2 = 1;
  for (int i = 2; i <= n; i += 1) {
    int n_new = n_1 + n_2;
    n_1 = n_2;
    n_2 = n_new;
  }
  return n_2;
}

Remarquez comment nous calculons essentiellement le prochain terme n_new à partir des termes précédents n_1 et n_2, puis "mélangeons" tous les termes pour la prochaine itération. Avec un temps d'exécution linéaire sur la valeur de n, quelques __ secondes pour n en milliards (bien après le dépassement d'entier pour vos variables intermédiaires) sur une machine moderne à gigahertz.

1
sheu

J'ai écrit une implémentation C, qui supporte n'importe quelle échelle du nombre d'entrée avec GNU gmp.

Le temps nécessaire pour déterminer la fib pour un seul numéro est O(n), et l'espace pour le cache est O(1)_, (il a en fait représenté toutes les fibs pour 0 ~ n).


Code

fib_cached_gmp.c:

// fibonacci - cached algorithm - any scale of input with GMP,
#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>

// a single step,
void fib_gmp_next(mpz_t *cache) {
    mpz_add(cache[2], cache[0], cache[1]);
    mpz_set(cache[0], cache[1]);
    mpz_set(cache[1], cache[2]);
}

// figure fib for a single number, in O(n),
mpz_t *fib_gmp(int n, mpz_t *result) {
    // init cache,
    mpz_t cache[3]; // number: [fib(n-2), fib(n-1), fib(n)],

    mpz_init(cache[0]);
    mpz_init(cache[1]);
    mpz_init(cache[2]);

    mpz_set_si(cache[0], 0);
    mpz_set_si(cache[1], 1);

    while (n >= 2) {
        fib_gmp_next(cache);
        n--;
    }

    mpz_set(*result, cache[n]);

    return result;
}

// test - print fib from 0 to n, tip: cache won't be reused between any 2 input numbers,
void test_seq(int n) {
    mpz_t result;
    mpz_init(result);

    for (int i = 0; i <= n; i++) {
        gmp_printf("fib(%2d): %Zd\n", i, fib_gmp(i, &result));
    }
}

// test - print fib for a single num,
void test_single(int x) {
    mpz_t result;
    mpz_init(result);

    gmp_printf("fib(%d): %Zd\n", x, fib_gmp(x, &result));
}

int main() {
    // test sequence,
    test_seq(100);

    // test single,
    test_single(12345);

    return 0;
}

Installez gmp en premier:

// for Ubuntu,
Sudo apt-get install libgmp3-dev

Compiler:

gcc fib_cached_gmp.c -lgmp

Exécuter:

./a.out

Exemple de sortie:

fib( 0): 0
fib( 1): 1
fib( 2): 1
fib( 3): 2
fib( 4): 3
fib( 5): 5
fib( 6): 8
fib( 7): 13
fib( 8): 21
fib( 9): 34
fib(10): 55
fib(11): 89
fib(12): 144
fib(13): 233
fib(14): 377
fib(15): 610
fib(16): 987
fib(17): 1597
fib(18): 2584
fib(19): 4181
fib(20): 6765
fib(21): 10946
fib(22): 17711
fib(23): 28657
fib(24): 46368
fib(25): 75025
fib(26): 121393
fib(27): 196418
fib(28): 317811
fib(29): 514229
fib(30): 832040
fib(31): 1346269
fib(32): 2178309
fib(33): 3524578
fib(34): 5702887
fib(35): 9227465
fib(36): 14930352
fib(37): 24157817
fib(38): 39088169
fib(39): 63245986
fib(40): 102334155
fib(41): 165580141
fib(42): 267914296
fib(43): 433494437
fib(44): 701408733
fib(45): 1134903170
fib(46): 1836311903
fib(47): 2971215073
fib(48): 4807526976
fib(49): 7778742049
fib(50): 12586269025
fib(51): 20365011074
fib(52): 32951280099
fib(53): 53316291173
fib(54): 86267571272
fib(55): 139583862445
fib(56): 225851433717
fib(57): 365435296162
fib(58): 591286729879
fib(59): 956722026041
fib(60): 1548008755920
fib(61): 2504730781961
fib(62): 4052739537881
fib(63): 6557470319842
fib(64): 10610209857723
fib(65): 17167680177565
fib(66): 27777890035288
fib(67): 44945570212853
fib(68): 72723460248141
fib(69): 117669030460994
fib(70): 190392490709135
fib(71): 308061521170129
fib(72): 498454011879264
fib(73): 806515533049393
fib(74): 1304969544928657
fib(75): 2111485077978050
fib(76): 3416454622906707
fib(77): 5527939700884757
fib(78): 8944394323791464
fib(79): 14472334024676221
fib(80): 23416728348467685
fib(81): 37889062373143906
fib(82): 61305790721611591
fib(83): 99194853094755497
fib(84): 160500643816367088
fib(85): 259695496911122585
fib(86): 420196140727489673
fib(87): 679891637638612258
fib(88): 1100087778366101931
fib(89): 1779979416004714189
fib(90): 2880067194370816120
fib(91): 4660046610375530309
fib(92): 7540113804746346429
fib(93): 12200160415121876738
fib(94): 19740274219868223167
fib(95): 31940434634990099905
fib(96): 51680708854858323072
fib(97): 83621143489848422977
fib(98): 135301852344706746049
fib(99): 218922995834555169026
fib(100): 354224848179261915075
fib(12345): 400805695072240470970514993214065752192289440772063392234116121035966330621821050108284603033716632771086638046166577665205834362327397885009536790892524821512145173749742393351263429067658996935575930135482780507243981402150702461932551227590433713277255705297537428017957026536279252053237729028633507123483103210846617774763936154673522664591736081039709294423865668046925492747583953758325850613548914282578320544573036249175099094644435323970587790740267131607004023987409385716162460955707793257532112771932704816713519196128834470721836094265012918046427449156654067195071358955104097973710150920536847877434256779886729555691213282504703193401739340461924048504866698176130757935914248753973087073009601101912877383634628929467608983980664185363370286731771712542583041365328648124549323878806758395652340861186334027392307091079257180835672989798524084534677252369585918458720952520972332496025465803523315515681084895362126005441170936820059518262349022456888758938672920855739736423917065122816343192172271301981007636070751378441363091187289522144227851382197807194256392294919912037019476582418451273767976783751999133072126657949249799858935787018952232743400610036315564885371356712960608966755186612620425868892621106627825137425386831657368826398245606147944273998498356443362170133234924531673939303668042878258282104212769625245680321344034442698232414181912301904509531018692483863038992377680591406376081935756597411807864832452421993121459549055042253305545594009110753730302061881025182053074077930494574304284381890534053065639084253641881363463311184024281835265103884539012874542416238100890688593076189105555658375552988619203325356676814545718066196038345684671830102920209857682912971565838896011294918349088792184108318689299230788355618638040186790724351073650210514429114905535411044888774713860041341593318365792673354888566799196442017231870631867558530906286613228902689695061557951752309687806567573290910909535395758148994377158637050112347651517847188123790794231572729345617619677555583207012253101701328971768827861922408064379891201972881554890367344239218306050355964382953279316318309272212482218232309006973312977359562553184608144571713073802285675503209229581312057259729362382786183100343961484090866057560474044189870633912200595478051573769889968342203512550302655117491740823696686983281784153050366346823513213598551985596176977626982962058849363351794302206703907577970065793839511591930741441079234179943480206539767561244271325923343752071038968002157889912694947204003637791271084190929058369801531787887444598295425899927970

Conseils:

  • test_seq() n'est pas très intelligent, il n'a pas réutilisé le cache entre 2 numéros d'entrée.
    En réalité, un seul appel à fib_gmp() serait suffisant, si vous ajoutez un gmp_printf() à fib_gmp_next() et fournissez le i à fib_gmp_next() à chaque étape.
    Quoi qu'il en soit, c'est juste pour la démo.
1
Eric Wang

Tout d’abord, vous pouvez vous faire une idée du terme le plus élevé à partir de le plus grand terme de Fibonacci connu . voir aussi parcourir la présentation de la fonction de Fibonacci récursive . Une approche intéressée à ce sujet est dans cet article . Aussi, essayez de lire à ce sujet dans le pire algorithme au monde? .

1
user1929959

voici un code python court, fonctionne bien jusqu'à 7 chiffres. Nécessite juste un tableau de 3 éléments

def fibo(n):
    i=3
    l=[0,1,1]
    if n>2:
        while i<=n:
            l[i%3]= l[(i-1) % 3] + l[(i-2) % 3]
            i+=1
    return l[n%3]
0
Nitin Labhishetty
#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;

const long long int MAX = 10000000;

// Create an array for memoization
long long int f[MAX] = {0};

// Returns n'th fuibonacci number using table f[]
long long int fib(int n)
{
    // Base cases
    if (n == 0)
        return 0;
    if (n == 1 || n == 2)
        return (f[n] = 1);

    if (f[n])
        return f[n];

    long long int k = (n & 1)? (n+1)/2 : n/2;

    f[n] = (n & 1)? (fib(k)*fib(k) + fib(k-1)*fib(k-1)) %MOD
        : ((2*fib(k-1) + fib(k))*fib(k))%MOD;

    return f[n];
}

int main()
{
    long long int n = 1000000;
    printf("%lld ", fib(n));
    return 0;
}

Complexité temporelle: O (Log n) car nous divisons le problème en deux à chaque appel récursif.

0
Sourabh Goel

La plus simple implémentation Pythonic peut être donnée comme suit

def Fib(n):
    if (n < 0) : 
        return -1
    Elif (n == 0 ): 
        return 0
    else:
        a = 1
        b = 1
        for i in range(2,n+1):
            a,b = b, a+b
        return a
0
Alex Mercer

Solution plus élégante en python

def fib(n):
  if n == 0: 
    return 0
  a, b = 0, 1
  for i in range(2, n+1):
    a, b = b, a+b
  return b
0
farincz

J'ai résolu un problème d'UVA: 495 - Fibonacci Freeze

Il génère tous les nombres de Fibonacci jusqu’à 5000e et imprime des sorties pour des entrées données (plage 1 à 5000).

Il est accepté avec le temps d'exécution 00.00 sec.

Le nombre de Fibonacci pour 5000 est:

3878968454388325633701916308325905312082127714646245106160597214895550139044037097010822916462210669479293452858882973813483102008954982940361430156911478938364216563944106910214505634133706558656238254656700712525929903854933813928836378347518908762970712033337052923107693008518093849801803847813996748881765554653788291644268912980384613778969021502293082475666346224923071883324803280375039130352903304505842701147635242270210934637699104006714174883298422891491273104054328753298044273676822977244987749874555691907703880637046832794811358973739993110106219308149018570815397854379195305617510761053075688783766033667355445258844886241619210553457493675897849027988234351023599844663934853256411952221859563060475364645470760330902420806382584929156452876291575759142343809142302917491088984155209854432486594079793571316841692868039545309545388698114665082066862897420639323438488465240988742395873801976993820317174208932265468879364002630797780058759129671389634214252579116872755600360311370547754724604639987588046985178408674382863125

#include<stdio.h>
#include<string.h>

#define LIMIT 5001
#define MAX 1050
char num[LIMIT][MAX];
char result[MAX];
char temp[MAX];

char* sum(char str1[], char str2[])
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int minLen, maxLen;
    int i, j, k;

    if (len1 > len2)
        minLen = len2, maxLen = len1;
    else
        minLen = len1, maxLen = len2;
    int carry = 0;
    for (k = 0, i = len1 - 1, j = len2 - 1; k<minLen; k++, i--, j--)
    {
        int val = (str1[i] - '0') + (str2[j] - '0') + carry;
        result[k] = (val % 10) + '0';
        carry = val / 10;
    }
    while (k < len1)
    {
        int val = str1[i] - '0' + carry;
        result[k] = (val % 10) + '0';
        carry = val / 10;

        k++; i--;
    }
    while (k < len2)
    {
        int val = str2[j] - '0' + carry;
        result[k] = (val % 10) + '0';
        carry = val / 10;

        k++; j--;
    }
    if (carry > 0)
    {
        result[maxLen] = carry + '0';
        maxLen++;
        result[maxLen] = '\0';
    }
    else
    {
        result[maxLen] = '\0';
    }
    i = 0;
    while (result[--maxLen])
    {
        temp[i++] = result[maxLen];
    }
    temp[i] = '\0';
    return temp;
}

void generateFibonacci()
{
    int i;
    num[0][0] = '0'; num[0][1] = '\0';
    num[1][0] = '1'; num[1][1] = '\0';
    for (i = 2; i <= LIMIT; i++)
    {
        strcpy(num[i], sum(num[i - 1], num[i - 2]));
    }
}

int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int N;
    generateFibonacci();
    while (scanf("%d", &N) == 1)
    {
        printf("The Fibonacci number for %d is %s\n", N, num[N]);
    }
    return 0;
}
0

Calcul des nombres de fibonacci (en utilisant Haskell):

Version 1 : Traduction directe de la définition en code (version très lente):

fib :: Integer -> Integer
fib 0 = 1
fib 1 = 1
fib n =
  fib (n - 1) + fib (n - 2)

Version 2 : Utilisation du travail effectué pour calculer F_ ​​{n - 1} et F_ ​​{n - 2} (la version rapide):

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Vous pouvez obtenir le nième fibonacci en faisant simplement fibs !! nn est l'index.

Version 3 : Utilisation de la technique de multiplicaiton matricielle. (la version encore plus rapide):

-- declaring a matrix
data Matrix = Matrix
  ( (Integer, Integer)
  , (Integer, Integer)
  )
  deriving (Show, Eq)

-- creating it an instance of Num
-- so that if we implement (*) we get (^) for free
instance Num Matrix where
  (*) = mMult

  -- don't need these
  (+) = undefined
  negate = undefined
  fromInteger = undefined
  abs = undefined
  signum = undefined


-- 2-d matrix multiplication
mMult :: Matrix -> Matrix -> Matrix
mMult (Matrix ((a11, a12), (a21, a22))) (Matrix ((b11, b12), (b21, b22))) =
  Matrix
    ( (a11 * b11 + a12 * b21, a11 * b12 + a12 * b22)
    , (a21 * b11 + a22 * b21, a21 * b12 + a22 * b22)
    )

-- base matrix for generating fibonacci
fibBase :: Matrix
fibBase =
  Matrix ((1,1), (1,0))

-- get the large fibonacci numbers
fastFib :: Int -> Integer
fastFib n =
  let
    getNth (Matrix ((_, a12), _)) = a12
  in
    getNth (fibBase ^ n)
0
Sherub Thakur

J'ai un code source en c pour calculer même le 3500ème numéro de fibonacci: - Pour plus de détails, visitez le site 

http://codingloverlavi.blogspot.in/2013/04/fibonacci-series.html

code source en C: -

#include<stdio.h>
#include<conio.h>
#define max 2000

int arr1[max],arr2[max],arr3[max];

void fun(void);

int main()
{
    int num,i,j,tag=0;
    clrscr();
    for(i=0;i<max;i++)
        arr1[i]=arr2[i]=arr3[i]=0;

    arr2[max-1]=1;

    printf("ENTER THE TERM : ");
    scanf("%d",&num);

    for(i=0;i<num;i++)
    {
        fun();

        if(i==num-3)
            break;

        for(j=0;j<max;j++)
            arr1[j]=arr2[j];

        for(j=0;j<max;j++)
            arr2[j]=arr3[j];

    }

    for(i=0;i<max;i++)
    {
        if(tag||arr3[i])
        {
            tag=1;
            printf("%d",arr3[i]);
        }
    }


    getch();
    return 1;
}

void fun(void)
{
    int i,temp;
    for(i=0;i<max;i++)
        arr3[i]=arr1[i]+arr2[i];

    for(i=max-1;i>0;i--)
    {
        if(arr3[i]>9)
        {
            temp=arr3[i];
            arr3[i]%=10;
            arr3[i-1]+=(temp/10);
        }
    }
}
0
Lavish Kothari

Avec quelques connaissances en mathématiques discrètes, vous pouvez trouver n’importe quel nombre de Fibonacci en temps constant O (1). Il existe quelque chose appelé Relation de récurrence homogène linéaire

La séquence de Fibonacci est un exemple célèbre.

Pour trouver le nième numéro de Fibonacci, nous devons trouver que 

f

Nous savons que

f1

où 

f2

Ensuite, l'équation caractéristique est 

f3

Après avoir trouvé les racines de l’équation caractéristique et les avoir remplacées par la première équation

f4

Enfin, nous devons trouver la valeur des deux alpha 1 et alpha 2

ff

Maintenant, vous pouvez utiliser cette équation pour trouver un nombre de Fibonacci dans O (1).

0
Omar Alghamdi