Bases numériques, tailles en octets et les unités qui font débat

Comment l'hexadécimal se projette sur les bits, pourquoi un disque de 1 To s'affiche à 931 Go, ce que vaut réellement 0,1 plus 0,2, et comment l'arrondi, les pourcentages et le formatage local modifient discrètement un nombre.

Un nombre écrit porte deux choses : une valeur, et un ensemble d'hypothèses sur la façon de le lire. 0xFF, 255, 0o377 et 11111111 sont une seule quantité en quatre notations. Un téraoctet et un tébioctet diffèrent de dix pour cent. 1,234 vaut à peu près mille à Londres et à peu près un à Berlin. La plupart des bogues numériques viennent des hypothèses plutôt que de l'arithmétique.

Binaire, octal, décimal et hexadécimal

Toute base positionnelle fonctionne de la même façon. Chaque rang vaut la base multipliée par le rang situé à sa droite, et les chiffres vont de zéro à la base moins un. La base 16 a besoin de six chiffres supplémentaires : elle emprunte donc A à F pour dix à quinze.

L'hexadécimal sert pour les octets et les couleurs parce que 16 vaut 2 à la puissance 4 : un chiffre hexadécimal vaut donc exactement quatre bits et un octet exactement deux chiffres hexadécimaux, sans report de l'un à l'autre.

0 0000   4 0100   8 1000   C 1100
1 0001   5 0101   9 1001   D 1101
2 0010   6 0110   A 1010   E 1110
3 0011   7 0111   B 1011   F 1111

Ce tableau contient toute la conversion. Pour passer de l'hexadécimal au binaire, remplacez chaque chiffre par ses quatre bits : 0x2F devient 0010 1111. Pour revenir, groupez les bits par quatre en partant de la droite, en complétant la gauche par des zéros, et lisez chaque groupe dans le tableau.

Pour le décimal, servez-vous des valeurs de rang. 0x2F vaut 2 x 16 + 15, soit 47. Dans l'autre sens, divisez par 16 de façon répétée et lisez les restes de bas en haut :

200 / 16 = 12 remainder 8   -> 8
 12 / 16 =  0 remainder 12  -> C
200 decimal = 0xC8

L'octal empaquette trois bits par chiffre, ce qui explique que les permissions Unix s'écrivent 755 : chaque chiffre est un triplet rwx, 7 valant 111 et 5 valant 101. Une couleur CSS comme #FF8800 fait trois octets, un par canal, allant chacun de 0 à 255, et la notation abrégée à trois chiffres #F80 s'étend en doublant chaque chiffre plutôt qu'en complétant par des zéros. Le Convertisseur de base numérique couvre les quatre bases d'un coup.

Le complément à deux, et d'où viennent les intervalles

Un octet contient 256 motifs distincts. Lus comme non signés, ils vont de 0 à 255. Lus comme signés, le bit de poids fort marque la moitié négative, et une valeur négative vaut son motif moins 256. Ce procédé est le complément à deux, retenu parce que l'addition binaire ordinaire fonctionne alors de façon identique sur les valeurs signées et non signées.

Pour prendre l'opposé d'un nombre, inversez chaque bit et ajoutez un. L'intervalle est asymétrique parce que le zéro occupe l'un des 128 emplacements de la moitié non négative : un octet signé va donc de -128 à 127. Ajouter un au sommet de l'intervalle ramène en bas :

  0111 1111    127
+ 0000 0001      1
= 1000 0000   -128

Rien n'est signalé dans la plupart des langages ; la valeur apparaît simplement de l'autre côté de l'intervalle. Le même bouclage sur 32 bits est le problème de 2038, où un horodatage Unix signé sur 32 bits arrive à court à 2 147 483 647 secondes. Sur 16 bits non signés, on obtient 0 à 65 535, ce qui explique exactement pourquoi les numéros de port TCP s'arrêtent là, et pourquoi le générateur de Ports aléatoires puise dans cet intervalle en évitant les ports réservés en dessous de 1024.

Kilooctets, kibioctets et les gigaoctets manquants

Les fabricants de stockage comptent en puissances de dix. Les systèmes d'exploitation ont historiquement compté en puissances de deux tout en étiquetant le résultat avec le préfixe décimal, et c'est là que la dispute commence. Les préfixes binaires (Kio, Mio, Gio) existent pour lever l'ambiguïté.

Puissance de dixValeur décimalePréfixe binaireValeur binaireÉcart
ko, 10^31 000Kio, 2^101 0242,4 %
Mo, 10^61 000 000Mio, 2^201 048 5764,9 %
Go, 10^91 000 000 000Gio, 2^301 073 741 8247,4 %
To, 10^121 000 000 000 000Tio, 2^401 099 511 627 77610,0 %
Po, 10^1510^15Pio, 2^501 125 899 906 842 62412,6 %

Un disque de 1 To contient 10^12 octets tel qu'il est vendu. Divisez cela par 2^30 et vous obtenez 931,32 : Windows annonce donc environ 931 Go, en employant l'étiquette décimale pour une quantité binaire. Rien ne manque ; ce sont les mêmes octets divisés par un autre nombre. macOS et la plupart des outils Linux annoncent aujourd'hui des Go décimaux, ce qui correspond à la boîte. Les tailles de mémoire sont véritablement binaires, si bien que 16 Go de RAM font réellement 16 Gio.

