Cours – Nombres à virgule, arrondis et calcul en binaire
BTS SIO SISR 1re année – Mathématiques pour l'informatique – S02 – à lire avant les exercices
Ce que tu dois savoir déjà
- Prérequis : S01 (bases 2, 10, 16).
- Outils : Papier, calculatrice, éditeur Python intégré au site
À la fin de ce cours tu sauras
- Convertir un nombre à virgule entre les bases 10 et 2 (parties entière et fractionnaire) ;
- Reconnaître les nombres qui s'écrivent avec un nombre fini de chiffres après la virgule en base 2 ;
- Arrondir et tronquer un nombre, et majorer l'erreur commise ;
- Additionner, soustraire et multiplier des entiers en binaire, et décaler pour multiplier ou diviser par une puissance de 2 ;
- Distinguer unités décimales (ko, Mo, Go) et binaires (Kio, Mio, Gio), bits et octets, et calculer des volumes et des durées de transfert.
I. Les nombres à virgule en base 2
En base \(b\), les chiffres placés après la virgule ont pour poids les puissances négatives de \(b\) :
Exemple. \((101,011)_2 = 1\times2^{2} + 0\times2^{1} + 1\times2^{0} + 0\times2^{-1} + 1\times2^{-2} + 1\times2^{-3} = 5,375\).
Convertir la partie fractionnaire de la base 10 vers la base 2
On multiplie par 2 la partie fractionnaire, on note la partie entière obtenue (0 ou 1), puis on recommence avec la nouvelle partie fractionnaire, jusqu'à obtenir 0 ou jusqu'à la précision voulue. Les chiffres se lisent de haut en bas, après la virgule. (La partie entière du nombre, elle, se convertit par divisions successives, comme en S01.)
Exemple. Écrire \(0,8125\) en binaire.
| Multiplication par 2 | Partie entière | Partie fractionnaire restante |
|---|---|---|
| 13/16 × 2 = 13/8 | 1 | 5/8 |
| 5/8 × 2 = 5/4 | 1 | 1/4 |
| 1/4 × 2 = 1/2 | 0 | 1/2 |
| 1/2 × 2 = 1 | 1 | 0 |
Donc \(0,8125 = (0,1101)_2\). Contrôle : \(\frac{1}{2} + \frac{1}{4} + \frac{1}{16} = \frac{13}{16}\).
Exemple. \(6{,}375\) : partie entière \(6 = (110)_2\), partie fractionnaire \(0{,}375 = (0,011)_2\), donc \(6{,}375 = (110,011)_2\).
Quels décimaux ont une écriture finie en base 2 ?
Un nombre s'écrit avec un nombre fini de chiffres après la virgule en base 2 si et seulement si c'est un rationnel \(\dfrac{k}{2^m}\) (fraction irréductible dont le dénominateur est une puissance de 2). Avec \(m\) chiffres après la virgule, on atteint exactement les multiples de \(2^{-m}\).
Or \(0{,}1 = \dfrac{1}{10}\) et \(10 = 2 \times 5\) : le dénominateur contient le facteur 5, donc 0,1 n'a pas d'écriture finie en binaire. Ses chiffres se répètent :
| Multiplication par 2 | Partie entière | Partie fractionnaire restante |
|---|---|---|
| 1/10 × 2 = 1/5 | 0 | 1/5 |
| 1/5 × 2 = 2/5 | 0 | 2/5 |
| 2/5 × 2 = 4/5 | 0 | 4/5 |
| 4/5 × 2 = 8/5 | 1 | 3/5 |
| 3/5 × 2 = 6/5 | 1 | 1/5 |
| 1/5 × 2 = 2/5 | 0 | 2/5 |
| 2/5 × 2 = 4/5 | 0 | 4/5 |
| 4/5 × 2 = 8/5 | 1 | 3/5 |
Le reste fractionnaire 0,2 est revenu, donc la suite se répète : \(0{,}1 = (0{,}0\,\overline{0011})_2\), avec les quatre chiffres \(0011\) qui se répètent à l'infini. Les 16 premiers chiffres sont 0001100110011001.
II. Troncature, arrondi, erreur
Quand l'écriture est infinie ou trop longue, on garde \(p\) chiffres après la virgule :
- troncature : on supprime les chiffres suivants ;
- arrondi : on choisit la valeur à \(p\) chiffres la plus proche.
L'erreur est la distance entre la valeur exacte et la valeur retenue. En base 2 avec \(p\) chiffres après la virgule : l'erreur d'une troncature est strictement inférieure à \(2^{-p}\) ; celle d'un arrondi est au plus \(2^{-(p+1)}\).
Exemple. On tronque \(0{,}1\) à 8 chiffres binaires : \((0,00011001)_2 = \dfrac{25}{256} = 0,09765625\). L'erreur vaut \(0{,}1 - 0,09765625 = 0,00234375\), qui est bien inférieure à \(2^{-8} = 0,00390625\).
Chiffres significatifs. En décimal, on indique souvent la précision d'un résultat par son nombre de chiffres significatifs : ce sont les chiffres à partir du premier chiffre non nul en partant de la gauche, les zéros qui suivent compris. Les zéros qui ne servent qu'à placer la virgule ne comptent pas.
| Écriture | Chiffres significatifs | Arrondi à 3 chiffres significatifs |
|---|---|---|
| 0,004567 | 4 (4, 5, 6, 7) | 0,00457 |
| 12 345 | 5 | 12 300 |
| 3,14159 | 6 | 3,14 |
| 0,3040 | 4 (3, 0, 4, 0) | 0,304 |
Donner « 3,14 » pour π, c'est annoncer 3 chiffres significatifs, donc une erreur d'au plus \(0{,}005\). Les résultats d'un calcul approché ne doivent pas annoncer plus de chiffres que ce que les données permettent.
III. Les nombres « à virgule » dans un ordinateur
Un float Python est un nombre binaire à précision finie (53 chiffres binaires significatifs). La plupart des décimaux ne sont donc que des valeurs approchées :
Warning
Ne jamais tester l'égalité de deux float avec ==. On teste que l'écart est petit : abs(a - b) < 1e-9, ou math.isclose(a, b). Pour calculer exactement avec des fractions, on utilise fractions.Fraction.
Les entiers Python (int) n'ont pas de limite de taille. Dans beaucoup d'autres langages et dans les circuits, un entier est codé sur un nombre fixe de bits : on parle alors de débordement quand le résultat dépasse la capacité (§ V).
IV. Calculer en binaire
Addition
On additionne colonne par colonne en propageant la retenue :
| Somme | Résultat |
|---|---|
| \(0 + 0\) | 0 |
| \(0 + 1\) | 1 |
| \(1 + 1\) | 10 (on pose 0, retenue 1) |
| \(1 + 1 + 1\) | 11 (on pose 1, retenue 1) |
Exemple. \((1011)_2 + (0111)_2\) :
Contrôle : \(11 + 7 = 18 = (10010)_2\).
Soustraction
On soustrait colonne par colonne avec emprunt. Contrôle toujours par l'addition : \((10110)_2 - (1101)_2 = (1001)_2\), car \(10110 = 1101 + 1001\) (22 = 13 + 9).
Multiplication
Multiplier par un chiffre binaire, c'est recopier (×1) ou écrire 0 (×0), avec un décalage à chaque rang, puis additionner.
Exemple. \((1101)_2 \times (101)_2\) (13 × 5) :
1 1 0 1
× 1 0 1
---------
1 1 0 1 (× 1)
0 0 0 0 (× 0, décalé d'un rang)
1 1 0 1 (× 1, décalé de deux rangs)
---------------
1 0 0 0 0 0 1 (65)
Contrôle : \(13 \times 5 = 65 = (1000001)_2\).
Multiplier et diviser par une puissance de 2 : décaler
- Multiplier par \(2^k\) : ajouter \(k\) zéros à droite (décalage de \(k\) rangs vers la gauche). \((11001)_2 \times 2^3 = (11001000)_2\), soit \(25 \times 8 = 200\).
- Division euclidienne par \(2^k\) : supprimer les \(k\) derniers chiffres : ce qui reste est le quotient et les \(k\) chiffres supprimés forment le reste. \((11001)_2 = 25\) divisé par \(4 = 2^2\) : quotient \((110)_2 = 6\), reste \((01)_2 = 1\), car \(25 = 4 \times 6 + 1\).
En Python, x << k multiplie par \(2^k\), x >> k donne le quotient de la division par \(2^k\) et x & (2**k - 1) donne le reste.
V. Capacité limitée et débordement
Sur \(n\) bits, un entier naturel est compris entre 0 et \(2^n - 1\). Si le résultat d'une addition dépasse \(2^n - 1\), le bit de retenue en trop est perdu : le résultat obtenu est le reste de la division par \(2^n\).
Exemple (8 bits). \(200 + 100 = 300\) dépasse \(255\). Le circuit conserve \(300 - 256 = 44\), c'est-à-dire \((00101100)_2\).
Pour aller plus loin : les entiers relatifs (complément à deux)
Pour représenter des entiers relatifs sur \(n\) bits, on utilise le complément à deux : un nombre négatif \(-x\) est codé par l'entier naturel \(2^n - x\). Sur 8 bits, on représente les entiers de \(-128\) à \(127\).
Exemple. \(-5\) sur 8 bits : \(256 - 5 = 251 = (11111011)_2\). Même résultat avec la règle pratique : on écrit 5 = \(00000101\), on inverse tous les bits (\(11111010\)), puis on ajoute 1 (\(11111011\)). Le premier bit vaut 1 pour un nombre négatif.
Note
Cette sous-section prolonge le cours (entiers relatifs) ; elle n'est pas nécessaire pour la suite.
VI. Unités : bits, octets et préfixes
Un octet (o) vaut 8 bits (b). Les tailles de données se donnent en octets, les débits en bits par seconde.
| Préfixe décimal (SI) | Valeur | Préfixe binaire (CEI) | Valeur |
|---|---|---|---|
| ko (kilooctet) | \(10^3\) o | Kio (kibioctet) | \(2^{10} = 1024\) o |
| Mo (mégaoctet) | \(10^6\) o | Mio (mébioctet) | \(2^{20} = 1 048 576\) o |
| Go (gigaoctet) | \(10^9\) o | Gio (gibioctet) | \(2^{30} = 1 073 741 824\) o |
| To (téraoctet) | \(10^{12}\) o | Tio (tébioctet) | \(2^{40} = 1 099 511 627 776\) o |
Warning
Ne pas confondre Go et Gio. Un disque annoncé « 500 Go » contient \(500 \times 10^9\) octets, soit \(\dfrac{500 \times 10^9}{2^{30}} \approx 465,66\) Gio : c'est cette dernière valeur que certains systèmes affichent (parfois en l'appelant « Go »).
Débit et durée. Un débit de \(100\) Mbit/s correspond à \(\dfrac{100 \times 10^6}{8} = 12,5\) Mo/s. Pour transférer un fichier de \(2\) Go (\(2 \times 10^9\) o) à ce débit, la durée théorique, sans tenir compte des protocoles, est
À retenir
- Après la virgule, les poids sont \(2^{-1}, 2^{-2}, \dots\) ; on convertit la partie fractionnaire en la multipliant par 2 à répétition.
- Un nombre est exact en binaire si et seulement s'il s'écrit \(\dfrac{k}{2^m}\) : 0,1 ne l'est pas, d'où \(0{,}1 + 0{,}2 \ne 0{,}3\) en
float. - Troncature à \(p\) chiffres binaires : erreur \(< 2^{-p}\) ; arrondi : erreur \(\le 2^{-(p+1)}\).
- Multiplier ou diviser par \(2^k\) = décaler de \(k\) rangs.
- Sur \(n\) bits, on perd la retenue au-delà de \(2^n - 1\) : résultat modulo \(2^n\).
- 1 octet = 8 bits ; ko, Mo, Go (puissances de 10) ≠ Kio, Mio, Gio (puissances de 2).