From 407b3f890533d5cfe23eff0bc7c647957f078563 Mon Sep 17 00:00:00 2001 From: Orestis <orestis.malaspinas@pm.me> Date: Sun, 13 Oct 2024 21:00:19 +0200 Subject: [PATCH] update 2024 --- slides/cours_4.md | 61 ----- slides/cours_5.md | 480 +++++++++++++++++++---------------- slides/cours_6.md | 633 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 890 insertions(+), 284 deletions(-) create mode 100644 slides/cours_6.md diff --git a/slides/cours_4.md b/slides/cours_4.md index 15e37dd..f018ab2 100644 --- a/slides/cours_4.md +++ b/slides/cours_4.md @@ -208,64 +208,3 @@ Algorithme de génération de nombres premiers. * Implémenter l'algorithme et le poster sur le salon `Element`. -# Crible d'Ératosthène: solution - -\footnotesize - -```C -#include <stdio.h> -#include <stdbool.h> -#define SIZE 51 -int main() { - bool tab[SIZE]; - for (int i=0;i<SIZE;i++) { - tab[i] = true; - } - for (int i = 2; i < SIZE; i++) { - if (tab[i]) { - printf("%d ", i); - int j = i; - while (j < SIZE) { - j += i; - tab[j] = false; - } - } - } - printf("\n"); -} -``` - - -# Réusinage de code (refactoring) - -## Le réusinage est? - -. . . - -* le processus de restructuration d'un programme: - * en modifiant son design, - * en modifiant sa structure, - * en modifiant ses algorithmes - * mais en **conservant ses fonctionalités**. - -. . . - -## Avantages? - -. . . - -* Amélioration de la lisibilité, -* Amélioration de la maintenabilité, -* Réduction de la complexité. - -. . . - -## "Make it work, make it nice, make it fast", Kent Beck. - -. . . - -## Exercice: - -* Réusiner le code se trouvant sur - [Cyberlearn](https://cyberlearn.hes-so.ch/pluginfile.php/703384/mod_resource/content/1/comprendre.c). - diff --git a/slides/cours_5.md b/slides/cours_5.md index 5b60503..026299a 100644 --- a/slides/cours_5.md +++ b/slides/cours_5.md @@ -1,15 +1,77 @@ --- -title: "Tableaux à deux dimensions et représentation des nombres" +title: "Tableaux à deux dimensions et récursivité" date: "2024-10-14" --- +# Rappel / devoirs: Crible d'Ératosthène + +* But: + - Générer tous les nombres premiers plus petit qu'un entier $N$. + - En utilisant qu'un tableau de booléens + - Et que des multiplications +* Exercice: Écrire l'algorithme en C. + +# Crible d'Ératosthène: solution + +\footnotesize + +```C +#include <stdio.h> +#include <stdbool.h> +#define SIZE 51 +int main() { + bool tab[SIZE]; + for (int i=0;i<SIZE;i++) { + tab[i] = true; + } + for (int i = 2; i < SIZE; i++) { + if (tab[i]) { + printf("%d ", i); + int j = i; + while (j < SIZE) { + j += i; + tab[j] = false; + } + } + } + printf("\n"); +} +``` + # Réusinage de code (refactoring) +## Le réusinage est? + +. . . + +* le processus de restructuration d'un programme: + * en modifiant son design, + * en modifiant sa structure, + * en modifiant ses algorithmes + * mais en **conservant ses fonctionalités**. + +. . . + +## Avantages? + +. . . + +* Amélioration de la lisibilité, +* Amélioration de la maintenabilité, +* Réduction de la complexité. + +. . . + +## "Make it work, make it nice, make it fast", Kent Beck. + +. . . + ## Exercice: * Réusiner le code se trouvant sur [Cyberlearn](https://cyberlearn.hes-so.ch/pluginfile.php/703384/mod_resource/content/1/comprendre.c). + # Tableau à deux dimensions (1/4) ## Mais qu'est-ce donc? @@ -175,313 +237,285 @@ for (int i = 0; i < NX; ++i) { A faire à la maison comme exercice! -# Représentation des nombres (1/2) +# And now for something completely different -* Le nombre `247`. +\Huge La récursivité -## Nombres décimaux: Les nombres en base 10 +# La factorielle: Code impératif -+--------+--------+--------+ -| $10^2$ | $10^1$ | $10^0$ | -+--------+--------+--------+ -| `2` | `4` | `7` | -+--------+--------+--------+ +* Code impératif -$$ -247 = 2\cdot 10^2 + 4\cdot 10^1 + 7\cdot 10^0. -$$ - -# Représentation des nombres (2/2) +```C +int factorial(int n) { + int f = 1; + for (int i = 1; i < n; ++i) { + f *= i; + } + return f; +} +``` -* Le nombre `11110111`. +# Exemple de récursivité (1/2) -## Nombres binaires: Les nombres en base 2 +## La factorielle -+-------+-------+-------+-------+-------+-------+-------+-------+ -| $2^7$ | $2^6$ | $2^5$ | $2^4$ | $2^3$ | $2^2$ | $2^1$ | $2^0$ | -+-------+-------+-------+-------+-------+-------+-------+-------+ -| `1` | `1` | `1` | `1` | `0` | `1` | `1` | `1` | -+-------+-------+-------+-------+-------+-------+-------+-------+ - -$$ -1\cdot 2^7 + 1\cdot 2^6 +1\cdot 2^5 +1\cdot 2^4 +0\cdot 2^3 +1\cdot 2^2 -+1\cdot 2^1 +1\cdot 2^0 -$$ +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; + } +} +``` . . . -$$ -= 247. -$$ - -# Conversion de décimal à binaire (1/2) - -## Convertir 11 en binaire? +## Que se passe-t-il quand on fait `factorial(4)`? . . . -* On décompose en puissances de 2 en partant de la plus grande possible +## On empile les appels - ``` - 11 / 8 = 1, 11 % 8 = 3 - 3 / 4 = 0, 3 % 4 = 3 - 3 / 2 = 1, 3 % 2 = 1 - 1 / 1 = 1, 1 % 1 = 0 - ``` -* On a donc - - $$ - 1011 \Rightarrow 1\cdot 2^3 + 0\cdot 2^2 + 1\cdot 2^1 + 1\cdot - 2^0=11. - $$ ++----------------+----------------+----------------+----------------+ +| | | | `factorial(1)` | ++----------------+----------------+----------------+----------------+ +| | | `factorial(2)` | `factorial(2)` | ++----------------+----------------+----------------+----------------+ +| | `factorial(3)` | `factorial(3)` | `factorial(3)` | ++----------------+----------------+----------------+----------------+ +| `factorial(4)` | `factorial(4)` | `factorial(4)` | `factorial(4)` | ++----------------+----------------+----------------+----------------+ -# Conversion de décimal à binaire (2/2) +# Exemple de récursivité (2/2) -## Convertir un nombre arbitraire en binaire: 247? +## La factorielle -* Par groupe établir un algorithme. - -. . . - -## Algorithme - -1. Initialisation - - ```C - num = 247 - N = 0 - - tant que (2^(N+1) < num) { - N += 1 +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; } - ``` +} +``` . . . -2. Boucle +## Que se passe-t-il quand on fait `factorial(4)`? - ```C - tant que (N >= 0) { - bit = num / 2^N - num = num % 2^N - N -= 1 - } - ``` - -# Les additions en binaire +. . . -Que donne l'addition `1101` avec `0110`? +## On dépile les calculs -* L'addition est la même que dans le système décimal ++----------------+----------------+----------------+----------------+ +| `1` | | | | ++----------------+----------------+----------------+----------------+ +| `factorial(2)` | `2 * 1 = 2` | | | ++----------------+----------------+----------------+----------------+ +| `factorial(3)` | `factorial(3)` | `3 * 2 = 6` | | ++----------------+----------------+----------------+----------------+ +| `factorial(4)` | `factorial(4)` | `factorial(4)` | `4 * 6 = 24` | ++----------------+----------------+----------------+----------------+ - ``` - 1101 8+4+0+1 = 13 - + 0110 + 0+4+2+0 = 6 - ------- ----------------- - 10011 16+0+0+2+1 = 19 - ``` -* Les entiers sur un ordinateur ont une précision **fixée** (ici 4 bits). -* Que se passe-t-il donc ici? +# La récursivité (1/4) -. . . +## Formellement -## Dépassement de capacité: le nombre est "tronqué" +* Une condition de récursivité - qui *réduit* les cas successifs vers... +* Une condition d'arrêt - qui retourne un résultat -* `10011 (19) -> 0011 (3)`. -* On fait "le tour"." +## Pour la factorielle, qui est qui? -# Entier non-signés minimal/maximal +```C +int factorial(int n) { + if (n > 1) { + return n * factorial(n - 1); + } else { + return 1; + } +} +``` -* Quel est l'entier non-signé maximal représentable avec 4 bit? +# La récursivité (2/4) -. . . +## Formellement -$$ -(1111)_2 = 8+4+2+1 = 15 -$$ +* Une condition de récursivité - qui *réduit* les cas successifs vers... +* Une condition d'arrêt - qui retourne un résultat -* Quel est l'entier non-signé minimal représentable avec 4 bit? +## 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; + } +} +``` -$$ -(0000)_2 = 0+0+0+0 = 0 -$$ +# La récursivité (3/4) -* Quel est l'entier non-signé min/max représentable avec N bit? +## Exercice: trouver l'$\varepsilon$-machine pour un `double` . . . -$$ -0\mbox{ et }2^N-1. -$$ - -* Donc `uint32_t?` maximal est? +Rappelez-vous vous l'avez fait en style **impératif** plus tôt. . . . -$$ -2^{32}-1=4'294'967'295 -$$ - - -# Les multiplications en binaire (1/2) - -Que donne la multiplication de `1101` avec `0110`? +```C +double epsilon_machine(double eps) { + if (1.0 + eps != 1.0) { + return epsilon_machine(eps / 2.0); + } else { + return eps; + } +} +``` -* La multiplication est la même que dans le système décimal +# La récursivité (4/4) - ``` - 1101 13 - * 0110 * 6 - --------- -------------- - 0000 78 - 11010 - 110100 - + 0000000 - --------- -------------- - 1001110 64+0+0+8+4+2+0 - ``` +\footnotesize -# Les multiplications en binaire (2/2) +## Exercice: que fait ce code récursif? -## Que fait la multiplication par 2? +```C +void recurse(int n) { + printf("%d ", n % 2); + if (n / 2 != 0) { + recurse(n / 2); + } else { + printf("\n"); + } +} +recurse(13); +``` . . . -* Décalage de un bit vers la gauche! - - ``` - 0110 - * 0010 - --------- - 0000 - + 01100 - --------- - 01100 - ``` - -. . . +```C +recurse(13): n = 13, n % 2 = 1, n / 2 = 6, + recurse(6): n = 6, n % 2 = 0, n / 2 = 3, + recurse(3): n = 3, n % 2 = 1, n / 2 = 1, + recurse(1): n = 1, n % 2 = 1, n / 2 = 0. -## Que fait la multiplication par $2^N$? +// affiche: 1 1 0 1 +``` . . . -* Décalage de $N$ bits vers la gauche! +Affiche la représentation binaire d'un nombre! -# Entiers signés (1/2) +# Exercice: réusinage et récursivité (1/4) -Pas de nombres négatifs encore... +## Réusiner le code du PGCD avec une fonction récursive -## Comment faire? +## Étudier l'exécution -. . . - -## Solution naïve: - -* On ajoute un bit de signe (le bit de poids fort): - - ``` - 00000010: +2 - 10000010: -2 - ``` - -## Problèmes? +```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) -* Il y a deux zéros (pas trop grave): `10000000` et `00000000` -* Les additions différentes que pour les non-signés (très grave) - - ``` - 00000010 2 - + 10000100 + -4 - ---------- ---- - 10000110 = -6 != -2 - ``` +## Réusiner le code du PGCD avec une fonction récursive -# Entiers signés (2/2) +## Étudier l'exécution -## Beaucoup mieux +```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) +``` -* Complément à un: - * on inverse tous les bits: `1001 => 0110`. +# Exercice: réusinage et récursivité (3/4) -## Encore un peu mieux +## Réusiner le code du PGCD avec une fonction récursive -* Complément à deux: - * on inverse tous les bits, - * on ajoute 1 (on ignore les dépassements). +## É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) +``` -* Comment écrit-on `-4` en 8 bits? +## Effectuer l'empilage - dépilage . . . +```C +PGCD(12, 3) | 3 +PGCD(15, 12) | 3 +PGCD(27, 15) | 3 +PGCD(42, 27) | 3 ``` - 4 = 00000100 - ________ - -4 => 00000100 - - 11111011 - + 00000001 - ---------- - 11111100 -``` - -# Le complément à 2 (1/2) -## Questions: +# Exercice: réusinage et récursivité (4/4) -* Comment on écrit `+0` et `-0`? -* Comment calcule-t-on `2 + (-4)`? -* Quel est le complément à 2 de `1000 0000`? +## Écrire le code . . . -## Réponses - -* Comment on écrit `+0` et `-0`? - - ``` - +0 = 00000000 - -0 = 11111111 + 00000001 = 100000000 => 00000000 - ``` -* Comment calcule-t-on `2 + (-4)`? +```C +int pgcd(int n, int m) { + if (n % m > 0) { + return pgcd(m, n % m); + } else { + return m; + } +} +``` - ``` - 00000010 2 - + 11111100 + -4 - ---------- ----- - 11111110 -2 - ``` -* En effet +# La suite de Fibonacci (1/2) - ``` - 11111110 => 00000001 + 00000001 = 00000010 = 2. - ``` +## Règle -# Le complément à 2 (2/2) +$$ +\mathrm{Fib}(n) = \mathrm{Fib}(n-1) + \mathrm{Fib}(n-2),\quad +\mathrm{Fib}(0)=0,\quad \mathrm{Fib}(1)=1. +$$ -## Quels sont les entiers représentables en 8 bits? +## Exercice: écrire la fonction $\mathrm{Fib}$ en récursif et impératif . . . -``` -01111111 => 127 -10000000 => -128 // par définition -``` +## En récursif (6 lignes) -## Quels sont les entiers représentables sur $N$ bits? +```C +int fib(int n) { + if (n > 1) { + return fib(n - 1) + fib(n - 2); + } + return n; +} +``` -. . . +# La suite de Fibonacci (2/2) -$$ --2^{N-1} ... 2^{N-1}-1. -$$ +## Et en impératif (11 lignes) -## Remarque: dépassement de capacité en `C` +```C +int fib_imp(int n) { + int fib0 = 1; + int fib1 = 1; + int fib = n == 0 ? 0 : fib1; + for (int i = 2; i < n; ++i) { + fib = fib0 + fib1; + fib0 = fib1; + fib1 = fib; + } + return fib; +} +``` -* Comportement indéfini! diff --git a/slides/cours_6.md b/slides/cours_6.md new file mode 100644 index 0000000..748b6e2 --- /dev/null +++ b/slides/cours_6.md @@ -0,0 +1,633 @@ +--- +title: "Représentation des nombres" +date: "2024-10-14" +--- + +# Représentation des nombres + +\Huge La représentation des nombres + +# Représentation des nombres (1/2) + +* Le nombre `247`. + +## Nombres décimaux: Les nombres en base 10 + ++--------+--------+--------+ +| $10^2$ | $10^1$ | $10^0$ | ++--------+--------+--------+ +| `2` | `4` | `7` | ++--------+--------+--------+ + +$$ +247 = 2\cdot 10^2 + 4\cdot 10^1 + 7\cdot 10^0. +$$ + +# Représentation des nombres (2/2) + +* Le nombre `11110111`. + +## Nombres binaires: Les nombres en base 2 + ++-------+-------+-------+-------+-------+-------+-------+-------+ +| $2^7$ | $2^6$ | $2^5$ | $2^4$ | $2^3$ | $2^2$ | $2^1$ | $2^0$ | ++-------+-------+-------+-------+-------+-------+-------+-------+ +| `1` | `1` | `1` | `1` | `0` | `1` | `1` | `1` | ++-------+-------+-------+-------+-------+-------+-------+-------+ + +$$ +1\cdot 2^7 + 1\cdot 2^6 +1\cdot 2^5 +1\cdot 2^4 +0\cdot 2^3 +1\cdot 2^2 ++1\cdot 2^1 +1\cdot 2^0 +$$ + +. . . + +$$ += 247. +$$ + +# Conversion de décimal à binaire (1/2) + +## Convertir 11 en binaire? + +. . . + +* On décompose en puissances de 2 en partant de la plus grande possible + + ``` + 11 / 8 = 1, 11 % 8 = 3 + 3 / 4 = 0, 3 % 4 = 3 + 3 / 2 = 1, 3 % 2 = 1 + 1 / 1 = 1, 1 % 1 = 0 + ``` +* On a donc + + $$ + 1011 \Rightarrow 1\cdot 2^3 + 0\cdot 2^2 + 1\cdot 2^1 + 1\cdot + 2^0=11. + $$ + +# Conversion de décimal à binaire (2/2) + +## Convertir un nombre arbitraire en binaire: 247? + +* Par groupe établir un algorithme. + +. . . + +## Algorithme + +1. Initialisation + + ```C + num = 247 + N = 0 + + tant que (2^(N+1) < num) { + N += 1 + } + ``` + +. . . + +2. Boucle + + ```C + tant que (N >= 0) { + bit = num / 2^N + num = num % 2^N + N -= 1 + } + ``` + +# Les additions en binaire + +Que donne l'addition `1101` avec `0110`? + +* L'addition est la même que dans le système décimal + + ``` + 1101 8+4+0+1 = 13 + + 0110 + 0+4+2+0 = 6 + ------- ----------------- + 10011 16+0+0+2+1 = 19 + ``` +* Les entiers sur un ordinateur ont une précision **fixée** (ici 4 bits). +* Que se passe-t-il donc ici? + +. . . + +## Dépassement de capacité: le nombre est "tronqué" + +* `10011 (19) -> 0011 (3)`. +* On fait "le tour"." + +# Entier non-signés minimal/maximal + +* Quel est l'entier non-signé maximal représentable avec 4 bit? + +. . . + +$$ +(1111)_2 = 8+4+2+1 = 15 +$$ + +* Quel est l'entier non-signé minimal représentable avec 4 bit? + +. . . + +$$ +(0000)_2 = 0+0+0+0 = 0 +$$ + +* Quel est l'entier non-signé min/max représentable avec N bit? + +. . . + +$$ +0\mbox{ et }2^N-1. +$$ + +* Donc `uint32_t?` maximal est? + +. . . + +$$ +2^{32}-1=4'294'967'295 +$$ + + +# Les multiplications en binaire (1/2) + +Que donne la multiplication de `1101` avec `0110`? + +* La multiplication est la même que dans le système décimal + + ``` + 1101 13 + * 0110 * 6 + --------- -------------- + 0000 78 + 11010 + 110100 + + 0000000 + --------- -------------- + 1001110 64+0+0+8+4+2+0 + ``` + +# Les multiplications en binaire (2/2) + +## Que fait la multiplication par 2? + +. . . + +* Décalage de un bit vers la gauche! + + ``` + 0110 + * 0010 + --------- + 0000 + + 01100 + --------- + 01100 + ``` + +. . . + +## Que fait la multiplication par $2^N$? + +. . . + +* Décalage de $N$ bits vers la gauche! + +# Entiers signés (1/2) + +Pas de nombres négatifs encore... + +## Comment faire? + +. . . + +## Solution naïve: + +* On ajoute un bit de signe (le bit de poids fort): + + ``` + 00000010: +2 + 10000010: -2 + ``` + +## Problèmes? + +. . . + +* Il y a deux zéros (pas trop grave): `10000000` et `00000000` +* Les additions différentes que pour les non-signés (très grave) + + ``` + 00000010 2 + + 10000100 + -4 + ---------- ---- + 10000110 = -6 != -2 + ``` + +# Entiers signés (2/2) + +## Beaucoup mieux + +* Complément à un: + * on inverse tous les bits: `1001 => 0110`. + +## Encore un peu mieux + +* Complément à deux: + * on inverse tous les bits, + * on ajoute 1 (on ignore les dépassements). + +. . . + +* Comment écrit-on `-4` en 8 bits? + +. . . + +``` + 4 = 00000100 + ________ + -4 => 00000100 + + 11111011 + + 00000001 + ---------- + 11111100 +``` + +# Le complément à 2 (1/2) + +## Questions: + +* Comment on écrit `+0` et `-0`? +* Comment calcule-t-on `2 + (-4)`? +* Quel est le complément à 2 de `1000 0000`? + +. . . + +## Réponses + +* Comment on écrit `+0` et `-0`? + + ``` + +0 = 00000000 + -0 = 11111111 + 00000001 = 100000000 => 00000000 + ``` +* Comment calcule-t-on `2 + (-4)`? + + ``` + 00000010 2 + + 11111100 + -4 + ---------- ----- + 11111110 -2 + ``` +* En effet + + ``` + 11111110 => 00000001 + 00000001 = 00000010 = 2. + ``` + +# Le complément à 2 (2/2) + +## Quels sont les entiers représentables en 8 bits? + +. . . + +``` +01111111 => 127 +10000000 => -128 // par définition +``` + +## Quels sont les entiers représentables sur $N$ bits? + +. . . + +$$ +-2^{N-1} ... 2^{N-1}-1. +$$ + +## Remarque: dépassement de capacité en `C` + +* Comportement indéfini! + + +# Nombres à virgule (1/3) + +## Comment manipuler des nombres à virgule? + +$$ +0.1 + 0.2 = 0.3. +$$ + +Facile non? + +. . . + +## Et ça? + +```C +#include <stdio.h> +#include <stdlib.h> +int main(int argc, char *argv[]) { + float a = atof(argv[1]); + float b = atof(argv[2]); + printf("%.10f\n", (double)(a + b)); +} +``` + +. . . + +## Que se passe-t-il donc? + +# Nombres à virgule (2/3) + +## Nombres à virgule fixe + ++-------+-------+-------+-------+-----+----------+----------+----------+----------+ +| $2^3$ | $2^2$ | $2^1$ | $2^0$ | `.` | $2^{-1}$ | $2^{-2}$ | $2^{-3}$ | $2^{-4}$ | ++-------+-------+-------+-------+-----+----------+----------+----------+----------+ +| `1` | `0` | `1` | `0` | `.` | `0` | `1` | `0` | `1` | ++-------+-------+-------+-------+-----+----------+----------+----------+----------+ + +## Qu'est-ce ça donne en décimal? + +. . . + +$$ +2^3+2^1+\frac{1}{2^2}+\frac{1}{2^4} = 8+2+0.5+0.0625=10.5625. +$$ + +## Limites de cette représentation? + +. . . + + +* Tous les nombres `> 16`. +* Tous les nombres `< 0.0625`. +* Tous les nombres dont la décimale est pas un multiple de `0.0625`. + +# Nombres à virgule (3/3) + +## Nombres à virgule fixe + +* Nombres de $0=0000.0000$ à $15.9375=1111.1111$. +* Beaucoup de "trous" (au moins $0.0625$) entre deux nombres. + +## Solution partielle? + +. . . + +* Rajouter des bits. +* Bouger la virgule. + +# Nombres à virgule flottante (1/2) + +## Notation scientifique + +* Les nombres sont représentés en terme: + * Une mantisse + * Une base + * Un exposant + +$$ +\underbrace{22.1214}_{\mbox{nombre}}=\underbrace{221214}_{\mbox{mantisse}}\cdot +{\underbrace{10}_{\mbox{base}}}{\overbrace{^{-4}}^{\mbox{exp.}}}, +$$ + +. . . + +On peut donc séparer la représentation en 2: + +* La mantisse +* L'exposant + +# Nombres à virgule flottante (2/2) + +## Quel est l'avantage? + +. . . + +On peut représenter des nombres sur énormément d'ordres de grandeur avec un +nombre de bits fixés. + +## Différence fondamentale avec la virgule fixe? + +. . . + +La précision des nombres est **variable**: + +* On a uniquement un nombre de chiffres **significatifs**. +$$ +123456\cdot 10^{23}+ 123456\cdot 10^{-23}. +$$ + +## Quel inconvénient y a-t-il? + +. . . + +Ce mélange d'échelles entraîne un **perte de précision**. + +# Nombres à virgule flottante simple précision (1/4) + +Aussi appelés *IEEE 754 single-precision binary floating point*. + +](figs/Float_example_bare.svg) + +## Spécification + +* 1 bit de signe, +* 8 bits d'exposant, +* 23 bits de mantisse. + +$$ +(-1)^{b_{31}}\cdot 2^{(b_{30}b_{29}\dots b_{23})_{2}-127}\cdot (1.b_{22}b_{21}\dots b_{0})_{2}, +$$ + +## Calculer la valeur décimale du nombre ci-dessus + +# Nombres à virgule flottante simple précision (2/4) + +](figs/Float_example.svg) + +. . . + +\begin{align} +\mbox{exposant}&=\sum_{i=0}^7 b_{23+i}2^i=2^2+2^3+2^4+2^5+2^6=124-127,\\ +\mbox{mantisse}&=1+\sum_{i=1}^{23}b_{23-i}2^{-i}=1+2^{-2}=1.25,\\ +&\Rightarrow (-1)^0\cdot 2^{-3}\cdot 1.25=0.15625 +\end{align} + +# Nombres à virgule flottante simple précision (3/4) + +## Quel nombre ne peux pas être vraiment représenté? + +. . . + +## Zéro: exception pour l'exposant + +* Si l'exposant est `00000000` (zéro) +$$ +(-1)^{\mbox{sign}}\cdot 2^{-126}\cdot 0.\mbox{mantisse}, +$$ +* Sinon si l'exposant est `00000001` à `11111110` +$$ +\mbox{valeur normale}, +$$ +* Sinon `11111111` donne `NaN`. + +# Nombres à virgule flottante simple précision (4/4) + +## Quels sont les plus petits/grands nombres positifs représentables? + +. . . + +\begin{align} +0\ 0\dots0\ 0\dots01&=2^{-126}\cdot 2^{-23}=1.4...\cdot +10^{-45},\\ +0\ 1\dots10\ 1\dots1&=2^{127}\cdot (2-2^{-23})=3.4...\cdot +10^{38}. +\end{align} + +## Combien de chiffres significatifs en décimal? + +. . . + +* 24 bits ($23 + 1$) sont utiles pour la mantisse, soit $2^{24}-1$: + * La mantisse fait $\sim2^{24}\sim 10^7$, + * Ou encore $\sim \log_{10}(2^{24})\sim 7$. +* Environ **sept** chiffres significatifs. + +# Nombres à virgule flottante double précision (64bits) + +## Spécification + +* 1 bit de signe, +* 11 bits d'exposant, +* 52 bits de mantisse. + +. . . + +## Combien de chiffres significatifs? + +* La mantisse fait $\sim 2^{53}\sim10^{16}$, +* Ou encore $\sim \log_{10}(2^{53})\sim 16$, +* Environ **seize** chiffres significatifs. + +## Plus petit/plus grand nombre représentable? + +. . . + +* Plus petite mantisse et exposant: $\sim 2^{-52}\cdot 2^{-1022}\sim 4\cdot 10^{-324}$, +* Plus grande mantisse et exposant: $\sim 2\cdot 2^{1023}\sim \cdot 1.8\cdot 10^{308}$. + +# Précision finie (1/3) + +## Erreur de représentation + +* Les nombres réels ont potentiellement un **nombre infini** de décimales + * $1/3=0.\overline{3}$, + * $\pi=3.1415926535...$. +* Les nombres à virgule flottante peuvent en représenter qu'un **nombre + fini**. + * $1/3\cong 0.33333$, erreur $0.00000\overline{3}$. + * $\pi\cong3.14159$, erreur $0.0000026535...$. + +On rencontre donc des **erreurs de représentation** ou **erreurs +d'arrondi**. + +. . . + +## Et quand on calcule? + +* Avec deux chiffres significatifs +\begin{align} +&8.9+(0.02+0.04)=8.96=9.0,\\ +&(8.9+0.02)+0.04=8.9+0.04=8.9. +\end{align} + +. . . + +## Même pas associatif! + +# Précision finie (2/3) + +## Erreur de représentation virgule flottante + +$$ +(1.2)_{10} = 1.\overline{0011}\cdot 2^0\Rightarrow 0\ 01111111\ +00110011001100110011010. +$$ +Erreur d'arrondi dans les deux derniers bits et tout ceux qui viennent +ensuite +$$ +\varepsilon_2 = (00000000000000000000011)_2. +$$ +Ou en décimal +$$ +\varepsilon_{10} = 4.76837158203125\cdot 10^{-8}. +$$ + +# Précision finie (3/3) + +## Comment définir l'égalité de 2 nombres à virgule flottante? + +. . . + +Ou en d'autres termes, pour quel $\varepsilon>0$ (appelé `epsilon-machine`) on a +$$ +1+\varepsilon = 1, +$$ +pour un nombre à virgule flottante? + +. . . + +Pour un `float` (32 bits) la différence est à +$$ +2^{-23}=1.19\cdot 10^{-7}, +$$ +Soit la précision de la mantisse. + +## Comment le mesurer (par groupe)? + +. . . + +```C +float eps = 1.0; +while ((float)1.0 + (float)0.5 * eps != (float)1.0) { + eps = (float)0.5 * eps; +} +printf("eps = %g\n", eps); +``` + +# Erreurs d'arrondi + +Et jusqu'ici on a encore pas fait d'arithmétique! + +## Multiplication avec deux chiffres significatifs, décimal + +$$ +(1.1)_{10}\cdot (1.1)_{10}=(1.21)_{10}=(1.2)_{10}. +$$ +En continuant ce petit jeu: +$$ +\underbrace{1.1\cdot 1.1\cdots 1.1}_{\mbox{10 fois}}=2.0. +$$ +Alors qu'en réalité +$$ +1.1^{10}=2.5937... +$$ +Soit une erreur de près de 1/5e! + +. . . + +## Le même phénomène se produit (à plus petite échelle) avec les `float` ou `double`. + -- GitLab