Premiere NSI / Thème 1 : Types et valeurs de base / Chapitre 3

Représentation binaire approximative des nombres réels

Dernière mise à jour le : 01/07/2024

Représentation binaire approximative des nombres réels

Vous avez vu que Python pouvait manipuler des nombres décimaux particuliers appelés nombres flottants qui correspondent aux représentations en machine de nombres réels. Dans ce chapitre, nous allons voir comment on peut écrire en binaire un nombre réel et comment sont encodés les nombres flottants.

Diaporama

Ce diaporama contient tous les éléments à connaître de ce chapitre.

Source : https://info-mounier.fr/premiere_nsi/types_base/data/T1_C3_Representation_reels_diapo_prof.pdf

Le cours qui suit reprend en détails tous les éléments présentés dans le diaporama (à l'écrit comme à l'oral). Des compléments sont également donnés. Sa lecture est donc essentielle pour réviser et ancrer les connaissances.

Écriture binaire d’un nombre réel

En notation décimale, les chiffres à droite de la virgule représentent les dixièmes, les centièmes, les millièmes, etc.
De la même manière, en binaire, les chiffres à droite de la virgule représentent les demis, les quarts, les huitièmes, les seizièmes, etc.

Par exemple, le nombre $(1,1101)_2$ est le nombre $1$ et $\frac{1}{2}$ et $\frac{1}{4}$ et $\frac{1}{16}$.

Conversion de la base 2 vers la base 10

Les chiffres à gauche de la virgule correspondent à des puissances de 2 positives, ceux situés à droite correspondent à des puissances de 2 négatives.

Exemple : À quel nombre décimal correspond l’écriture binaire $101,1101$ ?

Puissances de 2 $2^2$ $2^1$ $2^0$ $2^{-1}$ $2^{-2}$ $2^{-3}$ $2^{-4}$
Écriture binaire $1$ $0$ $1$ $,$ $1$ $1$ $0$ $1$

On a donc : $(101,1101)_2=2^2+2^0+2^{-1}+2^{-2}+2^{-4}=4+1+\dfrac{1}{2}+\dfrac{1}{4} + \dfrac{1}{16} =5,8125$.

Conversion de la base 10 vers la base 2

On commence par convertir la partie entière (à gauche de la virgule). Pour la partie décimale (à droite de la virgule), on effectue des multiplications successives par 2. Après chaque multiplication, la partie entière n’est pas reportée. On poursuit le calcul jusqu’à obtenir 1.

Exemple : Quelle est l’écriture binaire du nombre décimal $5,8125$ ?

On convertit 5 en binaire. Facile : $5=({\color{red} 101})_2$.

Il reste à convertir la partie décimale $0,8125$. On fait des multiplications successives par 2 sans reporter la partie entière :

$$\begin{aligned} 0,8125 \times 2 &= {\color{blue} \mathbf{1}},625 \newline 0,625 \times 2 &= {\color{blue} \mathbf{1}},25 \newline 0,25 \times 2 &= {\color{blue} \mathbf{0}},5 \newline 0,5 \times 2 &= {\color{blue} \mathbf{1}} \end{aligned}$$

Les parties entières ($0$ ou $1$) donnent les chiffres après la virgule de l’écriture binaire de $0,8125$, à lire de haut en bas :

$$0,8125 = (0,{\color{blue} 1101})_2$$

Finalement on a : $5,8125 = ({\color{red} 101},{\color{blue} 1101})_2$.

✍️ Pour s'entraîner : faites l'exercice 1

Écritures infinies

Il existe des nombres dont l’écriture binaire sera infinie (et périodique). Par exemple, $1,2=(1,001100110011 \ldots)_2$, le cycle « $0011$ » se répétant à l’infini.

Comme on ne peut pas représenter en machine un mot infini, il ne sera pas possible de représenter de manière exacte certains nombres réels (beaucoup d’entre eux !). Nous verrons cela un peu plus tard avec tous les problèmes que cela engendre.

