Théorie 2.3: Fibonacci #
Définition #
-
Voici le début de la suite de Fibonacci
0 1 1 2 3 5 8 13 21 34 55 89 144 ...
-
La définition mathématique est récursive
\( F_0 = 0\\~\\ F_1 = 1\\~\\ F_n = F_{n-1} + F_{n-2}\\~\\ \) -
Autrement dit:
-
0
et1
sont deux cas spéciaux -
sinon le prochain nombre de la suite est toujours l’addition deux nombres précédents
-
Nombre d’or #
-
La suite de Fibonacci est utilisée pour calculer le nombre d’or, soit environs
1.618
- (le nombre d’or est reconnu, entre autres choses, comme une proportion hauteur/largeur agréable à l’oeil)
-
Comme pour π, on peut le calculer le nombre d’or avec autant que précision que désiré
- (c-à-d avec autant de chiffres après le point que désiré)
-
Pour calculer un approximation du nombre d’or on fait tout simplement:
\( \text{nombre d'or} \approx \dfrac{F_{n}}{F_{n-1}} \text{~~~pour~~~} n\geq 2 \) -
Plus on prend un
n
élevé, plus la précision est bonne -
Autrement dit, le nombre d’or est à peu près égal à:
-
un nombre de la suite de Fibonacci, divisé par le nombre qui le précède
-
(plus on prend un nombre loin dans la suite, plus l’approximation est bonne)
-
Modéliser la suite de Fibonnaci #
- Pour modéliser la suite en Java, on va créer une structure de données récursive
-
Pour
n = 0
, on a le graphe d’objets suivant -
Pour
n = 1
, on a le graphe d’objets suivant -
Pour
n = 2
, on a le graphe d’objets suivant- NOTE: la suite se lit de droite à gauche
-
Pour
n = 3
, on a le graphe d’objets suivant -
Et ainsi de suite…
Pour calculer la réponse et le nombre d’or #
-
Calculer la réponse pour
n >= 2
est simplereponse = moinsUn.getReponse() + moinsDeux.getReponse();
-
Même chose pour le nombre d’or
nombreOr = Double.valueOf(reponse) / Double.valueOf(moinsUn.getReponse());
-
Le défi est qu’il faut d’abord construire le graphe d’objet
Construire le graphe d’objets récursivement #
-
Avec des appels récursifs, on va construire d’abord, puis calculer
- on crée d’abord l’objet
n
, puisn-1
, et ainsi de suite jusqu’à l’objet0
- on crée d’abord l’objet
-
Pour le cas
n >= 2
, voici comment procéder-
créer un nouvel objet
MonFibonacci
et le mémoriser dansmoinsUn
-
enregistrer que le
n
de cemoinsUn
estn-1
(len
courant moins1
) -
créer le reste du graphe récursivement en appelant
moinsUn.construireGrapheRecursivement()
-
enregister que le
moinsDeux
courant estmoinsUn.getMoinsUn()
(lemoinsUn
dumoinsUn
courant) -
calculer la réponse courante à partir des réponses de
moinsUn
etmoinsDeux
-
-
L’appel récursif est plus proche de la définition mathématique
- (pour calculer la réponse en
n
, il faut d’abord calculer la réponse enn-1
)
- (pour calculer la réponse en
-
L’inconvénient est qu’on peut déborder la pile d’appel
Exception in thread "main" java.lang.StackOverflowError at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) ...
- RAPPEL: le code n’est pas bogué, mais limité par la mémoire attribuée à la pile d’appel
Construire le graphe d’objets dynamiquement #
-
En programmation dynamique, on calcule en même temps qu’on construit
- on crée d’abord l’objet
0
, puis1
, et ainsi de suite jusqu’à l’objetn
- on crée d’abord l’objet
-
L’idée est qu’on fait une boucle pour créer le graphe d’objets
-
on crée une
nouvelleTete
-
le
moinsUn
de lanouvelleTete
est l’anciennetete
-
le
moinsDeux
de lanouvelleTete
est lemoinsUn
de l’anciennetete
-
c-à-d on insère la
nouvelleTete
à gauche, et on «pousse» les objets existants vers la droite
-
-
Pour le cas
n >= 2
, voici comment procéder-
pour chaque
i
allant de2
àn
(inclusivement)-
créer un nouvel objet
MonFibonacci
pour représenter lanouvelleTete
-
enregistrer que le
n
de lanouvelleTete
esti
-
enregistrer que le
moinsUn
de lanouvelleTete
est latete
courante -
enregistrer que le
moinsDeux
de lanouvelleTete
est lemoinsUn
de latete
courante -
enregistrer que
tete
pointe maintenant vers lanouvelleTete
-
calculer la réponse pour
tete
-
-
-
Le calcul dynamique est moins intuitif (et moins proche de la définition mathématique), mais
- on a éliminé l’appel récursif, alors on ne peut plus déborder la pile d’appel