Les débits réseau se comptent en bits, pas en octets, et toujours en décimal. Une ligne à 100 Mbit/s transporte 100 000 000 bits par seconde, soit 12,5 Mo par seconde avant les surcoûts. La surcharge des protocoles en prend quelques pour cent, si bien que 11 à 12 Mo par seconde constituent le plafond réaliste. Diviser par huit un chiffre annoncé en mégabits est le contrôle rapide, et le Convertisseur d'unités couvre les unités de stockage.

La virgule flottante, et pourquoi l'argent n'est pas un flottant

Les fractions binaires ne peuvent représenter que des sommes de moitiés, de quarts, de huitièmes et ainsi de suite. Un dixième n'a pas de forme binaire exacte, comme un tiers n'a pas de forme décimale exacte : 0.1 stocké dans un double IEEE 754 vaut donc un peu plus qu'un dixième. Additionnez deux approximations de ce genre et l'erreur remonte à la surface :

0.1 + 0.2 = 0.30000000000000004

Un double dispose de 53 bits de mantisse. Cela rend exactement représentable tout entier jusqu'à 2^53 (9 007 199 254 740 992), ainsi que toute fraction dont le dénominateur est une puissance de deux. Au-dessus de 2^53, l'écart entre valeurs représentables devient 2, si bien que 2^53 + 1 est égal à 2^53. C'est pourquoi des identifiants de base de données sur 64 bits transmis en JSON devraient voyager sous forme de chaînes : les nombres JavaScript sont des doubles, et un identifiant de 19 chiffres perd silencieusement ses derniers chiffres.

Pour l'argent, stockez des unités mineures entières (centimes) ou utilisez un type décimal qui travaille en base dix. Ne comparez jamais des flottants par égalité ; comparez l'écart à une petite tolérance. La Calculatrice d'expressions travaille elle aussi en doubles, et hérite des mêmes limites.

Arrondir, et arrondir deux fois

L'arrondi supérieur à la moitié écarte une égalité de zéro. L'arrondi à la moitié paire, dit aussi arrondi du banquier, envoie une égalité vers le chiffre pair le plus proche, ce qui supprime le biais vers le haut qu'introduit le premier sur une longue colonne de chiffres. C'est la valeur par défaut de l'IEEE 754 et la règle de plusieurs normes comptables.

ValeurMoitié au supérieurMoitié paire
0,510
1,522
2,532
3,544
-0,5-10

Arrondissez une seule fois, à partir de la valeur d'origine. Arrondir 2,4449 à trois décimales donne 2,445, et arrondir ce résultat à deux donne 2,45, alors qu'arrondir directement l'original à deux donne 2,44. Les arrondis enchaînés à travers des colonnes intermédiaires sont une cause fréquente de totaux faux d'un centime. Une surprise voisine : 2,675 s'arrondit à 2,67 dans la plupart des langages, parce que le double stocké vaut 2,67499999999999982.

Pourcentage et point de pourcentage

Un taux passant de 4 % à 5 % a augmenté d'un point de pourcentage, ou de 25 % en valeur relative. Les deux sont exacts, et l'unité doit être précisée.

Les variations en pourcentage ne s'annulent pas. Une baisse de 50 % suivie d'une hausse de 50 % laisse 75, pas 100, car le second pourcentage se calcule sur une base plus petite. Rattraper une baisse de p demande une hausse de p / (1 - p) : une baisse de 50 % réclame donc 100 %, et une baisse de 80 % en réclame 400 %. Les variations successives se multiplient et forment une suite géométrique plutôt qu'une somme, c'est-à-dire la croissance que modélise l'outil Suite de nombres.

La variation d'une ancienne valeur vers une nouvelle vaut (new - old) / old x 100, ce que le Calculateur de pourcentage rapporte comme une différence. Retirer une TVA de 20 % revient à diviser par 1,2, pas à soustraire 20 %. Faire la moyenne de pourcentages sur des groupes de tailles différentes donne un chiffre global faux à moins que la moyenne ne soit pondérée, et Somme et moyenne, qui affiche une médiane à côté de la moyenne, rend l'asymétrie visible.

Les nombres formatés pour une locale

Le formatage est une décision d'affichage, et il n'est pas réversible sans connaître la locale. 1.234 vaut un et des poussières au Royaume-Uni et mille en Allemagne. 1,234 fait l'inverse. Certaines locales groupent plutôt avec une espace ou une apostrophe.

Locale1234567.89
en-GB, en-US1,234,567.89
de-DE1.234.567,89
fr-FR1 234 567,89
de-CH1'234'567.89
en-IN12,34,567.89

Le groupement indien place le premier séparateur après trois chiffres puis tous les deux chiffres, ce qui donne des lakh et des crore plutôt que des milliers et des millions. Reconvertir une chaîne formatée en nombre est une opération avec perte exactement pour cette raison : stockez et transmettez donc les valeurs sans formatage, avec un point comme séparateur décimal, et ne formatez qu'au moment de l'affichage. Quand un nombre doit être sans ambiguïté pour un lecteur, l'écrire en toutes lettres avec Nombre en lettres est l'approche habituelle sur les chèques et dans les contrats. Les chiffres romains restent en dehors de tout cela : sans valeur de rang ni zéro, le convertisseur de Chiffres romains manipule un décompte plutôt qu'une base.