Représentation des nombres réels

Dans un ordinateur, les nombres à virgule (réels) sont codés en virgule flottante. On parle de nombres flottants (le type float de Python). La représentation binaire en machine d’un nombre flottant s’inspire de l’écriture scientifique des nombres décimaux dont voici quelques rappels.

Écriture scientifique (rappels)

L’écriture scientifique permet d’uniformiser la façon d’écrire des nombres décimaux. Par exemple :

  • $3542$ s'écrit $+3,542 \times 10^{3}$
  • $-0,0724753$ s'écrit $-7,24753 \times 10^{-2}$

Dans cette écriture, on distingue :

  • Un signe ($+$ ou $-$) ;
  • Un nombre décimal $m$, appelé mantisse, compris dans l’intervalle $[1;10[$ ($1$ inclus et $10$ exclu). Dans les deux exemples, il s’agit de $3,542$ et $7,24753$ ;
  • Un entier relatif $n$, appelé exposant. Dans les deux exemples, il s’agit de $3$ et $-2$.

Ainsi, de manière générale, l’écriture scientifique d’un nombre décimal est : $$± m \times 10^n.$$

La norme norme IEEE 754

La norme IEEE 754 est la plus utilisée pour représenter les nombres flottants. Ils sont représentés sur 32 bits (format appelé « simple précision » ou binary32) ou sur 64 bits (format appelé « double précision », ou binary64) sous la forme :

$$s.m×2^n$$

où :

  • $s$ est le signe du nombre, codé sur 1 bit (0 pour $+$ et 1 pour $-$) ;
  • $n$ son exposant en puissance de 2, codé sur 8 bits (en format 32 bits) ou sur 11 bits (en format 64 bits) ;
  • $m$ sa mantisse codée sur 23 bits (en format 32 bits) ou sur 52 bits (en format 64 bits).

Ainsi, en machine, un flottant est représenté en format 32 bits (simple précision) par un mot binaire de la forme

signe exposant mantisse
1 bit 8 bits 23 bits

et en format 64 bits (double précision) par un mot binaire de la forme

signe exposant mantisse
1 bit 11 bits 52 bits

Exemple (début) : Représentation machine du nombre $5,8125$

On sait que $5,8125$ est positif donc le bit de signe sera 0 :

signe exposant mantisse
0 ? ?

Rappelons que $5,8125=(101,1101)_2$. Par analogie avec l’écriture scientifique, on peut aussi écrire ce nombre binaire : $1,011101 \times 2^2$ en décalant la virgule de deux rangs vers la gauche. En faisant cela, on a fait apparaître :

  • la mantisse : $m = 1,011101$
  • l'exposant : $n=2$.

Il reste maintenant à voir comment sont codées la mantisse et l'exposant !

Codage de la mantisse

Pour représenter les flottants, la base choisie est la base 2 (contrairement à l’écriture scientifique qui est la base 10) donc la mantisse est dans l’intervalle $[1;2[$. Il s’agit donc d’un nombre de la forme :

$$m=1,xx…xx$$

Comme cette mantisse commence toujours par le chiffre $1$, il a été choisi de ne pas coder ce « $1$ » mais uniquement les chiffres après la virgule.

Exemple (suite) : Représentation machine du nombre $5,8125$

La mantisse de ce nombre est $m=1,{\color{blue} 011101}$. Comme le « $1$ » à gauche de la virgule n’est pas codé, la mantisse sera codée par 01110100...0 en ajoutant (à droite !!) autant de zéros que nécessaire pour arriver à 23 bits (simple précision) ou 52 bits (double précision) :

signe exposant mantisse (23 ou 52 bits)
0 ? 01110100...0

Codage de l'exposant

L’exposant est codé sur 8 bits ou 11 bits selon le format utilisé. Sur 8 bits, on peut coder 256 valeurs : les entiers compris entre $-127$ et $128$. Sur 11 bits, on peut coder 2048 valeurs : les entiers compris entre $-1023$ et $1024$.

Attention, les plages de valeurs des entiers sont différentes de celles du codage en complément à deux.
En effet, en complément à deux sur 8 bits (resp. 11 bits) on coderait les entiers compris entre $-128$ et $127$ (resp. entre $-1024$ et $1023$), comme on l'a vu dans le cours sur la représentation des entiers relatifs.

L’exposant est un entier relatif mais la norme IEEE 754 n’utilise pas l’encodage par complément à 2 des entiers relatifs. Elle prévoit un décalage qui dépend de l’encodage utilisé :

  • Dans le format simple précision (32 bits), le décalage est de 127, c’est-à-dire qu’il faut ajouter 127 à l’exposant.
  • Dans le format double précision (64 bits), le décalage est de 1023.

L’objectif est d’obtenir un nombre positif pour coder l’exposant. En effet, dans le format simple précision, en ajoutant $127$ à tous les entiers de la plage de valeurs $[-127 .. 128]$ on obtient des valeurs positives $[0..255]$ (de même, en ajoutant $1023$ dans le format double précision on obtient les valeurs $[0..2047]$).

Exemple (suite et fin) : Représentation machine du nombre $5,8125$

Rappelons que $5,8125=(101,1101)_2=(1,011101×2^2 )_2$ donc l’exposant est $2$.

La norme IEEE 754 ne prévoit pas de coder $+2$ en complément à deux mais d’ajouter $127$ en format simple précision ($1023$ en format double précision) : on obtient alors $2+127=129$.

Il ne reste plus qu’à coder l’entier $129$ en binaire : $({\color{blue} 10000001})_2$. On ajoute éventuellement des zéros (à gauche !!) pour compléter les 8 bits réservés à l’exposant (ici c'est inutile car on obtient 8 bits directement : 10000001)

Dans le format simple précision (sur 32 bits), on obtient finalement :

signe exposant mantisse (23 bits)
0 10000001 01110100...0

Dans le format double précision (sur 64 bits), on ajouterait $1023$ à la puissance pour obtenir $1025$ ($2+1023$) dont l’écriture binaire est $({\color{orange}10000000001})_2$ (qui est déjà sur 11 bits, donc inutile d'ajouter des zéros à gauche). On obtiendrait :

signe exposant mantisse (52 bits)
0 10000000001 01110100...0

Bilan :

  • En format simple précision, le nombre réel $5,8125$ est représenté sur 32 bits en machine par le mot binaire :

    0 10000001 01110100000000000000000
  • En format double précision, il est représenté sur 64 bits en machine par le mot :

    0 10000000001 0111010000000000000000000000000000000000000000000000

✍️ Pour s'entraîner : faites les exercices 2, 3, 4 et 5

Une représentation approximative

Codage approché de certains réels

Tous les nombres réels dont l’écriture en base est infinie ne peuvent être représentés de manière exacte en machine. Par exemple, on a vu que le nombre décimal $1,2$ a une écriture binaire infinie : $1,2=(1,001100110011…)_2=+1,001100110011\ldots \times 2^0$

La mantisse de ce nombre est $m=1,001100110011\ldots$ donc elle est infinie. Or, il n’y a que 23 ou 52 bits réservés pour coder la mantisse. L’ordinateur doit donc tronquer la mantisse à 23 ou 52 bits. Cela signifie qu’en format simple précision, la mantisse du nombre $1,2$ est codée par le mot binaire de 23 bits

$$\underbrace{001100110011001100110011001}_\textrm{23 bits}\xcancel{100110011 \ldots}$$

les autres bits ne pouvant pas être codés.

Seule une valeur tronquée de la mantisse peut être codée et donc la représentation en machine du nombre réel $1,2$ n’est qu’une approximation du réel $1,2$. Autrement dit, le nombre flottant 1.2 n’est qu’une valeur approchée du nombre réel $1,2$.

Cet exemple n’en est qu’un parmi tant d’autres : il y a une infinité de nombres réels qu’il est impossible de représenter de manière exacte en machine.

Méfiance

Dans un langage de programmation, il faut se méfier lorsque l’on manipule des nombres flottants. Par exemple, ajouter ou soustraire des flottants peut conduire à des résultats surprenants :

>>> 1.2 - 1.0
0.19999999999999996
>>> 0.5 - 0.2 - 0.2 - 0.1
-2.7755575615628914e-17
>>> 9007199254740992.0 + 1.0 + 1.0
9007199254740992.0
>>> 1 + 1 + 9007199254740992.0
9007199254740994.0

De même, il ne faut (théoriquement) jamais tester l'égalité entre deux flottants :

>>> 0.1 + 0.2 == 0.3
False
>>> from math import sqrt
>>> sqrt(2.0) ** 2 == 2.0
False
>>> 9007199254740992.0 + 1.0 == 9007199254740992.0
True

Il est important de noter que ces résultats ne sont pas des erreurs de Python, mais sont liées à la représentation approximative des nombres flottants en machine. Un ordinateur ne peut pas faire mieux !
Les calculs avec des flottants conduisent souvent à des résultats incohérents avec les résultats que l'on obtiendrait avec des nombres réels.

Impossibilité de coder tous les nombres réels

Voici l'écriture binaire en format double précision de deux flottants :

Nombre flottant Représentation au format double précision (mantisse sur 52 bits)
1.5 $+1.1000000000000000000000000000000000000000000000000000 \times 2^0$
1.5000000000000002 $+1.1000000000000000000000000000000000000000000000000001 \times 2^0$

Comme il n'y a pas de représentation possible entre les deux proposées (la mantisse de la seconde est celle qui suit immédiatement celle de la première), il n'existe donc pas de flottant entre 1.5 et 1.5000000000000002.

Le flottant 1.5000000000000001 n'a donc pas de représentation propre, il est représenté comme 1.5 pour un ordinateur (alors que le réel $1,5000000000000001$ est bien sûr différent du réel $1,5$) :

>>> 1.5 == 1.5000000000000001
True

La précision possible avec une mantisse sur 52 bits se situe au niveau dernier bit qui vaut $2^{-52}$ soit environ $2 \times 10^{-16}$. L’écart entre 1.5 et 1.5000000000000002 étant égal à $2 \times 10^{-16}$, on ne peut pas trouver un flottant compris entre les deux.

Bilan

  • Les nombres flottants sont une représentation approximative des nombres réels dans un ordinateur.
  • La représentation des flottants se base sur un équivalent en base 2, de l'écriture scientifique des nombres réels : $s.m\times 2^n$, où $s$ est le signe, $n$ est l'exposant et $m$ est la mantisse du nombre, chacun étant codé d'une manière et sur un nombre de bits définis pas la norme IEEE 754.
  • On a vu qu'il n’est pas possible de représenter de manière exacte en machine tous les nombres réels car ceux possédant une écriture décimale infinie en base 2 possèdent une mantisse infinie qui doit nécessairement être tronquée.
  • La manipulation de nombres réels par un langage informatique est donc à prendre avec précaution car elle peut engendrer des résultats surprenants, en particulier il ne faut jamais tester l’égalité entre deux flottants.

Références :

  • Documents ressources du DIU EIL de l'université de Nantes, Christophe DECLERCQ (diffusés sous licence CC BY-NC-SA).
  • Manuel Prépabac spécialité 1ère NSI, C. Adobet, G. Connan, G. Rozsavolgyi, L. Signac, éditions HATIER.
  • Manuel Numérique et Sciences Informatiques, T. Balabonski, S. Conchon, J.-C. Filliatre, K. Nguyen, éditions Ellipses.

Germain Becker & Sébastien Point, Lycée Emmanuel Mounier, Angers Licence Creative Commons BY-NC-SA

Voir en ligne : info-mounier.fr/premiere_nsi/types_base/reels