Architecture des ordinateurs · C1 Représentation de l'information · Chapitre 1 · 6 h
Systèmes de numération
Binaire, octal, hexadécimal et conversions dans les deux sens ; arithmétique binaire ; poids des bits, octet et mot.
L'accent de ce site s'écrit #4f46e5. Trois octets : un peu de rouge, un peu de vert,
beaucoup de bleu. Une adresse réseau s'écrit 192.168.1.1, un masque /24, et la mémoire
d'un programme qui plante s'affiche en colonnes de 0x7ffd3a20. Aucune de ces notations
n'est décorative : elles disent toutes la même chose, un nombre, dans la base qui rend ce
nombre lisible.
Une machine ne connaît qu'un alphabet à deux lettres. Tout ce que ce cours étudiera — instructions, adresses, images, sons — est une suite de zéros et de uns. Ce premier chapitre apprend à lire cette suite, à la traduire, et à y calculer. C'est le socle : le complément à deux du chapitre 2, les tables de vérité du chapitre 3 et les modes d'adressage du chapitre 6 sont tous écrits dans cette langue.
Compter, c'est pondérer
Notre système décimal n'a rien d'évident, et le comprendre en tant que système est ce qui permet d'en changer. Écrire 3705, c'est écrire une somme :
3705 = 3 × 10³ + 7 × 10² + 0 × 10¹ + 5 × 10⁰ = 3000 + 700 + 0 + 5Deux ingrédients seulement. Une base — ici dix — qui fixe le nombre de chiffres disponibles, de à . Et une position, qui donne à chaque chiffre son poids : une puissance de la base, croissante de droite à gauche à partir de .
Rien dans cette mécanique n'impose . Le choix de dix est anatomique, pas mathématique. En base quelconque, un nombre écrit vaut :
Et la propriété qui servira partout : avec chiffres en base , on écrit exactement valeurs différentes, de à . Huit chiffres binaires donnent valeurs, donc de 0 à 255 — le 255 des masques réseau et des composantes de couleur n'est pas un nombre rond arbitraire, c'est la dernière valeur qui tient sur un octet.
Trois bases, trois raisons
Le cours n'en emploiera que trois, et chacune existe pour une raison distincte.
La base 2 est la seule que le matériel connaisse. Un fil est sous tension ou ne l'est pas ; un transistor conduit ou bloque. Deux états discernables de façon fiable — trois seraient techniquement possibles et le sont si peu qu'on n'en fait pas d'ordinateurs. Le chiffre binaire s'appelle un bit (binary digit).
La base 16, dite hexadécimale, est une commodité d'écriture pour les humains. Ses chiffres vont de 0 à 9 puis A à F, où A vaut 10 et F vaut 15. Son intérêt tient à une coïncidence : , donc un chiffre hexadécimal vaut exactement quatre bits. Un octet s'écrit sur deux caractères au lieu de huit, sans le moindre calcul.
La base 8, octale, joue le même rôle avec : un chiffre pour trois bits. On
la rencontre surtout dans les permissions Unix — le chmod 755 du cours de systèmes est un
nombre octal, trois groupes de trois bits.
| Décimal | Binaire | Octal | Hexadécimal |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 5 | 0101 | 5 | 5 |
| 9 | 1001 | 11 | 9 |
| 10 | 1010 | 12 | A |
| 15 | 1111 | 17 | F |
| 16 | 10000 | 20 | 10 |
| 255 | 11111111 | 377 | FF |
Retenez la dernière ligne : FF = 255 = un octet plein. Elle revient constamment.
Quiz · 1 question
Pourquoi l'hexadécimal est-il universellement employé pour afficher le contenu de la mémoire, plutôt que l'octal ou le décimal ?
- Parce qu'il permet d'écrire de plus grands nombres avec moins de chiffres que toute autre base — compacité
- Parce que 16 = 2⁴ : un chiffre hexadécimal vaut exactement 4 bits, donc un octet s'écrit sur 2 caractères sans aucun calcul — alignement sur l'octet
- Parce que les processeurs calculent nativement en base 16 — calcul natif
Réponse : Le processeur ne calcule qu'en binaire ; l'hexadécimal n'existe que pour l'œil humain. Son avantage n'est pas la compacité en soi — la base 10 est plus compacte encore — mais l'ALIGNEMENT : 16 étant une puissance de 2, la conversion binaire ↔ hexadécimal se fait par simple découpage en groupes de 4 bits, sans division. Le décimal, lui, n'est pas une puissance de 2 : passer de 0b11010110 à 214 demande un vrai calcul, et l'inverse aussi. L'octal a la même propriété avec 3 bits, mais l'informatique s'organise en octets, donc en multiples de 4 bits.
Convertir dans les deux sens
Quatre procédés suffisent, et il faut les avoir tous automatisés.
Base → décimal : la somme pondérée. On applique la définition. Pour 1011₂ :
. Pour 2AF₁₆ :
.
En pratique on emploie le schéma de Horner, qui évite de calculer les puissances : partir
de 0, et pour chaque chiffre de gauche à droite, multiplier l'accumulateur par la base puis
ajouter le chiffre. Pour 2AF₁₆ : , puis , puis
. Trois multiplications, aucune puissance.
Décimal → base : les divisions successives. On divise par la base, on note le reste, on recommence sur le quotient jusqu'à zéro. Les restes, lus de bas en haut, donnent l'écriture.
Convertir 214 en binaire 214 ÷ 2 = 107 reste 0 ← bit de poids faible107 ÷ 2 = 53 reste 1 53 ÷ 2 = 26 reste 1 26 ÷ 2 = 13 reste 0 13 ÷ 2 = 6 reste 1 6 ÷ 2 = 3 reste 0 3 ÷ 2 = 1 reste 1 1 ÷ 2 = 0 reste 1 ← bit de poids fort Lecture de bas en haut : 11010110L'erreur de débutant est de lire les restes de haut en bas. Le contrôle est immédiat : le premier reste obtenu est celui de la division par 2, donc il vaut 1 si et seulement si le nombre est impair — c'est forcément le bit le plus à droite.
Binaire ↔ hexadécimal : le découpage. Aucune arithmétique. On groupe les bits par quatre en partant de la droite, en complétant par des zéros à gauche si besoin, et on traduit chaque groupe.
11010110 → 1101 | 0110 → D | 6 → 0xD60x4F46E5 → 0100 1111 0100 0110 1110 0101Avec l'octal, même chose par groupes de trois. Et pour passer de l'hexadécimal à l'octal, on transite par le binaire : il n'existe pas de raccourci direct, et n'étant pas puissances l'une de l'autre.
Calculer en binaire
L'addition binaire tient en quatre lignes, dont la dernière est la seule à retenir :
0 + 0 = 00 + 1 = 11 + 0 = 11 + 1 = 0 avec une retenue de 1 sur la colonne suivanteC'est exactement l'addition posée de l'école primaire, avec une retenue qui se déclenche à 2 au lieu de 10. Et c'est aussi, littéralement, le circuit du chapitre 4 : la colonne « somme » est un OU exclusif, la colonne « retenue » est un ET.
1 1 1 ← retenues 0 1 0 1 1 (11) + 0 0 1 1 1 ( 7) ─────────── 1 0 0 1 0 (18)La multiplication est plus simple qu'en décimal, parce que la table de multiplication
binaire ne contient que des 0 et des 1 : chaque ligne du produit posé est soit une copie
décalée du premier facteur, soit une ligne de zéros. D'où un fait qui servira au chapitre 6 :
multiplier par 2 revient à décaler tous les bits d'un rang vers la gauche, diviser par 2
à décaler vers la droite. Un processeur qui décale plutôt que de multiplier gagne beaucoup de
temps, et un compilateur remplace systématiquement x * 8 par un décalage de 3.
La soustraction binaire posée existe, avec ses emprunts. On ne l'enseignera pas : le chapitre 2 montrera qu'aucune machine ne l'utilise. Elles additionnent l'opposé, et c'est tout l'intérêt du complément à deux.
Bit, octet, mot
Le bit est l'unité. Il ne se manipule presque jamais seul.
L'octet (byte) est le groupe de 8 bits, et l'unité d'adressage de toutes les machines courantes : la mémoire est un tableau d'octets, et chaque octet a une adresse. Un octet code valeurs.
Le mot (word) est la quantité que le processeur traite en une opération : 32 ou 64 bits aujourd'hui. C'est aussi, en général, la largeur des registres et du bus de données du chapitre 5. Attention au faux ami : la taille du mot dépend de la machine, celle de l'octet non.
Dernier point, source d'une confusion tenace. Les préfixes du système international valent mille : un kilooctet (ko) vaut octets. Les préfixes binaires valent 1024 : un kibioctet (Kio) vaut octets. L'écart est de 2,4 % au kilo et grimpe à 7,4 % au téra — c'est toute la différence entre le disque « 1 To » du fabricant et les « 931 Gio » qu'affiche le système, et cela n'a rien d'une escroquerie : ce sont deux unités différentes portant des noms trop proches.
Quiz · 1 question
Combien de valeurs distinctes peut-on coder sur 12 bits, et combien de bits faut-il au minimum pour coder les 26 lettres de l'alphabet ?
- 4096 valeurs, et 5 bits pour l'alphabet — 2¹² et 2⁵
- 2048 valeurs, et 4 bits pour l'alphabet — 2¹¹ et 2⁴
- 4096 valeurs, et 26 bits pour l'alphabet — un bit par lettre
Réponse : Douze bits codent 2¹² = 4096 valeurs, de 0 à 4095. Pour l'alphabet, on cherche le plus petit n tel que 2ⁿ ≥ 26 : 2⁴ = 16 ne suffit pas, 2⁵ = 32 suffit — donc 5 bits, avec 6 combinaisons inutilisées. C'est le raisonnement de dimensionnement le plus fréquent du cours : il donnera la largeur du bus d'adresses au chapitre 5 et le nombre de bits de déplacement dans une page au chapitre 7. La troisième réponse confond codage binaire et codage « un bit par élément », qui gaspillerait 21 bits.
À vous
L'exercice implémente les deux conversions dans les deux sens, puis vérifie qu'elles sont réciproques sur une série de nombres. C'est le meilleur contrôle qui soit : une conversion juste dans un sens et fausse dans l'autre se repère immédiatement.
Attention au piège volontaire du squelette : les restes des divisions successives doivent être lus de bas en haut, et le code fourni les concatène dans le mauvais ordre.
Exercice de code
Réparez la conversion décimal → base b, et vérifiez que l'aller-retour est fidèle.
Point de départ
const CHIFFRES = "0123456789ABCDEF";
// Base b -> décimal, par le schéma de Horner : on parcourt les chiffres de
// gauche à droite, on multiplie l'accumulateur par la base, on ajoute.
function versDecimal(texte, base) {
let n = 0;
for (const c of texte.toUpperCase()) {
n = n * base + CHIFFRES.indexOf(c);
}
return n;
}
// Décimal -> base b, par divisions successives.
function versBase(n, base) {
if (n === 0) return "0";
let sortie = "";
while (n > 0) {
const reste = n % base;
sortie = sortie + CHIFFRES[reste]; // ← les restes s'accumulent... dans quel sens ?
n = Math.floor(n / base);
}
return sortie;
}
// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. versBase est fausse : les restes sont lus à l'envers. Corrigez-la.
// 2. Vérifiez que l'aller-retour redonne bien le nombre de départ.
const CAS = [
{ n: 214, base: 2, attendu: "11010110" },
{ n: 214, base: 16, attendu: "D6" },
{ n: 687, base: 16, attendu: "2AF" },
{ n: 493, base: 8, attendu: "755" },
{ n: 255, base: 2, attendu: "11111111" },
{ n: 0, base: 2, attendu: "0" },
];
for (const c of CAS) {
const ecrit = versBase(c.n, c.base);
const relu = versDecimal(ecrit, c.base);
const ok = ecrit === c.attendu && relu === c.n ? " ok" : " X attendu " + c.attendu;
console.log(
String(c.n).padStart(4) + " en base " + String(c.base).padStart(2) +
" -> " + ecrit.padEnd(10) + " -> " + String(relu).padStart(4) + ok
);
}
Solution
const CHIFFRES = "0123456789ABCDEF";
function versDecimal(texte, base) {
let n = 0;
for (const c of texte.toUpperCase()) {
n = n * base + CHIFFRES.indexOf(c);
}
return n;
}
function versBase(n, base) {
if (n === 0) return "0";
let sortie = "";
while (n > 0) {
// Le reste obtenu est le chiffre de POIDS LE PLUS FAIBLE de ce qui
// reste : il s'écrit donc à GAUCHE de ce qu'on a déjà produit.
sortie = CHIFFRES[n % base] + sortie;
n = Math.floor(n / base);
}
return sortie;
}
const CAS = [
{ n: 214, base: 2, attendu: "11010110" },
{ n: 214, base: 16, attendu: "D6" },
{ n: 687, base: 16, attendu: "2AF" },
{ n: 493, base: 8, attendu: "755" },
{ n: 255, base: 2, attendu: "11111111" },
{ n: 0, base: 2, attendu: "0" },
];
for (const c of CAS) {
const ecrit = versBase(c.n, c.base);
const relu = versDecimal(ecrit, c.base);
const ok = ecrit === c.attendu && relu === c.n ? " ok" : " X attendu " + c.attendu;
console.log(
String(c.n).padStart(4) + " en base " + String(c.base).padStart(2) +
" -> " + ecrit.padEnd(10) + " -> " + String(relu).padStart(4) + ok
);
}
En travaux pratiques
Travaux pratiques 1 · 2 h
Compter comme la machine
Convertir sans outil, écrire son propre convertisseur, et rencontrer la limite qui gouverne tout le reste du cours : un nombre de bits fixé.
Avant de commencer
- De quoi compiler ou exécuter un petit programme, dans le langage de votre choix
- Une calculatrice en mode programmeur, pour vérifier — pas pour travailler
Énoncé
- À la main d'abord — Convertissez 173, 255 et 1000 en binaire, octal et hexadécimal, par divisions successives. Vérifiez ensuite seulement, avec la calculatrice. Indice : Divisez par la base, notez le reste, recommencez avec le quotient. Les restes se lisent du dernier au premier.
- Votre convertisseur — Écrivez une fonction qui convertit un entier positif vers une base entre 2 et 16, sans utiliser la fonction toute faite du langage. Testez-la sur les trois valeurs précédentes.
- Pourquoi l'hexadécimal existe — Affichez la même valeur, 3 735 928 559, en binaire et en hexadécimal. Comptez les caractères de chaque écriture, puis dites combien de bits représente un seul chiffre hexadécimal.
- Trouver le mur — Simulez un compteur sur 8 bits : partez de 250 et ajoutez 1, dix fois de suite, en gardant toujours 8 bits. Notez la suite obtenue et expliquez ce qui se passe entre deux valeurs.
- Le vrai débordement — En C, déclarez une variable de type unsigned char valant 255 et ajoutez-lui 1. Puis faites la même chose avec un char signé valant 127. Comparez les deux résultats. Indice : Les deux occupent 8 bits, mais ne les interprètent pas de la même façon — c'est le sujet du chapitre suivant.
- Lire de la mémoire brute — Créez un fichier texte contenant le mot « OK », puis affichez-le avec un outil hexadécimal. Retrouvez chaque octet dans la table ASCII.
C'est réussi quand
- Vous convertissez 173 en hexadécimal sans calculatrice, en moins d'une minute
- Votre convertisseur donne AD pour 173 en base 16
- Vous savez dire où passe le bit perdu quand 255 devient 0
Correction
173 en base 2 173 en base 16 173 / 2 = 86 reste 1 173 / 16 = 10 reste 13 (D) 86 / 2 = 43 reste 0 10 / 16 = 0 reste 10 (A) 43 / 2 = 21 reste 1 21 / 2 = 10 reste 1 lecture à rebours : AD 10 / 2 = 5 reste 0 5 / 2 = 2 reste 1 2 / 2 = 1 reste 0 1 / 2 = 0 reste 1 lecture à rebours : 1010 1101
Le même nombre, trois écritures. La VALEUR ne change pas — seule la façon de l'écrire change. C'est la distinction que le chapitre entier cherche à installer, et celle qui manque à quiconque dit « convertir un nombre en binaire » comme s'il changeait de nature.
void convertir(unsigned int n, int base) {
const char *chiffres = "0123456789ABCDEF";
char tampon[33];
int i = 0;
if (n == 0) { printf("0\n"); return; }
while (n > 0) { /* on empile les restes */
tampon[i++] = chiffres[n % base];
n /= base;
}
while (i > 0) /* on les dépile : ordre inverse */
putchar(tampon[--i]);
putchar('\n');
}Les restes sortent dans le mauvais ordre, d'où le tampon lu à rebours. C'est exactement une pile — vous la reverrez formalisée en Algorithmique 2, et câblée en matériel au chapitre 5 pour les appels de fonction.
3735928559 en binaire : 1101 1110 1010 1101 1011 1110 1110 1111 (32 caractères) 3735928559 en hexa : DEADBEEF ( 8 caractères) 1 chiffre hexadécimal = 4 bits, exactement
L'hexadécimal n'apporte rien de nouveau : il regroupe les bits par quatre. C'est pour cela qu'un vidage mémoire s'écrit en hexadécimal et jamais en décimal — on peut retrouver chaque bit de tête, ce qui est impossible avec du décimal.
250 251 252 253 254 255 0 1 2 3 1111 1111 (255) + 0000 0001 ----------- 10000 0000 ← 9 bits, mais il n'y a que 8 fils 0000 0000 ← ce qui reste après la troncature
Le bit de retenue n'est pas arrondi, ni signalé, ni perdu par erreur : il n'y a physiquement aucun fil pour le porter. Le processeur le met de côté dans un DRAPEAU de retenue — vous câblerez ce drapeau au TP 4, et un débordement non testé restera silencieux. C'est l'origine directe de l'échec du vol Ariane 5 (1996).
unsigned char u = 255; u + 1 → 0 (retour à zéro) signed char s = 127; s + 1 → -128 (retour au minimum) les deux valent 1000 0000 en mémoire, ou 0000 0000 selon le cas : les BITS sont identiques, l'INTERPRÉTATION diffère
Aucun octet ne porte en lui l'information « je suis signé ». C'est le TYPE, connu du seul compilateur, qui décide comment lire les bits. Le chapitre 2 explique pourquoi 127 + 1 donne -128 et pas autre chose.
Ce que la suite en fait
Ce chapitre n'a manipulé que des entiers positifs, et c'est sa limite : rien de ce qui précède ne sait écrire , ni , ni la lettre « é ». Le chapitre 2 lève ces trois restrictions, et découvre au passage que chaque codage a un domaine hors duquel il ment silencieusement.
La suite pondérée sert aussi ailleurs qu'en conversion. La somme est exactement ce que calcule un décodeur au chapitre 4, et le découpage d'une adresse en « numéro de page » et « déplacement » du chapitre 7 n'est rien d'autre qu'une coupure de cette somme en deux morceaux.
À retenir
Flashcards · 4 cartes
- Comment convertir un décimal en base b, et quelle est l'erreur classique ?
- Par divisions successives par b : on divise, on note le reste, on recommence sur le quotient jusqu'à obtenir 0. L'erreur classique est de lire les restes dans l'ordre où on les obtient. Il faut les lire DE BAS EN HAUT : le premier reste est celui de la division par b, donc le chiffre de poids le plus faible, celui le plus à droite.
- Pourquoi la conversion binaire ↔ hexadécimal ne demande-t-elle aucun calcul ?
- Parce que 16 = 2⁴. Un chiffre hexadécimal correspond donc exactement à 4 bits, et la conversion se réduit à un découpage en groupes de 4 bits depuis la droite, chacun traduit indépendamment. Même chose en octal avec 3 bits, puisque 8 = 2³. Le décimal n'a pas cette propriété : 10 n'est pas une puissance de 2.
- Combien de valeurs sur n bits, et comment dimensionner un codage ?
- n bits codent 2ⁿ valeurs, de 0 à 2ⁿ − 1. Pour coder k éléments distincts, on cherche le plus petit n tel que 2ⁿ ≥ k. Un octet (8 bits) code 256 valeurs, de 0 à 255 — d'où le 255 des masques réseau et des composantes de couleur.
- Quelle est la différence entre un kilooctet (ko) et un kibioctet (Kio) ?
- 1 ko = 10³ = 1000 octets (préfixe du système international) ; 1 Kio = 2¹⁰ = 1024 octets (préfixe binaire). L'écart est de 2,4 % au kilo et de 7,4 % au téra : c'est pourquoi un disque vendu « 1 To » affiche 931 Gio. Deux unités différentes aux noms trop proches, pas une tromperie.