Première NSIReprésentation des données

Nombres réels en Binaire

Représentation en virgule fixe et flottante (IEEE754)

Nombres réels en binaire

Un entier tombe juste sur un nombre fini de bits, alors qu'un réel n'y tombe souvent pas. On le code comme une notation scientifique, mais en base 2 :

N=(−1)S×m×2eN = (-1)^{S} \times m \times 2^{e}

SS est le signe, mm la mantisse, ee l'exposant. Mantisse et exposant tiennent sur un nombre fini de bits. Beaucoup de décimaux familiers, à commencer par 0,10{,}1, n'ont donc pas de représentation exacte. Ce n'est pas un bug de Python. C'est le format.

Après la virgule

À gauche de la virgule, les colonnes valent 20,21,22,…2^0, 2^1, 2^2, \ldots À droite, ce sont les puissances négatives : 2−1=0,52^{-1} = 0{,}5, 2−2=0,252^{-2} = 0{,}25, 2−3=0,1252^{-3} = 0{,}125, et ainsi de suite.

0,75=0,5+0,25=0,11(2)0{,}75 = 0{,}5 + 0{,}25 = 0{,}11_{(2)}

Pour trouver les bits d'une partie décimale, on multiplie par 2. Le chiffre passé devant la virgule est le prochain bit. On recommence avec ce qui reste après la virgule.

Étape× 2Bit
0,751,51
0,51,01

On s'arrête quand la partie fractionnaire tombe à 0. Ainsi 14,75(10)=1110,11(2)14{,}75_{(10)} = 1110{,}11_{(2)} : 1414 s'écrit 11101110, et 0,750{,}75 s'écrit 0,110{,}11. Certains nombres ne s'arrêtent jamais. 0,10{,}1 produit une suite infinie de bits, comme 1/31/3 produit 0,333…0{,}333\ldots en décimal. Avec un nombre fini de bits, on coupe, donc on approxime.

IEEE 754, simple précision

La norme IEEE 754 fixe ce découpage. En simple précision, 32 bits : 1 bit de signe, 8 bits d'exposant, 23 bits de mantisse. Les float de Python sont en pratique des doubles précisions, 64 bits. Le principe est le même, les largeurs changent. L'exemple ci-dessous est le format 32 bits, plus court à écrire à la main.

Signe (1)Exposant (8)Mantisse (23)
SSEE (biais 127)bits après le 1. implicite

On ne stocke pas l'exposant tel quel. On lui ajoute un biais, 127 en simple précision, pour coder aussi les exposants négatifs avec un entier positif. Et on normalise : on décale la virgule pour que le nombre s'écrive 1,…×2e1{,}\ldots \times 2^{e}. Le 1 avant la virgule est implicite. On ne le range pas dans les 23 bits. On range seulement ce qui suit.

14,7514{,}75 pas à pas

  1. Binaire : 1110,11(2)1110{,}11_{(2)}
  2. Normaliser : 1,11011(2)×231{,}11011_{(2)} \times 2^{3}
  3. Signe : S=0S = 0, le nombre est positif
  4. Exposant biaisé : E=3+127=130=10000010(2)E = 3 + 127 = 130 = 10000010_{(2)}
  5. Mantisse : les bits après le 1. sont 11011, complétés de zéros jusqu'à 23 bits

14,75=0⏟S 10000010⏟E 11011000000000000000000⏟M14{,}75 = \underbrace{0}_{S}\ \underbrace{10000010}_{E}\ \underbrace{11011000000000000000000}_{M}

Le biais de 127 ne concerne que l'exposant sur 8 bits. En double précision, l'exposant tient sur 11 bits et le biais vaut 1023. Le principe est le même, seule la constante change.

Ce que Python affiche vraiment

>>> 0.1 + 0.2
0.30000000000000004

>>> (3.3 + 2.1) * 4.2
22.680000000000003

0,10{,}1 et 0,20{,}2 ne sont pas exacts en binaire. Leur somme n'est pas exactement 0,30{,}3. Comparer deux flottants avec == dit donc souvent « différent » pour deux résultats que le calcul décimal juge égaux. On compare à une tolérance, ou l'on passe par Decimal quand on veut une arithmétique décimale exacte, par exemple pour de l'argent.

# Tolérance
abs((0.1 + 0.2) - 0.3) < 1e-9  # True

# Ou Decimal pour de l'arithmétique décimale exacte
from decimal import Decimal
Decimal("0.1") + Decimal("0.2") == Decimal("0.3")  # True

Decimal("0.1") part du texte "0.1", donc du décimal écrit. Decimal(0.1) partirait du flottant déjà arrondi : ce n'est pas la même chose.

En résumé, après la virgule, les poids sont 2−12^{-1}, 2−22^{-2}, et la suite. Un flottant, c'est un signe, un exposant et une mantisse, sur un nombre fini de bits. L'exposant est stocké avec un biais, 127 en simple précision. En Python, float suit la norme IEEE 754 en double précision, c'est-à-dire sur 64 bits. On compare avec une tolérance, ou avec Decimal si le décimal doit tomber juste.

Pour s'entraîner

Exercices : données binaires