Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

FIBONACCI EN O( N )


Information sur la source

Catégorie :Maths & Algorithmes Classé sous : fibonacci, algorithme, fibonnacci Niveau : Débutant Date de création : 24/07/2004 Date de mise à jour : 24/07/2004 20:55:26 Vu : 5 486

Note :
Aucune note

Commentaire sur cette source (25)
Ajouter un commentaire et/ou une note


Description

Cliquez pour voir la capture en taille normale
Ce code permet de trouver le nombre n de la suite de fibonacci !
Le code est en O( n ) se qui accroit grandement sa vitesse !

Vous pouvez facilement avoir le 10^7ieme nombre de la suite de Fibonacci, aprés ça devient un peu long...
 

Source

  • #include <stdio.h>
  • typedef unsigned long int ULONG;
  • void MultiMatrice(ULONG Matrice1[][2], ULONG Matrice2[][2], ULONG MatriceResultat[][2])
  • {
  • int i,j,k;
  • for(i = 0; i < 2; i++)
  • {
  • for(j = 0; j < 2; j++)
  • {
  • MatriceResultat[i][j] = 0;
  • for(k = 0; k < 2; k++)
  • MatriceResultat[i][j] += Matrice1[i][k] * Matrice2[k][j];
  • }
  • }
  • }
  • void CopieMatrice(ULONG Matrice1[][2], ULONG Matrice2[][2])
  • {
  • int i,j;
  • for(i = 0; i < 2; i++)
  • for(j = 0; j < 2; j++)
  • Matrice1[i][j] = Matrice2[i][j];
  • }
  • int main(void)
  • {
  • int Nombre, n;
  • ULONG Matrice[2][2] = {{0,1},{1,1}};
  • ULONG resMatrice[2][2], tmpMatrice[2][2];
  • CopieMatrice(tmpMatrice, Matrice);
  • scanf("%lu",&Nombre);
  • if(Nombre <= 0)
  • {
  • printf("Le resultat est : 0");
  • getch();
  • return 0;
  • }
  • // On cherche la puissance N de la matrice :
  • // Le problème c'est que c'est en O( n ) pour l'instant !
  • for(n = 0; n < Nombre; n++)
  • {
  • MultiMatrice(tmpMatrice, Matrice, resMatrice);
  • CopieMatrice(tmpMatrice, resMatrice);
  • }
  • printf("Le resultat est : %lu", resMatrice[0][0]);
  • // F(n+1) ==> resMatrice[1][1] !
  • getch();
  • return 0;
  • }
#include <stdio.h>

typedef unsigned long int ULONG;
                    
void MultiMatrice(ULONG Matrice1[][2], ULONG Matrice2[][2], ULONG MatriceResultat[][2])
{
    int i,j,k;
    for(i = 0; i < 2; i++)
    {
        for(j = 0; j < 2; j++)
        {
            MatriceResultat[i][j] = 0;
            for(k = 0; k < 2; k++)
                MatriceResultat[i][j] += Matrice1[i][k] * Matrice2[k][j];
        }
    }
}

void CopieMatrice(ULONG Matrice1[][2], ULONG Matrice2[][2])
{
    int i,j;
    for(i = 0; i < 2; i++)
        for(j = 0; j < 2; j++)
            Matrice1[i][j] = Matrice2[i][j];
}
                  
int main(void)
{
    int Nombre, n;
    ULONG Matrice[2][2] = {{0,1},{1,1}};
    ULONG resMatrice[2][2], tmpMatrice[2][2];
    CopieMatrice(tmpMatrice, Matrice);
    
    scanf("%lu",&Nombre);
    if(Nombre <= 0)
    {
        printf("Le resultat est : 0");
        getch();
        return 0;
    }
    
    // On cherche la puissance N de la matrice :  
    // Le problème c'est que c'est en O( n ) pour l'instant !      
    for(n = 0; n < Nombre; n++)
    {
        MultiMatrice(tmpMatrice, Matrice, resMatrice);
        CopieMatrice(tmpMatrice, resMatrice);
    }

    printf("Le resultat est : %lu", resMatrice[0][0]);
    // F(n+1) ==> resMatrice[1][1] !
    
    getch();
    return 0;
}

Conclusion

Si vous savez comment faire pour rendre le code plus rapide, n'hésitez surtout pas ;)
 

Historique

24 juillet 2004 11:42:51 :
Mise à jour permmettant de dépasser l'erreur du modulo 2^32 des int
24 juillet 2004 20:54:13 :
Amélioration du code !
24 juillet 2004 20:55:26 :
Dépouillement du code des bugs !

