Vue d'ensemble
Une machine ne connaît que des 0 et des 1. Pour qu'un ordinateur manipule le nombre ou le nombre , il faut d'abord le coder avec des bits. Ce chapitre explique comment : les entiers en base 2, les entiers négatifs par complément à deux, et pourquoi les nombres à virgule (les flottants) réservent des surprises — au point que 0.1 + 0.2 ne vaut pas 0.3 pour l'ordinateur.
Prérequis
- Variables, types et affectations (types
intetfloat). - Boucles
foretwhile. - Les puissances de 2 :
La représentation des nombres piège tout le monde en début de prépa. Comprendre vraiment pourquoi 0.1+0.2 échoue vous évitera des heures de bugs incompréhensibles ; nos mentors alumni X · Centrale · Mines vous font manipuler ces notions jusqu'au réflexe.
Les entiers naturels en base 2
En base 10, l'écriture signifie . En base 2, on n'utilise que les chiffres 0 et 1, et chaque position vaut une puissance de 2. De droite à gauche, les poids sont .
Ainsi .
Convertir un entier décimal en binaire
Méthode par les poids : on parcourt les poids du plus grand au plus petit ; à chaque poids, on regarde s'il « tient » dans ce qu'il reste. Traçons-la sur .
| Poids testé | Poids ≤ reste ? | Bit | Reste après |
|---|---|---|---|
| 8 | 13 ≥ 8 → oui | 1 | 13 − 8 = 5 |
| 4 | 5 ≥ 4 → oui | 1 | 5 − 4 = 1 |
| 2 | 1 ≥ 2 → non | 0 | 1 |
| 1 | 1 ≥ 1 → oui | 1 | 0 → fini, 1101 ✓ |
En lisant la colonne « Bit » de haut en bas : .
- Lister les poids jusqu'au plus grand nombre.
- Du plus grand poids au plus petit : si le poids reste, écrire un 1 et soustraire ce poids ; sinon écrire un 0.
- Le binaire est la suite des bits, du premier écrit (poids fort) au dernier (poids faible).
En Python : bin() et int()
Python fournit deux outils tout prêts pour passer d'une écriture à l'autre.
print(bin(13)) # decimal -> binaire
print(int("1101", 2)) # binaire (texte) -> decimal
print(bin(6)) # autre exemplebin(13)Renvoie la chaîne '0b1101'. Le préfixe 0b signale « ceci est écrit en base 2 » ; les chiffres utiles sont 1101. C'est bien notre .int("1101", 2)L'inverse : on donne une chaîne de bits et la base (2), Python renvoie l'entier décimal 13. Le deuxième argument est indispensable : sans lui, int("1101") lirait treize-cent-un en base 10.bin(6)Affiche '0b110', car . Remarquez que le bit de poids faible est 0 : 6 est pair.Sortie exacte de ce programme :
0b1101
13
0b110Les entiers relatifs : le complément à deux
Les bits ne « connaissent » pas le signe moins. Sur une machine à taille fixe (un registre de bits), on adopte donc une convention : le complément à deux. Elle a un immense avantage : l'addition des négatifs se fait avec le même circuit que celle des positifs.
Exemple sur 8 bits : coder . On calcule , puis on écrit en binaire sur 8 bits.
n = 8
x = 5
code = (2**n - x) % (2**n) # 256 - 5 = 251
print(format(code, "08b")) # ecrit 251 sur 8 bitsn = 8 ; x = 5On travaille sur 8 bits et on veut coder , donc .(2**n - x) % (2**n)Le cœur du complément à deux : . Le % (2**n) ramène le résultat dans (utile quand , où l'on veut 0 et non 256).format(code, "08b")Convertit 251 en binaire sur exactement 8 caractères (le 08 complète avec des zéros à gauche). Résultat : 11111011.Sortie : 11111011. Le bit de poids fort vaut 1 : c'est bien un nombre négatif. Vérification : , et .
Le débordement (overflow)
Sur taille fixe, dépasser la borne haute fait « repartir » du bas : c'est le débordement. Sur 8 bits, ajouter 1 à (soit ) donne , qui vaut en complément à deux — un positif est devenu négatif ! C'est un bug classique en langage C.
int) sont de taille arbitraire : ils grandissent tant qu'il reste de la mémoire. 2**100 se calcule sans problème. Le complément à deux et le débordement décrits ici concernent les entiers de taille fixe du processeur (et des langages comme C, Java). Connaître ces notions reste au programme, car elles expliquent le comportement du matériel.Les nombres à virgule : les flottants
Pour représenter ou , l'ordinateur utilise des flottants (type float), codés selon la norme IEEE 754. Idée (présentation simplifiée) : un flottant s'écrit
un peu comme la notation scientifique , mais en base 2. La mantisse a un nombre fini de bits : c'est là que naissent tous les problèmes.
Le piège central : 0.1 + 0.2
print(0.1 + 0.2) # la somme affichee
print(0.1 + 0.2 == 0.3) # le test d'egalite0.1 + 0.20.1 et 0.2 sont déjà stockés arrondis. Leur somme cumule les petites erreurs et donne 0.30000000000000004 — pas tout à fait .0.1 + 0.2 == 0.3À gauche, 0.30000000000000004 ; à droite, le flottant stocké pour 0.3, qui est encore une autre approximation. Les deux motifs de bits diffèrent → le test renvoie False.Sortie exacte :
0.30000000000000004
False==. Le résultat dépend d'erreurs d'arrondi invisibles. C'est la règle d'or du calcul flottant.La bonne façon de comparer
On teste si les deux nombres sont suffisamment proches, à une tolérance (epsilon) près.
a = 0.1 + 0.2
b = 0.3
epsilon = 1e-9
print(abs(a - b) < epsilon) # comparaison correcteepsilon = 1e-9Une petite tolérance, ici . Deux flottants dont l'écart est inférieur à sont considérés « égaux ».abs(a - b) < epsilonabs(a - b) est la distance entre les deux nombres. Si elle est plus petite que , on renvoie True. Ici l'écart vaut , largement sous → True.Sortie : True. C'est la comparaison qu'il faut écrire systématiquement pour des flottants.
- Choisir une tolérance adaptée (souvent à ).
- Calculer l'écart absolu
abs(a - b). - Conclure « égaux » si
abs(a - b) < epsilon, jamais aveca == b.
Le réflexe epsilon se travaille sur des TP réels. En colle comme aux concours, savoir quand un flottant trahit fait la différence ; nos mentors alumni X · Centrale · Mines vous entraînent sur les vrais pièges d'énoncés.
Trouver un mentor →Exercices corrigés
1) Convertir en binaire à la main (méthode des poids). 2) Que renvoient bin(22) et int("10110", 2) ?
Voir la correction détaillée
bin(22) renvoie la chaîne '0b10110' ; int("10110", 2) renvoie l'entier 22. Les deux opérations sont inverses l'une de l'autre.1) Coder sur 8 bits en complément à deux. 2) Quel entier relatif le motif 11111111 représente-t-il sur 8 bits ? 3) Rappeler l'intervalle représentable sur 8 bits.
Voir la correction détaillée
11111010. Le bit de poids fort vaut 1 (négatif). ✓11111111 vaut en non-signé ; en complément à deux, . C'est le codage de (un motif « tout à 1 » vaut toujours ).Un étudiant écrit une boucle qui doit s'arrêter quand un compteur flottant atteint :
x = 0.0
while x != 1.0:
x = x + 0.1
print(x)1) Pourquoi cette boucle risque-t-elle de ne jamais s'arrêter ? 2) Corriger le code proprement.
Voir la correction détaillée
0.1 n'est pas représentable exactement. En l'additionnant 10 fois, on obtient une valeur très proche de mais différente ( ou ). Le test x != 1.0 reste alors toujours vrai → boucle infinie. On ne compare jamais des flottants avec == ou !=.for i in range(10):
x = (i + 1) * 0.1
print(x)i (exact) et on calcule x à part. Le nombre d'itérations est garanti.x != 1.0 par abs(x - 1.0) >= 1e-9 comme condition de continuation.Récap final — Ce qu'il faut absolument retenir
Coche mentalement chaque point : si tu bloques, retourne à la section correspondante avant le quiz.
- Sais-tu convertir un entier décimal en binaire par la méthode des poids () et l'inverse ?
- Sais-tu que
bin(n)renvoie une chaîne'0b...'et queint("...", 2)fait l'inverse ? - Sais-tu reconnaître un nombre pair sur son bit de poids faible (dernier bit = 0) ?
- Sais-tu coder un négatif en complément à deux sur bits via , et lire le signe sur le bit de poids fort ?
- Connais-tu l'intervalle représentable sur bits : (donc sur 8 bits) ?
- Sais-tu ce qu'est le débordement, et qu'en Python les entiers sont de taille arbitraire (pas de débordement natif) ?
- Sais-tu expliquer pourquoi
0.1 + 0.2 == 0.3renvoieFalse? - As-tu le réflexe de comparer deux flottants par
abs(a - b) < epsilonet jamais par==?