Flottants

Définition d'un flottant

Le terme flottant vient de virgule flottante qui est une méthode d'écriture de nombres réels fréquemment utilisée dans les ordinateurs. Nous allons développer en partie cette méthode.

En base b, un flottant est un nombre de la forme :

\(s \times m \times b^e\)

  • \(s\) est le signe (+ ou -) ;

  • \(m\) est la mantisse. C'est un nombre à \(p\) chiffres, avec exactement un chiffre (non nul) avant la virgule ;

  • \(e\) est l'exposant, avec \(e_{min} \leq e \leq e_{max}\).

Attention

Les nombres \(p\), \(e_{min}\) et \(e_{max}\) sont des nombres écrits en base \(b\) et donnés dès le départ.

Ils permettent de définir une norme (une convention) de représentation des flottants en base b.

Remarque

La définition donnée ci-dessus n'est pas tout à fait la définition générique des flottants, mais nous nous tiendrons à cette approche pour simplifier.

Il s'agit donc de nombres pour lesquels nous imposons l'écriture en notation scientifique.

Les nombres de chiffres pour \(m\) et pour \(e\) sont bornés : cela permet de tenir compte des contraintes des nombres en machine qui seront toujours représentés avec le même nombre, nécessairement fini, de bits (sur les machines actuelles, usuellement 64 bits).

ExempleExemple en base 10

Question :

Faire la liste des flottants en imposant \(p = 2, e_{min} = −1\ et\ e_{max}=1\).

Les mantisses possibles sont :

  • 1,0 ; 1,1 ; ... 1,9 ;

  • 2,0 ; 2,1 ; ... 2,9 ;

  • ...

  • 9,0 ; ... ; 9,9

Les exposants possibles sont -1, 0 et 1.

Les flottants sont donc les nombres suivants :