Commentaires et avis

signaler à un administrateur
Commentaire de MetalDwarf le 24/07/2004 11:28:05

Oui je connais cette methode je l ai eu en DS d'info. C'est d'ailleurs etonnant que l algorithme "naturel" soit exponentiel, que le plus reflechi en O(n) et  celui-la en O(log(n)). Ce qui est egalement troublant c est le fait que cette formule n ai pas de rapport a priori avec la suite de fibonacci (meme si demontrer la correction de cet algorithme n est pas dur du tout).

signaler à un administrateur
Commentaire de ZogStriP le 24/07/2004 11:44:28 administrateur CS

J'ai lu sur une autre source :

"Il y a une méthode pour accélérer le tout de facon draconnienne (complexité en log(n) au lieu de n)
- on remarque que [[0,1][1,1]]^n a pour element en haut à gauche fibo(n)
- pour calculer a^n efficacement ,on utilise
a^(2*p)=(a*a)^p et a^(2*p+1)=a*((a*a)^p)"

Ca m'a l'air d'être plus rapide que mes boucles !
Si quelqu'un sait comment implémenter ça ;)

signaler à un administrateur
Commentaire de MetalDwarf le 24/07/2004 11:51:50

A oui c est vrai, je n avais pas regarde bien en detail ton code source.
Si tu veux que ton algo soit vraiment en O(log(n)), il faut imperativement utiliser l'algorithme d'exponentiation rapide sinon tu restes en O(n).
Il est tres simple a implementer, et il est naturellement recursif.

int exp_rap(int a, int n)
{
   int tmp;
   if(n=1) return 1;
   if(n%2)   // n impair
   {
       tmp = exp_rap(a,n/2);
       return (tmp*tmp)*a;
   }
    // n pair
   tmp = exp_rap(a,n/2);
    return tmp*tmp;
}

Bien sur vu que tu utilises des matrices il faut remplacer * par le produit des matrices.

signaler à un administrateur
Commentaire de coucou747 le 24/07/2004 13:39:48

c'est pas ce nombre qui s'aproche du nombre d'or plus n est grand ?

signaler à un administrateur
Commentaire de Xs le 24/07/2004 14:38:35

Si, lim (n->+oo) (Un+2 = Un+Un+1) = (1+Rac(5))/2

D'ailleurs, une manniere assez rapide le n-ieme terme de la suite de fibonacci est :

(si on part de U0 en 1er terme et non pas U1)

Un+1 = 1/Rac(5) * (L^n + L_barre^n)

