From a36e9b5dbac6247b9dcf49382be61eaa0cfe7ae9 Mon Sep 17 00:00:00 2001 From: Orestis <orestis.malaspinas@pm.me> Date: Tue, 19 Oct 2021 00:47:00 +0200 Subject: [PATCH] =?UTF-8?q?recursivit=C3=A9=20finie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slides/cours_5.md | 246 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 226 insertions(+), 20 deletions(-) diff --git a/slides/cours_5.md b/slides/cours_5.md index 8de07ce..5d8bb24 100644 --- a/slides/cours_5.md +++ b/slides/cours_5.md @@ -324,7 +324,7 @@ $$ * Comportement indéfini! -# Nombres à virgule (1/N) +# Nombres à virgule (1/3) ## Comment manipuler des nombres à virgule? @@ -352,7 +352,7 @@ int main(int argc, char *argv[]) { ## Que se passe-t-il donc? -# Nombres à virgule (2/N) +# Nombres à virgule (2/3) ## Nombres à virgule fixe @@ -379,7 +379,7 @@ $$ * Tous les nombres `< 0.0625`. * Tous les nombres dont la décimale est pas un multiple de `0.0625`. -# Nombres à virgule (3/N) +# Nombres à virgule (3/3) ## Nombres à virgule fixe @@ -431,7 +431,7 @@ La précision des nombres est **variable**: * On a uniquement un nombre de chiffres **significatifs**. $$ -123456\cdot 10^23+ 123456\cdot 10^{-23}. +123456\cdot 10^{23}+ 123456\cdot 10^{-23}. $$ ## Quel inconvénient y a-t-il? @@ -440,7 +440,7 @@ $$ Ce mélange d'échelles entraîne un **perte de précision**. -# Nombres à virgule flottante simple précision (1/N) +# Nombres à virgule flottante simple précision (1/4) Aussi appelés *IEEE 754 single-precision binary floating point*. @@ -458,7 +458,7 @@ $$ $$ ## Calculer la valeur décimale du nombre ci-dessus -# Nombres à virgule flottante simple précision (2/N) +# Nombres à virgule flottante simple précision (2/4) ](figs/Float_example.svg) @@ -471,7 +471,7 @@ $$ &\Rightarrow (-1)^0\cdot 2^{-3}\cdot 1.25=0.15625 \end{align} -# Nombres à virgule flottante simple précision (3/N) +# Nombres à virgule flottante simple précision (3/4) ## Quel nombre ne peux pas être vraiment représenté? @@ -487,9 +487,9 @@ $$ $$ \mbox{valeur normale}, $$ -* Sinon `1111111` donne `NaN`. +* Sinon `11111111` donne `NaN`. -# Nombres à virgule flottante simple précision (4/N) +# Nombres à virgule flottante simple précision (4/4) ## Quels sont les plus petits/grands nombres positifs représentables? @@ -587,7 +587,7 @@ $$ . . . -Ou en d'autres termes, pour quel $\varepsilon>0$ on a +Ou en d'autres termes, pour quel $\varepsilon>0$ (appelé `epsilon-machine`) on a $$ 1+\varepsilon = 1, $$ @@ -613,7 +613,7 @@ while ((float)1.0 + (float)0.5 * eps != (float)1.0) { printf("eps = %g\n", eps); ``` -# Erreurs d'arrondi (1/N) +# Erreurs d'arrondi Et jusqu'ici on a encore pas fait d'arithmétique! @@ -634,20 +634,226 @@ Soit une erreur de près de 1/5e! . . . -Le même phénomène se produit (à plus petite échelle) avec les `float` ou +## Le même phénomène se produit (à plus petite échelle) avec les `float` ou `double`. -<!-- # TODO -- +# Exemple de récursivité (1/2) -<!-- ## Entiers, entiers non-signés --> +## La factorielle -<!-- ## Complément à 1, 2 --> +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; + } +} +``` + +. . . + +## Que se passe-t-il quand on fait `factorial(4)`? + +. . . + +## On empile les appels + ++----------------+----------------+----------------+----------------+ +| | | | `factorial(1)` | ++----------------+----------------+----------------+----------------+ +| | | `factorial(2)` | `factorial(2)` | ++----------------+----------------+----------------+----------------+ +| | `factorial(3)` | `factorial(3)` | `factorial(3)` | ++----------------+----------------+----------------+----------------+ +| `factorial(4)` | `factorial(4)` | `factorial(4)` | `factorial(4)` | ++----------------+----------------+----------------+----------------+ + +# Exemple de récursivité (2/2) + +## La factorielle + +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; + } +} +``` + +. . . + +## Que se passe-t-il quand on fait `factorial(4)`? + +. . . + +## On dépile les calculs + ++----------------+----------------+----------------+----------------+ +| `1` | | | | ++----------------+----------------+----------------+----------------+ +| `factorial(2)` | `2 * 1 = 2` | | | ++----------------+----------------+----------------+----------------+ +| `factorial(3)` | `factorial(3)` | `3 * 2 = 6` | | ++----------------+----------------+----------------+----------------+ +| `factorial(4)` | `factorial(4)` | `factorial(4)` | `4 * 6 = 24` | ++----------------+----------------+----------------+----------------+ + +# La récursivité (1/4) + +## Formellement + +* Une condition de récursivité - qui *réduit* les cas successifs vers... +* Une condition d'arrêt - qui retourne un résultat + +## Pour la factorielle, qui est qui? + +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; + } +} +``` + +# La récursivité (2/4) + +## Formellement + +* Une condition de récursivité - qui *réduit* les cas successifs vers... +* Une condition d'arrêt - qui retourne un résultat + +## Pour la factorielle, qui est qui? + +```C +int factorial(int n) { + if (n > 1) { // Condition de récursivité + return n * factorial(n - 1); + } else { // Condition d'arrêt + return 1; + } +} +``` + +# La récursivité (3/4) + +## Exercice: trouver l'$\varepsilon$-machine pour un `double` + +. . . + +```C +double epsilon_machine(double eps) { + if (1.0 + eps != 1.0) { + return epsilon_machine(eps / 2.0); + } else { + return eps; + } +} +``` + +# La récursivité (4/4) + +## Exercice: que fait ce code récursif? + +```C +void recurse(int n) { + printf("%d ", n % 2); + if (n / 2 != 0) { + recurse(n / 2); + } else { + printf("\n"); + } +} + +recurse(13); +``` + +. . . + +```C +binaire(13): n = 13, n % 2 = 1, n / 2 = 6, + binaire(6): n = 6, n % 2 = 0, n / 2 = 3, + binaire(3): n = 3, n % 2 = 1, n / 2 = 1, + binaire(1): n = 1, n % 2 = 1, n / 2 = 0. + +// affiche: 1 1 0 1 +``` + +# Exercice: réusinage et récursivité (1/4) + +## Réusiner le code du PGCD avec une fonction récursive + +## Étudier l'exécution + +```C +42 = 27 * 1 + 15 +27 = 15 * 1 + 12 +15 = 12 * 1 + 3 +12 = 3 * 4 + 0 +``` + +# Exercice: réusinage et récursivité (2/4) + +## Réusiner le code du PGCD avec une fonction récursive + +## Étudier l'exécution + +```C +42 = 27 * 1 + 15 | PGCD(42, 27) +27 = 15 * 1 + 12 | PGCD(27, 15) +15 = 12 * 1 + 3 | PGCD(15, 12) +12 = 3 * 4 + 0 | PGCD(12, 3) +``` + +# Exercice: réusinage et récursivité (3/4) + +## Réusiner le code du PGCD avec une fonction récursive + +## Étudier l'exécution + +```C +42 = 27 * 1 + 15 | PGCD(42, 27) +27 = 15 * 1 + 12 | PGCD(27, 15) +15 = 12 * 1 + 3 | PGCD(15, 12) +12 = 3 * 4 + 0 | PGCD(12, 3) +``` + +## Effectuer l'empilage - dépilage + +. . . + +```C +PGCD(12, 3) | 3 +PGCD(15, 12) | 3 +PGCD(27, 15) | 3 +PGCD(42, 27) | 3 +``` + +# Exercice: réusinage et récursivité (4/4) + +## Écrire le code + +. . . + +```C +int pgcd(int n, int m) { + if (n % m > 0) { + return pgcd(m, n % m); + } else { + return m; + } +} +``` -<!-- ## Nombres à virgule flottante, simple/double précision --> +# Exercices pour les semaines sans cours +## Quelques algorithmes à réaliser et poster sur matrix -# TODO jusqu'aux vacances +1. Algorithme du PPCM. +2. La puissance indienne. +3. La suite de Fibonacci. -* Refactorisation -* Tris et complexité -* Récursivité -- GitLab