Codage des entiers naturels Principe En informatique, selon le besoin et le contexte, on a le choix d’écrire les nombres sous 4 représentations différentes : le décimal (→ base 10) le binaire (→ base 2) l'hexadécimal (→ base 16) l'octal (→ base 8) Depuis l’antiquité, on écrit les nombres avec des symboles qui, associés entre eux, peuvent représenter n’importe quelle valeur. Plusieurs représentations ont existé au cours de l’histoire mais celle qui a supplanté les autres est la représentation qui repose sur le principe de position. Dans ce genre de représentation, la valeur du symbole utilisée pour écrire le nombre varie en fonction de la place — son rang — qu’il occupe dans l’écriture du nombre : c’est qu’on appelle son poids. Ex. : Dans le nombre 808, exprimé en décimal, le ‘8’ de gauche occupe la place des centaines et vaut/“pèse” donc 100 fois plus que le ‘8’ de droite même si ce sont les mêmes symboles. Le décimal, l’hexadécimal, le binaire et l’octal suivent ce même principe en utilisant des bases différentes (respectivement 10, 16, 2 et 8) qui donneront à chaque symbole du nombre (chiffres mais aussi lettres pour l’hexadécimal) un poids différent. Ainsi, quelle que soit la représentation choisie, la valeur du nombre pourra toujours être obtenue avec la formule suivante : avec : b la base associée à la représentation (décimal → 10, binaire → 2, hexadécimal → 16, octal → 8) ai un des symboles définis pour la base : décimal → [0, 1, 2, …, 9] binaire → [0, 1] hexadécimal → [0, 1, 2, …, 9, A, B, C ,D, E ,F] octal → [0, 1, 2, …, 7] Voyons maintenant ça d’un peu plus près … Par la suite, pour lever toute ambiguité sur la représentation utilisée dans le texte pour écrire un nombre, on le fera suivre par un indice indiquant sa base (ou plus exactement le caractère ‘|’ suivi de sa base). Exemples : 48|10 → le nombre 48 en représentation décimale (4 x 101 + 8 x 100) 21|16 → le nombre 33 en représentation hexadécimale (2 x 161+ 1 x 160) 1100|2 → le nombre 12 en représentation binaire (1 x 23 + 1 x 22 ^+ 0 x 21 + 0 x 20) Système décimal C’est la représentation la plus répandue. On la maitrise plutôt bien puisqu’on l’utilise depuis qu’on est petits ! 😉 Chaque chiffre du nombre représente une puissance de 10. Exemples : 12|10 = 1 x 101 + 2 x 100 = 1 x 10 + 2 x 1 123|10 = 1 x 102 + 2 x 101 + 3 x 100 = 1 x 100 + 2 x 10 + 3 x 1 100 vaut bien 1 et pas 0. Pour écrire un nombre en base 10 dans des codes source C/C++ ou Python, il suffit de le saisir tel quel en veillant à ne pas le précéder d’un 0. foobar.c int main() { int i = 12; (1) int j = 012; // ⚠ (2) } 1 on définit une variable i qui contient la valeur 12 2 on définit une variable j qui contient la valeur 10 et non pas la valeur 12 comme on pourrait le croire. Ceci vient de la présence du ‘0’ devant le ‘12’. Voir l’explication plus loin (→ système octal). Système binaire C’est la représentation qui est souvent utilisée pour effectuer des calculs de sous-réseaux informatique et lorsqu’on programme proche du matériel (registres de microprocesseurs ou composants périphériques). Chaque symbole code une puissance de 2. Exemples : 101|2 = 1 x 22 + 0 x 21 + 1 x 20 = 1 x 4 + 0 x 2 + 1 x 1 = 5|10 1010|2 = 1 x 23 + 0 x 22 + 1 x 21 + 0 x 20 = 1 x 8 + 0 x 4 + 1 x 2 + 0 x 1 = 10|10 Il est plutôt rare d’exprimer des nombres en binaire dans des codes source. Ceci s’explique d’une part par le fait que c’est rarement pris en charge par les langages de programmation et d’autre part car c’est trop long à écrire. le langage Python propose néanmoins la possibilité de saisir les nombres binaires en utilisant le préfixe 0b (zéro suivi de la lettre ‘b’). foobar.py if __name__ == '__main__': foo = 0b11000011 (1) print("{0:b} vaut {0:d} en décimal et {0:x} en hexadécimal".format(foo)) (2) # Affiche : # 11000011 vaut 195 en décimal et c3 en hexadécimal 1 on définit une variable foo qui contient la valeur 195|10 (← 11000011|2) 2 on affiche le contenu de la variable number en binaire ainsi que sa représentation en décimal puis hexadécimal. Bit, Quartet, Octet Chaque chiffre d’un nombre exprimé en binaire est appelé bit (Binary digIT) pour bien faire la distinction avec les chiffres ‘0’ et ‘1’ d’un nombre exprimé en décimal. Les nombres représentés en binaire comportent généralement un nombre de bits multiple de 8. En effet, au niveau interne, les composants électroniques mémorisent les nombres avec des séries de transistors dont l’état est soit passant soit bloqué à la manière d’un interrupteur. Ils sont généralement regroupés par 8 et la valeur codée par ces 8 bits est ce qu’on appelle un octet (ou un byte en anglais). En représentant les nombres binaires avec un nombre de bits multiple de 8 on se rapproche ainsi de la structure interne du composant. Selon le nombre de bits d’un nombre binaire on le qualifiera de : Octet (Byte) lorsqu’il comporte 8 bits Mot (Word) lorsqu’il comporte 16 bits Double Mot (Double Word ou DWord) lorsqu’il comporte 32 bits Quadruple Mot (Quad Word ou QWord) lorsqu’il comporte 64 bits On est parfois amené à manipuler des suites de 4 bits : c’est ce qu’on appelle un quartet (ou nibble en anglais). MSB, LSB Dans un nombre binaire, on se réfère souvent aux bits qui sont situés aux 2 extrémités. Le bit le plus à gauche est souvent désigné par l’acronyme MSB pour Most Significant Bit (ou bit le plus significatif en français). Le bit le plus à droite est, quant à lui, désigné par LSB pour Less Significant Bit (ou bit le moins significatif en français). Tableau 1. Exemple pour le nombre 10100101|2 1 0 1 0 0 1 0 1 MSB LSB Multiples d’octets Pour exprimer la capacité des différents supports de stockage (mémoire RAM, clé USB, disque SSD…) ou les débits de données sur les réseaux, on utilise systématiquement des multiples de l’octet. 2 types de multiplicateurs sont utilisés : ceux correspondant à des puissance de 10 : le kilooctet (ko) = 103 octets = 1000 octets le mégaoctet (Mo) = 106 octets (million) = 1000 ko le gigaoctet (Go) = 109 octets (milliard) = 1000 Mo = 106 ko le téraoctet (To) = 1012 octets (billion) = 1000 Go = 106 Mo = 109 ko le pétatoctet (Po) = 1015 octets (billiard) = 1000 To = 106 Go = 109 Mo = 1012 ko ceux correspondant à des puissances de 2 le kibioctet (Kio) = 210 octets = 1024 octets le mébioctet (Mio) = 220 octets = 1024 Kio le gibioctet (Gio) = 230 octets = 1024 Mio le tébioctet (Tio) = 240 octets = 1024 Gio … Application : La capacité d’un disque SSD est annoncée comme étant 512Go. Quelle est sa capacité en Gio et en Tio ? Réponse Capacité donnée : 512 Go = 512 . 109 octets ⇒ Capacité en Gio : 512 . 109 / 230 ≈ 476,84 Gio ⇒ Capacité en Tio : 512 . 109 / 240 ≈ 0,46 Tio Système hexadécimal Cette représentation est assez versatile. On l’utilise pour représenter : des valeurs binaires dans les codes source C/C++, Python, Javascript… les adresses matérielles (adresses MAC) des cartes réseau des couleurs en HTML … Chaque symbole d’un nombre représenté en hexadécimal (→ hex digit) correspond à une puissance de 16. Dans cette représentation, 16 symboles sont nécessaires. Pour cela, on utilise les 10 chiffres (‘0’ à ‘9’) et les 6 premières lettres de l’alphabet (’A’ à ’F’) dont les valeurs en décimales correspondent aux nombres 10 à 15. Exemples : 3B|16 = 3 x 161 + 11 x 160 = 59|10 1CF|16 = 1 x 162 + 12 x 161 + 15 x 160 = 463|10 Pour écrire un nombre en base 16 dans des codes source (C/C++ , Python, Javascript …), il suffit de le saisir en le précédant du préfixe 0x (zéro suivi de la lettre ‘x’). foobar.c int main() { int i = 0x5A; (1) } 1 on définit une variable i qui contient la valeur 5A|16 = 90|10 Système octal Cette représentation est peu utilisée. On la rencontre essentiellement dans le système d’exploitation Linux pour coder les droits d’accès sur les fichiers. Chaque symbole utilisé dans la représentation en octal d’un nombre (chiffres de ‘0’ à ‘7’ uniquement) représente une puissance de 8. Exemples : 62|8 = 6 x 81 + 2 x 80 = 50|10 750|8 = 7 x 82 + 5 x 81 + 0 x 80 = 488|10 Pour écrire un nombre en base 8 dans des codes source C/C++, Javascript, PHP (v < 8.1), il suffit de le saisir en le précédant du chiffre ‘0’. foobar.c int main() { int i = 0750; (1) } 1 on définit en C/C++une variable i qui contient la valeur 750|8 = 488|10 Dans Python 3.0+ et PHP v8.1+, une valeur octale sera préfixée de 0o (chiffre ‘0’ suivi de la lettre ‘o’). foobar.py if __name__ == '__main__': foo = 0o750 (1) print("{0:o} en octal vaut {0:d} en décimal, {0:x} en hexadécimal et {0:b} en binaire".format(foo)) (2) # Affiche : # 750 en octal vaut 488 en décimal, 1e8 en hexadécimal et 111101000 en binaire 1 on définit une variable foo qui contient la valeur 195|10 (← 11000011|2) 2 on affiche le contenu de la variable number en binaire ainsi que sa représentation en décimal puis hexadécimal. Conversions entre bases Il est impératif de savoir passer d’une base à l’autre. Par exemple, il est impossible de calculer des masques de sous-réseau si on ne maitrise pas les conversions de la base 10 à la base 2. Une autre situation dans laquelle une conversion est nécessaire est lorsqu’on désire saisir des nombres binaires dans un langage ne les prenant pas en charge au niveau du code source (Ex. : C++ dans sa version inférieure à C++14). On va alors plutôt utiliser la représentation hexadécimale car le passage de l’une à l’autre est très facile à réaliser. Conversion binaire ⇆ décimal Décimal → Binaire La méthode pour passer de la représentation décimale à la représentation binaire consiste à effectuer la division entière du nombre à convertir jusqu’à ce que le quotient soit égal à 0. Les restes successifs des divisions — en partant du bas — correspondent à la représentation binaire du nombre. Exemple avec la valeur 57|10 : Binaire → Décimal La méthode consiste à multiplier chaque bit par son poids (← 2rang) et faire la somme de ces produits. Exemple avec 111001|2 : 111001|2 = 1 x 25 + 1 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 = 32 + 16 + 8 + 0 + 0 + 1 = 57|10 Conversion binaire ⇆ hexadécimal Binaire → Hexadécimal La méthode consiste à : regrouper les bits par paquets de 4 en partant de la droite ajouter éventuellement des 0 à gauche pour avoir un nombre entier de paquets de 4 bits convertir chaque paquet en hexadécimal selon la table de correspondance suivante qu’il est fortement recommandé d’apprendre par cœur : Binaire Hexadécimal Binaire Hexadécimal 0000 0 1000 8 0001 1 1001 9 0010 2 1010 A 0011 3 1011 B 0100 4 1100 C 0101 5 1101 D 0110 6 1110 E 0111 7 1111 F Exemples : 11000000|2 ⇒ [1100|2][0000|2] ⇒ [C|16][0|16] ⇒ C0|16 1110101100|2 ⇒ 11|2[1010|2][1011|2] ⇒ [0011|2][1010|2][1011|2] ⇒ [3|16][A|16][B|16] ⇒ 3AB|16 Hexadécimal → Binaire Cette conversion s’obtient en remplaçant directement chaque symbole du nombre hexadécimal par son équivalent binaire sur 4 bits en utilisant la table de correspondance précédente. Exemples : 6C|16 ⇒ [6|16][C|16] ⇒ [0110|2][1100|2] ⇒ 01101100|2 A35|16 ⇒ [A|16][3|16][5|16] ⇒ [1010|2][0011|2][0101|2] ⇒ 10100110101|2 Conversion binaire ⇆ octal Le principe de la conversion est le même que pour une conversion binaire ⇆ hexadécimal sauf que l’on fait des paquets de 3 bits au lieu de 4. Binaire → Octal Exemples : 101011|2 ⇒ [101|2][011|2] ⇒ [5|8][3|8] ⇒ 53|8 1011010|2 ⇒ 1|2[011|2][010|2] ⇒ [001|2][011|2][010|2] ⇒ [1|8][3|8][2|8] ⇒ 132|8 Octal → Binaire Exemples : 27|8 ⇒ [2|8][7|8] = [010|2][111|2] ⇒ 010111|2 755|8 ⇒ [7|8][5|8][5|8] ⇒ [111|2][101|2][101|2] ⇒ 111101101|2 🞄 🞄 🞄 Numération Codage des entiers relatifs