ou L est la limite, donc (1+Rac(5))/2 et L_Barre le conjugué ((1-Rac(5)/2).

C'est, je pense, assez rapide (plus rapide que cet algo je pense), puisque n est naturel

signaler à un administrateur
Commentaire de coucou747 le 24/07/2004 14:54:07

Ok merci, mais bon, je comprends vraiment pas grand chose a ce que vous dites...

signaler à un administrateur
Commentaire de Xs le 24/07/2004 14:57:16

Tu comprends pas quoi ? Dis moi que j'essaie de t'expliquer :D

signaler à un administrateur
Commentaire de coucou747 le 24/07/2004 15:02:59

pouriez vous expliquer clairement comment fonctionne cette suite... (je rentre en première S alors les math, je connais, mais pas a haut niveau, et la progbah un peu mais pas trop non plus)
Comment cette suite se fait elle ?
A quoi ça corespond ?
(1+Rac(5))/2 ça je comprends, c'est le nombre d'or, mais le reste...
Je sais pas pose clairement tes variables ou explique a quoi ça coresponds, la moi, je reste coincé... (même si ce problème n'est pas dans mes projets actuels, j'aime bien les math alors je me renseigne.)

signaler à un administrateur
Commentaire de Xs le 24/07/2004 16:06:57

Re !

"Comment cette suite se fait elle ?"
=> Reformule ta question stp, je ne comprend pas trés bien ce qu'elle veut dire. Si tu demandes d'ou on la sort, faut voir pour la petite histoire des lapins de F.

Si tu parles de "comment calculer Un" :

Une suite est en faite une fonction adaptée pour N (donc l'application U:N->R alors qu'une fct est f:R->R ou dans le genre)
C'est a dire que (Un) est le n-ieme terme de la suite, et que n est un entier naturel (0,1,2,....)

Dans le cas de F., si on te donne U(0) = 0 et U(1) = 1, pour calculer
U(2) tu fais, sachant que U(n+2) = U(n) + U(n+1)
n+2 = 2 <=> n = 0

donc

U(0+2) = U(0) + U(0+1)
<=> U(2) = U(0) + U(1)
<=> U(2) = 0 + 1
<=> U(2) = 1

U(3) = U(1) + U(2)
<=> U(3) = 1 + 1
<=> U(3) = 2

U(4) = U(2) + U(3)
<=> U(4) = 1 + 2 = 3

etc.... (u(5) = 5 ; u(6) = 8 ; u(7) = 13....)

Mes variables, je suppose L et L_barre sont juste des lettres que j'ai prises pour remplacer ce nombre d'or dont l'ecriture dans une equation en ANSII est assez casse pieds et encore plus à lire.

L_barre est le conjugué de ce nombre. Le conjugué de a+b est a-b. donc L_barre = (1-Rac(5))/2.

Pour ma "formule", c'est mon prof de maths qui me l'a donné, sans la démontrer (enfin si, mais j'ai rien compris à ses histoires d'espaces vectoriel, linéarité,etc...)

Ah ui, L est la limite de la suite de F. C'est a dire que plus "n" devient grand, plus on prend n aussi grand que l'on veut, plus U(n) aura des valeurs proches de 1.668.... ((1+Rac(5))/2)

Voici la démo (enfin.. les fractions continues ne sont pas une démo à mon gout mais bon)
http://www.sciences-en-ligne.com/momo/chronomath/anx3/suite_fibo.html

J'epere que tu auras compris ce que je t'ai expliqué... mais sache que faire plus précis va m'etre difficile car je ne suis qu'en TS (ex-1er S :D)


cordailement

signaler à un administrateur
Commentaire de MetalDwarf le 24/07/2004 16:42:08

non non non on ne peux pas dire que cette suite converge vers le nombre d'or puisque c est faux!!
en effet elle diverge vers +oo !!

Je crois par contre que cette limite est vraie :
           un+1
lim      -------  = (1+Rac(5))/2
n->oo   un

est correcte.

Quant a la methode presentee ici pour calculer cette suite, elle utilise les matrices (niveau 1ere annee de DEUG MIAS ou math sup)

signaler à un administrateur
Commentaire de coucou747 le 24/07/2004 16:55:25

ah oui, c'est les lapins quse multiplient tout les 4 mois...
Qqn dans ma classe avait le nombre d'or comme thème d'étude...

Donc, cette "fonction" si j'ai bien compris, donne :
f(x)=f(x-1)+f(x-2)
et évidement, x ne peut pas être infèrieur a deux car avec un seul lapin, on a rien...
Mais ceci c'est une fonction f:N->N
et ça ne va pas vers le nombre d'or...

signaler à un administrateur
Commentaire de ZogStriP le 24/07/2004 20:57:58 administrateur CS

Le problème c'est que les suites ne sont pas vraiment des fonctions (enfin si, mais non en fait ;)

Tu apprendras tout ça en 1Ere S c'est au programme ( et je peux te dire que je m'en souvient... 21/20 au contrôle)

Sinon, j'ai trouvé l'exponentiation rapide en itératif :

ULONG exponentiation_rapide(int Nombre, int Puissance)
{
    ULONG resultat = 1lu;
    while (Puissance != 0)
    {
        // si Puissance est impair :
        if(Puissance % 2)
            resultat *= Nombre;
        Nombre *= Nombre;
        Puissance /= 2;
    }
    return resultat;
}

Le problème c'est que je n'arrive pas à l'implémenter avec les Multiplications de matrice...
MetalDwarf, tu peux m'aider ?

signaler à un administrateur
Commentaire de coucou747 le 24/07/2004 21:01:46

je ne compredns pas vraiment ce que tu veux faire, mais si tu veux, j'ai un truc qui permet de faire a=i^d%n
on s'en sert en cryptographie rsa

signaler à un administrateur
Commentaire de ZogStriP le 25/07/2004 00:59:55 administrateur CS

Merci bcp coucou747 mais j'en ai pas besoin ;)

Je souhaiterais simplement "changer" l'algo pour qu'il fonctionne avec les multiplication des matrices et non des nombres !

signaler à un administrateur
Commentaire de MetalDwarf le 25/07/2004 11:07:08

Ba je ne vois pas trop ou est le probleme!!
Est ce que tu as une fonction de multiplication des matrices 2x2. Si non tu peux facilement en faire une qui aurait comme prototype :

