3-01. Représentation de l’information
Dans ce chapitre, nous allons découvrir comment les données sont stockées et manipulées dans la mémoire d’un ordinateur. Tout commence par la base du numérique : les nombres, du binaire de la machine à l’hexadécimal des développeurs.
Entiers positifs
- Comprendre le principe de la numération de position.
- Passer d’une base à une autre (bases 2, 10 et 16).
- Comprendre les notions de bit, d’octet et de quartet.
- Manipuler les différentes bases de numération en Python.
Pourquoi plusieurs bases de numération ?
Au quotidien, on compte en base 10 (système décimal). Pourquoi ? Tout simplement parce qu’on a 10 doigts ! On utilise donc 10 symboles (les chiffres de 0 à 9) et, dès qu’on dépasse 9, on crée une nouvelle « retenue » (les dizaines, les centaines, etc.).
Mais les ordinateurs n’ont pas de doigts. Ils sont constitués de milliards de micro-composants électroniques (les transistors) qui ne connaissent que deux états physiques :
- Passant : noté
1(allumé) ; - Bloquant : noté
0(éteint).
L’ordinateur compte donc naturellement en base 2 (système binaire). L’unité minimale d’information en informatique s’appelle un bit (contraction de binary digit, soit « chiffre binaire »). Un bit ne peut valoir que 0 ou 1.
💡 Bit vs octet :
- Un bit est la plus petite unité (
0ou1). - Un octet (byte en anglais) est un regroupement de 8 bits (par exemple
10110100). C’est l’unité de mesure standard de la mémoire informatique.
💡 Le saviez-vous ?
La base 10 n’est pas la seule base humaine ! Certaines civilisations de l’Antiquité (comme les Sumériens) utilisaient la base 12 (système duodécimal). En effet, si vous utilisez le pouce d’une main comme pointeur, vous pouvez compter les 12 phalanges des 4 autres doigts ! C’est de cet héritage antique que viennent nos journées de 24 heures (2 × 12 heures).
Travailler uniquement avec des suites de 0 et de 1 (comme 110101101011) devient très vite illisible pour nous, humains. C’est pour ça que les informaticiens utilisent la base 16 (système hexadécimal) comme une écriture « condensée » et pratique du binaire.
Comprendre la numération de position
Avant d’étudier le binaire et l’hexadécimal, décomposons la manière dont nous écrivons les nombres en base 10. C’est ce qu’on appelle la numération de position : la valeur d’un chiffre dépend de sa position dans le nombre.
Prenons le nombre 2026 en base 10 :
| Position (rang) | 3 | 2 | 1 | 0 |
|---|---|---|---|---|
| Poids de la colonne | 103 = 1000 | 102 = 100 | 101 = 10 | 100 = 1 |
| Chiffre | 2 | 0 | 2 | 6 |
Ce nombre vaut donc : 2×1000 + 0×100 + 2×10 + 6×1 = 2026.
🖐️ Dans n’importe quelle base $*b*$ :
- On dispose de $*b*$ symboles différents (de 0 à $*b*$-1).
- Les poids des colonnes sont les puissances successives de la base : $*b*$0, $*b*$1, $*b*$2, $*b*$3, etc., en partant de la droite.
La base 2 : le binaire
En base 2, on n’a que deux symboles : 0 et 1. Les poids des colonnes sont les puissances de 2 : 20 = 1, 21 = 2, 22 = 4, 23 = 8, 24 = 16, 25 = 32, 26 = 64, 27 = 128, etc.
💡Il est très utile d’apprendre par cœur les premières puissances de 2 : 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024… (chaque nombre est simplement le double du précédent !).
A. Conversion du binaire vers le décimal
Pour connaître la valeur en décimal d’un nombre binaire, il suffit d’additionner les poids des colonnes qui contiennent un 1.
Exemple 1 : Convertir le nombre binaire (1011)2 en décimal.
| Puissance de 2 | 23 = 8 | 22 = 4 | 21 = 2 | 20 = 1 |
|---|---|---|---|---|
| Bit | 1 | 0 | 1 | 1 |
| Calcul | 1×8 | 0×4 | 1×2 | 1×1 |
Calcul : 8 + 0 + 2 + 1 = 11. Donc (1011)2 = (11)10.
Exemple 2 : Convertir l’octet (11001010)2 en décimal.
| Poids | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|
| Bit | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
Calcul : 128 + 64 + 8 + 2 = 202. Donc (11001010)2 = (202)10.
B. Conversion du décimal vers le binaire
Il existe deux méthodes pour effectuer cette conversion.
Méthode 1 : La méthode des soustractions
C’est la méthode la plus rapide de tête pour les petits nombres.
Soit à convertir 45 en binaire :
-
Quelle est la plus grande puissance de 2 inférieure ou égale à 45 ? C’est 32. On met un
1sous 32.
Il reste 45 − 32 = 13. - Dans 13, peut-on caser 16 ? Non → on met un
0sous 16. -
Dans 13, peut-on caser 8 ? Oui → on met un
1sous 8.
Il reste 13 − 8 = 5. -
Dans 5, peut-on caser 4 ? Oui → on met un
1sous 4.
Il reste 5 − 4 = 1. - Dans 1, peut-on caser 2 ? Non → on met un
0sous 2. -
Dans 1, peut-on caser 1 ? Oui → on met un
1sous 1.
Il reste 0. Fin !
Résultat : 45 = 32 + 8 + 4 + 1 ⇒ (45)10 = (101101)2.
Méthode 2 : Les divisions successives par 2
C’est la méthode systématique, idéale pour les algorithmes ou les grands nombres.
On divise le nombre par 2 répétitivement et on conserve les restes de la division euclidienne jusqu’à obtenir un quotient égal à 0. On lit ensuite les restes de bas en haut (du dernier au premier).
Convertissons 45 avec cette méthode :
- 45 ÷ 2 = 22, reste 1 (bit de poids faible)
- 22 ÷ 2 = 11, reste 0
- 11 ÷ 2 = 5, reste 1
- 5 ÷ 2 = 2, reste 1
- 2 ÷ 2 = 1, reste 0
- 1 ÷ 2 = 0, reste 1 (bit de poids fort)
En lisant les restes du bas vers le haut, on retrouve bien : (101101)2.
La base 16 : l’hexadécimal
En base 16, il nous faut 16 symboles. Les chiffres de 0 à 9 ne suffisent plus ! On utilise donc les lettres de A à F pour représenter les valeurs de 10 à 15 :
| Décimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Hexadécimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
Le lien entre binaire et hexadécimal
Puisque 16 = 24, un chiffre hexadécimal correspond exactement à un paquet de 4 bits.
💡 Un octet (8 bits) s’écrit donc toujours très simplement avec exactement 2 chiffres hexadécimaux ! Par exemple, 11111111 en binaire vaut FF en hexadécimal.
A. Conversion binaire ↔ hexadécimal
Pour convertir un nombre binaire en hexadécimal :
- On découpe le nombre binaire par paquets de 4 bits en partant de la droite.
- On convertit chaque paquet de 4 bits en son chiffre hexadécimal correspondant.
Exemple : Convertir (11010110)2 en hexadécimal.
- On découpe en 2 quartets :
1101et0110. - (1101)2 = 8 + 4 + 1 = 13 ⇒ en hexadécimal, c’est D.
- (0110)2 = 4 + 2 = 6 ⇒ en hexadécimal, c’est 6.
Résultat : (11010110)2 = (D6)16.
B. Convertir de l’hexadécimal vers le décimal
Les poids des colonnes en hexadécimal sont les puissances de 16 : 160 = 1, 161 = 16, 162 = 256, etc.
Exemple : Convertir (2F)16 en décimal.
- Le chiffre
2est au rang 1 (poids 16) : 2×16 = 32. - Le chiffre
F(qui vaut 15) est au rang 0 (poids 1) : 15×1 = 15.
Résultat : 32 + 15 = 47. Donc (2F)16 = (47)10.
Les bases de numération en Python
Python sait manipuler nativement les nombres écrits dans différentes bases. Par défaut, tous les nombres affichés par Python le sont en base 10, mais on peut lui spécifier la base lors de la saisie d’une valeur en utilisant un préfixe :
- Préfixe
0bpour le binaire (ex:0b1011) - Préfixe
0xpour l’hexadécimal (ex:0xA3)
a = 0b1011 # Saisie en binaire (vaut 11 en décimal)
b = 0xA3 # Saisie en hexadécimal (vaut 163 en décimal)
print(a) # Affiche 11 (Python convertit automatiquement en décimal)
print(b) # Affiche 163
print(a + b) # Affiche 174 (11 + 163)
Fonctions de conversion en Python
Python fournit des fonctions intégrées pour convertir un entier vers une chaîne de caractères représentée dans une autre base, ou vice-versa :
| Fonction / Instruction | Rôle | Exemple | Résultat |
|---|---|---|---|
bin(n) |
Convertit un entier n en chaîne binaire |
bin(13) |
"0b1101" |
hex(n) |
Convertit un entier n en chaîne hexadécimale |
hex(255) |
"0xff" |
int(texte, base) |
Convertit du texte exprimé dans une base vers un entier décimal |
int("1011", 2)int("A3", 16)
|
11163
|
# Passer du décimal vers le binaire/hexa :
nombre = 42
print(bin(nombre)) # "0b101010"
print(hex(nombre)) # "0x2a"
# Passer d’une chaîne binaire ou hexa vers un nombre entier :
valeur_bin = int("1101", 2) # 13
valeur_hex = int("FF", 16) # 255
print(valeur_bin + valeur_hex) # 268
Conversions binaire ↔ décimal
1. Quel est le plus grand nombre entier en base 10 qui puisse être exprimé en un octet ?
2. Convertir les nombres binaires suivants en base 10 (décimal) :
- a = (00001101)2
- b = (10000001)2
- c = (11111111)2
3. Convertir les nombres décimaux suivants en binaire sur un octet (8 bits) :
- x = 25
- y = 100
- z = 180
Correction
1. 28 + 27 + 26 + 24 + 23 + 22 + 21 + 20 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255
2. Binaire vers décimal :
- (00001101)2 = 8 + 4 + 1 = 13
- (10000001)2 = 128 + 1 = 129
- (11111111)2 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 (valeur maximale d’un octet !)
3. Décimal vers binaire :
- 25 = 16 + 8 + 1 → (00011001)2
- 100 = 64 + 32 + 4 → (01100100)2
- 180 = 128 + 32 + 16 + 4 → (10110100)2
Hexadécimal et couleurs
En informatique, les couleurs sont représentées en code hexadécimal sous la forme #RRGGBB, où :
RRest la quantité de rouge (sur un octet, de 00 à FF) ;GGest la quantité de vert (sur un octet, de 00 à FF) ;BBest la quantité de bleu (sur un octet, de 00 à FF).
1. Convertir les paires hexadécimales suivantes en valeurs décimales (de 0 à 255) :
- 00
- 80
- FF
- A0
2. Soit une couleur définie par #FF8000 (du orange). Donnez ses composantes Rouge, Vert et Bleu sous forme de valeurs décimales compris entre 0 et 255.
3. Convertir le nombre binaire (110110101111)2 directement en hexadécimal en utilisant la méthode des quartets.
Correction
1. Hexadécimal vers décimal :
00= 0 × 16 + 0 = 080= 8 × 16 + 0 = 128FF= 15 × 16 + 15 = 255A0= 10 × 16 + 0 = 160
2. Couleur #FF8000 :
- Rouge (
FF) = 255 - Vert (
80) = 128 - Bleu (
00) = 0
3. Binaire vers hexadécimal par quartets :
On découpe 110110101111 en quartets : 1101.1010.1111
- (
1101)2 = 8 + 4 + 1 = 13 → D - (
1010)2 = 8 + 2 = 10 → A - (
1111)2 = 8 + 4 + 2 + 1 = 15 → F
Résultat : (DAF)16 ou 0xDAF.
Manipulations en Python
1. Sans exécuter le code dans un éditeur, déterminez ce qu’affichent les instructions suivantes :
a = 0b101
b = 0x10
print(a + b)
2. Écrivez une ligne de code Python qui prend la chaîne de caractères "10110" (en binaire) et affiche son équivalent sous forme de chaîne de caractères en hexadécimal (indice : combinez hex() et int()).
Correction
1. Résultat des instructions
a = 0b101vaut 4 + 1 = 5 en décimal.b = 0x10vaut 1×16 + 0 = 16 en décimal.print(a + b)affiche21(car 5 + 16 = 21).
2. Conversion binaire ⟶ hexadécimal
print(hex(int("10110", 2))) # Affiche ’0x16’
Explication : int("10110", 2) convertit la chaîne binaire en l’entier décimal 22, puis hex(22) renvoie la chaîne hexadécimale ’0x16’.
Entiers relatifs
- Évaluer le nombre de bits nécessaires à l’écriture en binaire d’un entier, d'une somme et d'un produit.
- Comprendre le codage des entiers relatifs avec le complément à 2.
- Connaître les tailles courantes d'entiers (8, 16, 32 et 64 bits) et la spécificité de Python.
Taille des entiers en mémoire (champs de bits fixes)
Dans la section précédente, nous avons écrit des nombres binaires avec autant de bits que nécessaire. Mais dans un ordinateur réel, la mémoire physique est organisée en « cases » de tailles fixes. Les tailles les plus fréquentes sont :
- 8 bits (1 octet) ;
- 16 bits (2 octets) ;
- 32 bits (4 octets) ;
- 64 bits (8 octets).
Quand on réserve un emplacement mémoire de $*n*$ bits pour un entier non signé (positif ou nul), on dispose de 2$*n*$ combinaisons possibles, permettant de coder tous les entiers de 0 à 2$*n*$ − 1.
| Taille | Nombre de combinaisons (2$*n*$) | Intervalle (non signé) |
|---|---|---|
| 8 bits | 28 = 256 | 0 à 255 |
| 16 bits | 216 = 65 536 | 0 à 65 535 |
| 32 bits | 232 ≈ 4,29 × 109 | 0 à 4 294 967 295 |
| 64 bits | 264 ≈ 1,84 × 1019 | 0 à 18 446 744 073 709 551 615 |
💡 Anectode de jeu vidéo (L'overflow) :
Dans les jeux rétro (comme Pac-Man ou Pokémon), le niveau ou les statistiques étaient souvent codés sur 8 bits (max 255). Au niveau 256 de Pac-Man, 255 + 1 provoquait un dépassement de mémoire (overflow), remettant le compteur à 0 et corrompant l’affichage du jeu !
Évaluer le nombre de bits nécessaires
A. Pour un entier $*N*$
Pour coder un entier positif $*N*$ en binaire, il faut trouver le plus petit nombre de bits $*k*$ tel que $*N*$ < 2$*k*$. En d’autres termes, le nombre de bits $*k*$ est tel que 2$*k*$-1 ≤ $*N*$ < 2$*k*$.
Exemple : Pour coder $*N*$ = 200 :
- 27 = 128 (trop petit)
- 28 = 256 (suffisant car 200 < 256)
Il faut donc 8 bits pour représenter 200.
B. Pour une somme ($*A*$ + $*B*$)
Si un entier $*A*$ nécessite $*k*$ bits et un entier $*B*$ nécessite $*p*$ bits (avec $*k*$ ≥ $*p*$), la somme $*A*$ + $*B*$ nécessite au plus $*k*$ + 1 bits (un bit de plus pour gérer la retenue finale).
Exemple : $*A*$ = 200 (8 bits) et $*B*$ = 150 (8 bits). $*A*$ + $*B*$ = 350. Comme 350 < 29 = 512, il faut 9 bits.
C. Pour un produit ($*A*$ × $*B*$)
Si un entier $*A*$ s'écrit sur $*k*$ bits et $*B*$ sur $*p*$ bits, leur produit $*A*$ × $*B*$ nécessite au plus $*k*$ + $*p*$ bits.
Exemple : $*A*$ = 15 (11112 → 4 bits) et $*B*$ = 12 (11002 → 4 bits). $*A*$ × $*B*$ = 180. Comme 180 < 28 = 256, il faut 4 + 4 = 8 bits.
Le cas particulier de Python : entiers de taille arbitraire
Dans la plupart des langages de programmation traditionnels (C, C++, Java), les variables ont une taille fixe dans la mémoire (32 ou 64 bits). Si le résultat d'un calcul dépasse cette taille, le nombre recommence à zéro ou provoque une erreur.
Python est différent ! Il gère automatiquement les entiers de taille arbitraire. Tant que votre ordinateur a de la mémoire RAM disponible, Python agrandit la taille mémoire du nombre au fur et à mesure qu'il grandit. On peut donc calculer 21000 sans aucun problème de dépassement !
Représentation des entiers négatifs : le complément à 2
Un ordinateur ne dispose ni d'un signe « − », ni d'un signe « + ». Il ne connaît que des 0 et des 1. Comment représenter un nombre négatif comme −5 dans une case mémoire de $*n*$ bits ?
Pourquoi la méthode « naïve » ne marche pas
L'idée la plus simple consisterait à réserver le premier bit (celui tout à gauche) pour le signe (0 pour +, 1 pour −). Mais cette méthode pose deux gros problèmes :
- Elle crée deux représentations pour zéro : un « +0 » et un « −0 », ce qui fait gaspiller une combinaison.
- Les opérations mathématiques de base ne fonctionnent plus ! Additionner +5 et −5 ne donnerait pas 0.
La solution universelle : le complément à 2
En informatique, les entiers signés (positifs ou négatifs) sont codés selon la méthode du complément à 2.
⚙️ Algorithme pour coder un entier négatif −$*X*$ sur $*n*$ bits :
- Écrire la valeur absolue +$*X*$ en binaire sur $*n*$ bits (en rajoutant les
0inutiles à gauche). - Inverser tous les bits : changer tous les
0en1et tous les1en0. (C'est le complément à 1). - Ajouter 1 au résultat binaire obtenu. (C'est le complément à 2).
Exemple pas à pas : Coder le nombre −5 sur 8 bits (1 octet).
- On écrit +5 sur 8 bits :
0000 0101 - On inverse tous les bits :
1111 1010 - On ajoute 1 :
1111 1010+ 1 =1111 1011
Ainsi, en complément à 2 sur 8 bits, −5 s'écrit 1111 1011.
Comprendre le poids du premier bit
Dans un codage en complément à 2 sur $*n*$ bits, le premier bit à gauche (bit de poids fort) a un rôle particulier :
- S'il vaut
0, le nombre est positif ou nul. - S'il vaut
1, le nombre est négatif. Son poids n'est pas +2$*n*$-1, mais −2$*n*$-1 !
Vérifions notre exemple 1111 1011 sur 8 bits :
| Poids | -128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|
| Bit | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
Calcul : −128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = −5.
Intervalle de valeurs pour $*n*$ bits signés
Sur $*n*$ bits signés en complément à 2, les valeurs représentables vont de −2$*n*$-1 à +2$*n*$-1 − 1.
Par exemple, sur 8 bits signés :
- Le plus grand positif est
0111 1111= +127 - Le plus petit négatif est
1000 0000= −128
💡 Pourquoi la soustraction devient une simple addition :
Le grand avantage du complément à 2 est que le processeur n'a pas besoin de circuit spécial pour la soustraction ! Effectuer 5 − 5, c'est faire 5 + (−5) :
0000 0101 (+5)
+ 1111 1011 (-5)
------------------
1 0000 0000 (= 0 sur 8 bits, le 9e bit de retenue tout à gauche est ignoré !)
Taille en bits d'une somme et d'un produit
1. Quel est le nombre minimal de bits nécessaires pour représenter le nombre décimal 150 ?
2. On considère deux entiers $*A*$ = 100 et $*B*$ = 200.
- Sur combien de bits faut-il coder $*A*$ et $*B*$ individuellement ?
- Sur combien de bits faut-il coder la somme $*A*$ + $*B*$ ?
- Sur combien de bits faut-il coder le produit $*A*$ × $*B*$ ?
Correction
1. 150 < 28 = 256. Il faut 8 bits (1 octet).
2.
- $*A*$ = 100 < 128 → 7 bits. $*B*$ = 200 < 256 → 8 bits.
- $*A*$ + $*B*$ = 300. 300 < 29 = 512 → 9 bits.
- $*A*$ × $*B*$ = 20 000. 20 000 < 215 = 32 768 → 15 bits (au plus 7 + 8 = 15 bits).
Codage en complément à 2 sur 8 bits
1. Donner le codage binaire en complément à 2 sur 8 bits des entiers suivants :
- $*A*$ = +18
- $*B*$ = −18
- $*C*$ = −1
- $*D*$ = −128
2. Retrouver la valeur décimale des deux octets signés suivants (codés en complément à 2) :
E = 0101 0000F = 1111 0000
Correction
1. Codage sur 8 bits :
- $*A*$ = +18 : 18 = 16 + 2 →
0001 0010(positif, donc écriture directe). - $*B*$ = −18 :
1. +18 →0001 0010
2. Inversion →1110 1101
3. +1 →1110 1110 - $*C*$ = −1 :
1. +1 →0000 0001
2. Inversion →1111 1110
3. +1 →1111 1111(tous les bits à 1 valent −1). - $*D*$ = −128 : C'est la limite minimale sur 8 bits signés →
1000 0000(car −128 + 0 = −128).
2. Décodage d'octets signés :
E = 0101 0000: Le premier bit est0, donc c'est un nombre positif.
Calcul : 64 + 16 = +80.F = 1111 0000: Le premier bit est1, donc c'est un nombre négatif.
Calcul avec poids du bit fort : −128 + 64 + 32 + 16 = −16.
Autre méthode : Inverser les bits (0000 1111) + 1 (0001 0000= 16), donc le nombre vaut −16.
Nombres réels et nombres flottants
- Comprendre le principe de la représentation binaire des réels (puissances négatives de 2).
- Calculer la représentation binaire de réels simples (0,5 ; 0,25 ; 0,75…).
- Comprendre pourquoi certains nombres réels comme 0,1 n'ont pas d’écriture binaire exacte.
- Comprendre les conséquences pratiques en programmation (erreurs d'arrondi et comparaison de flottants).
L'infini dans une mémoire finie
Pour les entiers, les choses sont simples : entre 0 et 10, il n'y a qu'un nombre fini d'entiers (11 exactement). Mais pour les nombres réels (les nombres à virgule), c'est une autre histoire : entre 0 et 1, il existe une infinité de nombres réels (0,1 ; 0,15 ; 0,0001 ;…)
Un ordinateur possédant une mémoire finie, il est physiquement impossible de stocker toutes les valeurs réelles possibles. L'ordinateur va donc devoir stocker la plupart de ces nombres sous forme approximative. On appelle ces nombres des flottants (floats en anglais).
La virgule en binaire (puissances négatives de 2)
En décimal, les chiffres situés après la virgule représentent les dixièmes (10−1 = 0,1), les centièmes (10−2 = 0,01), les millièmes (10−3 = 0,001), etc.
En binaire, c'est le même principe ! Les chiffres après la virgule correspondent aux puissances négatives de 2 :
| Rang après la virgule | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| Puissance de 2 | 2−1 | 2−2 | 2−3 | 2−4 |
| Valeur décimale | 0,5 (1/2) | 0,25 (1/4) | 0,125 (1/8) | 0,0625 (1/16) |
Pour trouver la valeur d'un nombre binaire à virgule, on additionne simplement ses poids :
- (0,1)2 = 1 × 0,5 = 0,5
- (0,01)2 = 0 × 0,5 + 1 × 0,25 = 0,25
- (0,11)2 = 0,5 + 0,25 = 0,75
- (10,101)2 = 2 + 0,5 + 0,125 = 2,625
Les nombres « infinis »
En base 10, nous savons tous que la fraction 1/3 ne « tombe pas juste » : 1/3 = 0,333333… avec une infinité de 3. On ne peut pas l'écrire exactement avec un nombre fini de chiffres décimaux.
En binaire, c'est exactement la même chose pour certaines fractions. Un nombre décimal ne possède une écriture binaire exacte que s'il s'exprime comme une somme finie de puissances négatives de 2.
Prenons le nombre 0,1 (c'est-à-dire 1/10). Si on essaie de le convertir en binaire :
(0,1)10 = (0,00011001100110011…)2 (la suite 0011 se répète à l'infini !)
Le nombre 0,1 (pourtant tout simple en décimal) a une écriture infinie en binaire ! Comme l'ordinateur ne peut pas stocker une infinité de bits, il doit couper le nombre.
Résultat : 0,1 n'est pas stocké exactement comme 0,1 dans la mémoire de votre ordinateur !
Comment la mémoire stocke-t-elle un « flottant » ?
Je ne comprends pas, commet l’ordinateur peut écrire 0,001101 ? Vous avez dit qu’il ne peut pas stocker la virgule… 🤔.
C’est vrai ! Dans la mémoire de l'ordinateur, il n'existe pas de caractère « point » ou « virgule », ni de signe « − ». Il n'y a que des 0 et des 1. Pour stocker un nombre réel sur 64 bits (norme courante des ordinateurs), la mémoire utilise la notation scientifique binaire (par exemple 1,101-10) et découpe la case mémoire en 3 zones fixes :
| Signe (1 bit) | Exposant (11 bits) | Mantisse (52 bits) |
|---|---|---|
| 0 = Positif 1 = Négatif |
Déplace la virgule vers la gauche ou la droite selon son signe. | Les chiffres significatifs situés après le « 1, » (implicite) |
L'ordinateur n'a donc pas besoin de stocker le symbole de la virgule : la position de la virgule est calculée dynamiquement grâce à l'exposant (elle « flotte », d'où le nom de flottant). Et si la suite de bits est infinie (comme pour 0,1), la mantisse se remplit jusqu'au 52e bit et coupe sauvagement le reste, créant une infime erreur d'arrondi.
Les conséquences concrètes en Python
Cette légère imprécision a des conséquences directes très célèbres en programmation. Ouvrez une console Python et tapez :
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
Puisque 0,1 et 0,2 sont stockés avec de minuscules erreurs d'arrondi en binaire, leur somme donne 0.30000000000000004 et non pas exactement 0.3 !
⛔ Ne testez JAMAIS l'égalité stricte (==) entre deux nombres flottants ! En raison des erreurs d'arrondi, deux calculs censés donner le même résultat réel peuvent différer d'une infime fraction et rendre le test faux.
Comment comparer correctement deux flottants en Python ?
Pour vérifier si deux flottants a et b sont "égaux", on teste si la valeur absolue de leur différence est extrêmement petite (inférieure à un seuil de tolérance $*\epsilon*$, par exemple 10−9) :
a = 0.1 + 0.2
b = 0.3
# ❌ Mauvaise méthode :
if a == b:
print("Égaux") # Ne s'exécutera PAS !
# ✅ Bonne méthode (test de tolérance) :
if abs(a - b) < 1e-9:
print("Les nombres sont égaux à la tolérance près !")
# ✅ Variante avec le module math de Python :
import math
if math.isclose(a, b):
print("Les nombres sont très proches !")
Conversion de réels simples en binaire
1. Convertir les nombres décimaux suivants en écriture binaire à virgule :
- A = 0,5
- B = 0,25
- C = 0,875
- D = 3,5
2. Donnez la valeur décimale exacte du nombre binaire (11,01)2.
Correction
1. Conversions en binaire :
- A = 0,5 : 0,5 = 2-1 ⟶
(0,1)₂ - B = 0,25 : 0,25 = 2-2 ⟶
(0,01)₂ - C = 0,875 : 0,875 = 0,5 + 0,25 + 0,125 = 2-1 + 2-2 + 2-3 ⟶
(0,111)₂ - D = 3,5 : 3 = (11)2 et 0,5 = (0,1)2 ⟶
(11,1)₂
2. Valeur décimale de (11,01)2 :
Partie entière : (11)2 = 2 + 1 = 3.
Partie fractionnaire : (0,01)2 = 0 × 0,5 + 1 × 0,25 = 0,25.
Résultat : 3 + 0,25 = 3,25.
Boucle infinie avec les flottants
Observez attentivement le programme Python suivant :
x = 0.0
while x != 1.0:
print(x)
x = x + 0.1
1. Pourquoi ce programme risque-t-il de tourner en boucle infinie au lieu de s'arrêter lorsque x atteint 1.0 ?
2. Proposez une modification simple de la condition du while pour sécuriser l'arrêt de la boucle.
Correction
1. Explication du piège :
À cause des erreurs d'arrondi répétées lors des additions de 0.1 en binaire, la variable x ne va jamais valoir exactement 1.0 (elle va par exemple valoir 0.9999999999999999 puis sauter directement à 1.0999999999999999). La condition x != 1.0 restera donc toujours vraie (True) et la boucle ne s'arrêtera jamais !
2. Correction du code :
Au lieu de tester l'inégalité stricte avec !=, on utilise une inégalité < :
x = 0.0
while x < 1.0: # Se termine dès que x dépasse 1.0
print(x)
x = x + 0.1