pour e = -1 :

  • 0,10; 0,11; 0,12; ...; 0,19 (c'est à dire \(1,0 \times 10^-1; 1,1 \times 10^-1 ; 1,2 \times 10^-1; ...; 1,9 \times 10^-1\))

  • 0,20; 0,21; 0,22; ..., 0,29 (c'est à dire \(2,0 \times 10^-1; 2,1 \times 10^-1 ; 2,2 \times 10^-1; ...; 2,9 \times 10^-1\))

  • ...

  • 0,90; 0,91; 0,92; ...; 0,99 (c'est à dire \(9,0 \times 10^-1; 9,1 \times 10^-1 ; 9,2 \times 10^-1; ...; 9,9 \times 10^-1\))

pour e = -0 :

  • 1,0; 1,1; 1,2; ...; 1,9 (c'est à dire \(1,0 \times 10^0; 1,1 \times 10^0 ; 1,2 \times 10^0; ...; 1,9 \times 10^0\))

  • 2,0; 2,1; 2,2; ..., 2,9(c'est à dire \(2,0 \times 10^0; 2,1 \times 10^0 ; 2,2 \times 10^0; ...; 2,9 \times 10^0\))

  • ...

  • 9,0; 9,1; 9,2; ...; 9,9 (c'est à dire \(9,0 \times 10^0; 9,1 \times 10^0 ; 9,2 \times 10^0; ...; 9,9 \times 10^0\))

pour e = +1 :

  • 10; 11; 12; ...; 19 (c'est à dire \(1,0 \times 10^1; 1,1 \times 10^1 ; 1,2 \times 10^1; ...; 1,9 \times 10^1\))

  • 20; 21; 22; ..., 29 (c'est à dire \(2,0 \times 10^1; 2,1 \times 10^1 ; 2,2 \times 10^1; ...; 2,9 \times 10^1\))

  • ...

  • 90; 91; 92; ...; 99 (c'est à dire \(9,0 \times 10^1; 9,1 \times 10^1 ; 9,2 \times 10^1; ...; 9,9 \times 10^1\))

Et tous les opposés de ces nombres !

Question :

Que peut-on dire de l'écart entre un nombre et le nombre suivant avec cette représentation ?

On peut déjà remarquer que la notion de « nombre suivant » a un sens alors qu'elle n'en a pas avec les nombres réels.

Raisonnons uniquement sur les positifs.

  • Entre deux "petits" nombres consécutifs (par exemple entre 0,10 et 0,11), l'écart est 0,01.

  • Entre deux "grands" nombres (par exemple 90 et 91), l'écart est 1.

ComplémentConséquence sur l'exemple ci-dessus :

Avec la représentation précédente,

  • tous les réels de l'intervalle \([0,10 ; 0,105[\) (ouvert ou fermé à droite, choix possible) seront représentés par le même flottant : \(1,0 \times 10^{−1}\).

  • Et tous les réels de l'intervalle \([10;10,5[\) seront représentés par le flottant \(1,0 \times 10^1\).

Ainsi, suivant qu'il s'agit de nombres proches de 0 ou éloignés de 0, chaque réel aura pour représentant dans les flottants un nombre plus ou moins éloigné de lui. Ou en d'autres termes, un même flottant représentera chacun des réels d'un intervalle plus ou moins grand.

La conséquence la plus importante est que l'on ne peut pas attendre que les opérations sur les flottants aient les mêmes propriétés que les opérations sur les réels. Nous avons déjà constaté cela. Par exemple la non commutativité avec :

1
>>> 1 + 10**(-16) -1
2
0.0
3
>>> 1 - 1 + 10**(-16)
4
1e-16

Peut-on expliquer la différence de résultat dans les deux lignes précédentes ?

On a :

>>> 1+10**(-16)

1.0

tandis que

>>> 0 + 10**(-16)

1e-16

Sans rentrer dans les détails, on peut reprendre ce qui est exposé plus haut:

  • 10**(-16) est proche de 0 et aura un représentant flottant assez fidèle,

  • 1 + 10**(-16) est plus éloigné de 0 et les réels entre 1 et 1 + 10**(-16) auront tous 1 pour représentants.

Dans 1 + 10**(-16) -1, on évalue 1 + 10**(-16) qui donne 1 puis on évalue 1 - 1, on obtient 0.

Dans 1 - 1 + 10**(-16), on évalue 1 - 1 qui donne 0 puis on évalue 0 + 10**(-16), on obtient 10**(-16).

DéfinitionNorme IEEE 754

Les flottants binaire sont représentés en général en machine suivant la norme IEEE 754.

Ce nombre est de la forme : \((−1)^s \times m \times 2^{n−d}\)

La norme IEEE 754 est la norme la plus employée pour la représentation des nombres à virgule flottante dans le domaine informatique. La première version de cette norme date de 1985. Nous allons étudier deux formats associés à cette norme :

  • le format dit "simple précision"

  • le format dit "double précision".

Le format "simple précision" utilise 32 bits pour écrire un nombre flottant alors que le format "double précision" utilise 64 bits.

Dans le format double précision (binary64), les flottants sont codés sur 64 bits selon le schéma ci-dessous :

codage sur 64 bits

1

11

52

signe

exposant

mantisse

Dans le format simple précision ou 32 bits :

codage sur 32 bits

1

8

23

signe

exposant

mantisse

  • Le premier bit (à gauche) représente le signe s : 0 pour un positif, 1 pour un négatif ;

  • Les 11 bits suivants (ou 8) représentent l'exposant e.

  • Pour connaître la valeur de l'exposant représenté, on traduit la suite de bits par un entier (écrit en binaire) puis on enlève le décalage d de valeur 1023 (on enlève 127 dans un codage 32 bits).

  • Les 52 bits restants correspondent aux bits se trouvant après la virgule du flottant. C'est la mantisse m privée du 1 qui se trouve avant la virgule (car il y a forcément un 1 devant la virgule en binaire).

Exemple

Quel nombre décimal est représenté par le mot de 64 bits suivant ?

1 10000000110 1010110110000000000000000000000000000000000000000000

  • Nous sommes sur un codage sur 64 bits, l'exposant est long de 11 bits.

  • Le bit de poids fort est 1 donc le signe est négatif

  • L'exposant est \(e=2^{10}+2^2+2^1−1023=1030−1023=7\)

  • La mantisse est \(m= 1+ \frac{1}{2^1} + \frac{1}{2^3} +\frac{1}{2^5} + \frac{1}{2^6} + \frac{1}{2^8} + \frac{1}{2^9} = 1,677734375\)

  • Le nombre décimal représenté est \(−1,677734375×2^7=−214,75\)

ComplémentValeurs particulières

Un certain nombre de codes sont réservés pour représenter des cas particuliers :

0 11111111111 0000000000000000000000000000000000000000000000000000

Ce code (0 suivi de onze 1, suivis de cinquante-deux 0) représente +∞ (+inf).

1 11111111111 0000000000000000000000000000000000000000000000000000

Ce code (1 suivi de onze 1, suivis de cinquante-deux 0) représente −∞ (-inf).

1 11111111111 1111111111111111111111111111111111111111111111111111

Ce code (soixante-quatre bits à 1) représente NaN (not a number).

0 00000000000 0000000000000000000000000000000000000000000000000000

Ce code (soixante-quatre bits à 0) représente 0.

1 00000000000 0000000000000000000000000000000000000000000000000000

Ce code (Un bit à 1 suivi de soixante-trois bits à 0) représente également 0 (-0).

MéthodeEt dans l'autre sens ? Écrire un flottant en respectant la norme IEEE754.

Pour écrire un nombre flottant en respectant la norme IEEE754, il est nécessaire de commencer par écrire le nombre sous la forme 1,XXXXX.2e (avec e l'exposant), il faut obligatoirement qu'il y ait un seul chiffre à gauche de la virgule et il faut que ce chiffre soit un "1".

Par exemple le nombre "1010,11001" devra être écrit "1,01011001.211". Autre exemple, "0,00001001" devra être écrit "1,001.2-101".

La partie "XXXXXX" de "1,XXXXX.2e" constitue la mantisse (dans notre exemple "1010,11001" la mantisse est "01011001"). Comme la mantisse comporte 23 bits en simple précision, il faudra compléter avec le nombre de zéro nécessaire afin d'atteindre les 23 bits (si nous avons "01011001", il faudra ajouter 23 - 8 = 15 zéros à droite, ce qui donnera en fin de compte "01011001000000000000000" )

Notre première intuition serait de dire que la partie "exposant" correspond simplement au "e" de "1,XXXXX.2e" (dans notre exemple "1010,11001", nous aurions "11"). En faite, c'est un peu plus compliqué que cela. En effet, comment représenter les exposants négatifs ? Aucun bit pour le signe de l'exposant n'a été prévu dans le norme IEEE754, une autre solution a été choisie :

Pour le format simple précision, 8 bits sont consacrés à l'exposant, il est donc possible de représenter 256 valeurs, nous allons pouvoir représenter des exposants compris entre (-126)10 et (+127)10 (les valeurs -127 et +128 sont des valeurs réservées, nous n'aborderons pas ce sujet ici). Pour avoir des valeurs uniquement positives, il va falloir procéder à un décalage : ajouter systématiquement 127 à la valeur de l'exposant. Prenons tout de suite un exemple (dans la suite, afin de simplifier les choses nous commencerons par écrire les exposants en base 10 avant de les passer en base 2 une fois le décalage effectué) :

Repartons de "1010,11001" qui nous donne 1,01011001.23, effectuons le décalage en ajoutant 127 à 3 : "1,01011001.2130", soit en passant l'exposant en base 2 : "1,01011001.210000010". Ce qui nous donne donc pour "1010,11001" une mantisse "01011001000000000000000" (en ajoutant les zéros nécessaires à droite pour avoir 23 bits) et un exposant "10000010" (même si ce n'est pas le cas ici, il peut être nécessaire d'ajouter des zéros pour arriver à 8 bits... ATTENTION, ces zéros devront être rajoutés à gauche).