int [2][2] mult_mat(int mat1[2][2],int mat2[2][2]);

a partir de la ton algo devient :

int [2][2] exponentiation_rapide(int mat[2][2], int Puissance)
{
    int resultat[2][2] = {{1,0],{0,1}};  // la matrice unite
    while (Puissance != 0)
    {
        // si Puissance est impair :
        if(Puissance % 2)
            resultat = mult_mat(resultat,mat);
        mat = mult_mat(mat,mat);
        Puissance /= 2;
    }
    return resultat;
}

Je crois que c est correct, mais je ne guarantie rien car je n ai implemente cet algorithme qu en Caml (langage au programme en math sup).

signaler à un administrateur
Commentaire de ZogStriP le 25/07/2004 11:49:20 administrateur CS

Le problème c'est quand c/c++ on ne peut pas retourner un tableau à deux dimensions !

Il faut le faire comme je l'ai fait !

signaler à un administrateur
Commentaire de Xs le 25/07/2004 13:32:05

Ah bon ? C'est la meilleure celle-là.

En C/C++, peut etre que tu ne peux pas retourner de tableau a 2 dim, mais en tout cas tu peux retourner un double ptr :

int**exponentiation_rapide(int mat[2][2], int Puissance)
{
    int **resultat // la matrice unite
    *resultat = new int[2]

for(int i=0;i<2;i++)
   resultat[i] = new int[2];

    while (Puissance != 0)
    {
        // si Puissance est impair :
        if(Puissance % 2)
            resultat = mult_mat(resultat,mat);
        mat = mult_mat(mat,mat);
        Puissance /= 2;
    }
    return resultat;
}

signaler à un administrateur
Commentaire de JCDjcd le 26/07/2004 19:56:40

Le nombre d'or est lie au suite de fibbonacci par la relation dite plus haut, d'ailleurs cette methode est "instantanée" du faite que sont calcul ne depend pas de n, donc => O(k) avec k une constante independante de n. Pour la demonstration, elle n'est pas tres complique.

Sinon je voudrais intervenir au sujet de l'exponentielle rapide. L'algorithme est pas si difficile a comprendre (je l'ai implementer pour une cryptage RSA pour mon TPE de premier). Le but est d'elever un nombre (au une matrice) a une exposant entier (x^n). Si vous ecrivez l'exposant en base 2, alors on s'apersoit qu'il faut mutiplier par x le nombre si il y a un 1, et sinon dans les deux autre cas (0/1) on eleve au carre.

signaler à un administrateur
Commentaire de coucou747 le 26/07/2004 20:01:51

euh...
si je comptrends bien ,ceci devrais fonctionner pour calculer cette suite ?

#include <stdio.h>
int main(void)
{
int unsigned long a,b,c,i=1;
a=0;
b=1;
i++
c=a+b;
printf("f(%i)=%d\n",i,c);
a=b;
b=c:
}

signaler à un administrateur
Commentaire de coucou747 le 26/07/2004 20:04:33

oups, j'avais oublié la boucle... voici la version corigée :

#include <stdio.h>
int main(void)
{
int unsigned long a,b,c,i=1;
a=0;
b=1;
while(1){
i++
c=a+b;
printf("f(%i)=%d\n",i,c);
a=b;
b=c:
}
}

signaler à un administrateur
Commentaire de JCDjcd le 27/07/2004 10:59:59

Non la formule suivant, temps de calcul independant de n !! :

Un=1/sqrt(5) * [p0^n - p1^n]
avec p0 et p1 les deux nombres en or :
p0=(1+sqrt(5))/2
p1=(1-sqrt(5))/2

DEMONSTRATION DE LA FORMULE :
on suppose que Un est de la forme x^n (c'est exponentielle, donc ...) alors Un+2 = Un+1 + Un
Donc : x^(n+2) - x^(n+1) - x^n = 0     <=>   x^n * [x²-x-1] = 0
On suppose que x est non nul, donc x²-x-1=0
donc x=p0 ou x=p1 (nombres definis plus haut, les deux nombres en or).
De plus on peut rajouter un constant k devant x^n : Un = k.x^n
La demonstration est la meme. Mais on a aussi : U0=0 et U1=1, c'est deux conditions nous obligent a ecrire : Un = k0.p0^n + k1.p1^n    (qui est solution de Un+2 = Un+1 + Un, voir demonstration plus haut), il suffit donc de determiner k0 et k1 selon les deux valeurs initiales de U0 et U1.
U0 = 0 = k0 + k1   donc   k1 = -k0
U1 = 1 = k0.p0 + k1.p1  donc  k0(p0-p1)=1  donc k0=1/(p0-p1)
Or p0-p1=sqrt(5) , faite le calcul vous meme ...
D'ou la formule :

Un=1/sqrt(5) * [p0^n - p1^n]

ou sinon :

Un=1/sqrt(5) * [((1+sqrt(5))/2)^n - ((1-sqrt(5))/2)^n]
1

signaler à un administrateur
Commentaire de coucou747 le 27/07/2004 14:10:16

oulala je comprends plus moi....
faut que je me recicle en bac es...
Ta solution est surement plus rapide si tu cherche un grand nombre, mais si tu cherche toute la suite, que tu veux l'enregistrer dans un fichier ?
Ce que j'ai dit marche ?
Sur ma calculatrice j'ai fais ce joli petit programme, et j'obtient
1 + f(n-1) / f(n) environ = a (1+ sqrt(5) ) / 2;
voila voila...

signaler à un administrateur
Commentaire de JCDjcd le 27/07/2004 14:35:29

Ouais, si tu veux toutes la suite, il faut faire la boucle, mais si tu veux un nombre de la suite en particulier (sans calculer les precedents) alors ma methode (enfin c'est pas la mienne, mais celle que j'ai ecrite et demonstrée) est plus rapide.

signaler à un administrateur
Commentaire de coucou747 le 27/07/2004 14:43:01

ok, je ne m'ataques pas a des problèmes de math de ce niveau la si ça ne m'interesse pas vraiment (dsl de te le dire comme ça)

J'adore les math, mais pour moi, ce petit programme n'était qu'un exercice de maitrise du C (enfin, celui en tibasic, je sais pas pourquois je l'ai fait...)

je cherches en ce moment a faire du AES alors je sais c'est plus compliqué, mais en me temps on fait qqch d'un peu plus concret...

Cependant très bonne solution, mais faut y ajouter une fonction de gestion de grands nombres... (ce que je suis entrain de faire pour le rsa)

signaler à un administrateur
Commentaire de MetalDwarf le 27/07/2004 22:10:44

Alors la je dis FAUTE!!
Non ce programme n est pas en O(k) (d ailleurs O(k) ca se dit pas, on dit O(1) en general).
Tu crois qu une matrice ca s eleve a la puissance n comme ca?? Et non c est de la que vient la complexite. Et justement le complexite de ce programme est en O(log2(n)), et ca j en suis sur je devais le demontrer en DS d info cette annee!!

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Algorithme de compression STAR amélioré [ par hi_vivie2 ] Bonjour à tous,Je dois réaliser de manière urgente l'implémentation en java de l'algorithme de compression STAR amélioré appliqué aux images en mouvem Algorithme de compression STAR amélioré [ par hi_vivie2 ] Bonjour à tous,Je dois réaliser de manière urgente l'implémentation en java de l'algorithme de compression STAR amélioré appliqué aux images en mouvem un programme à creer [ par yoyo ] je dois creer un programme permettant d trouver les nombres premiers.l'algorithme est donné, et il utilise des tableaux dont les cases sont remplies p Qui sait l'algorithme pour calculer les racines? [ par TMT ] Aidez-moi! conversion de la partie fractionnaire en base n [ par Alucard ] J'ai vu qu'il y avait beaucoup d'algorithme de la partie entière (int) d'un nombre en n'importe quel base mais je voulais savoir si quelqu'un avait un Algorithme de mélange [ par C2S ] bonjour, j'aimerais connaitre un algorithme de mélange d'un tableau... (aléatoire) ... c'est pour simuler une fonction "mélanger" relative a un paquet aide sur l'algorithme AMR [ par semecurbep ] Votre texte iciVotre texte ICIVotre texte ICI map basic?????? [ par Sfoued2003 ] slt tout le monde,je me demande si je peux faire implémenter un algorithme de Electre1 sur map basic, pour pouvoir l'utiliser aprés sur map info? et ç algorithme de gauss et decomposition LU [ par speedamine ] bonjour a tous.je voudrai avoir des algorithmes ,ecrits en borland pascal,suivants:methode de gauss ordinaire pour la resolution d'un systeme .la deco Algorithme conversion Noms longs <-> Noms courts [ par franck406 ] Je suis à la recherche de l'algorithme qui permet d'obtenir un nom fichier court à partir d'un nom de fichier long comme le fait Dos. Je dois écrire u


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,608 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.