Représentation approximative des nombres réels
La problématique est la suivante : comment représenter les nombres réels sur 32, 64 bits, sachant qu'il faut représenter les très grands nombres tout autant que les très petits.
Fondamental : Nombres réels et nombre décimaux
Tous les nombres réels peuvent être approchés aussi près qu'on le désire par des nombres décimaux ( \(\mathbb{D}\) est dense dans \(\mathbb{R}\)) :
Soit x un réel quelconque. Pour n entier naturel donné, soient \(a_n = E(10^n x) \in \mathbb{Z}\) puis \(d_n = \frac{a_n}{10^n} \in \mathbb{D}\). alors \(d_n \leqslant x <d_n+ \frac{1}{10^n}\)
\(d_n\) est une valeur décimal approchée de x à \(10^n\) près.
Fondamental : Écriture scientifique.
Tout nombre décimal peut s'écrire sous la forme : \(\pm m \times 10^n\)
avec m un nombre décimal tel que \(m \in [1 ; 10 [\) et n un entier relatif.
Cette forme s'appelle l'écriture scientifique du nombre décimal.
Exemple : Application : donner l'écriture scientifique des nombres suivants
2156
- 398879,62
0,000142
1,34
Définition : Norme IEEE 754
Cette norme IEEE 754 définit la représentation des nombres dit flottants ainsi que les opérations arithmétiques qui les concernent. Elle encode ces nombres sur 32 ou 64 bits.
Elle repose sur la représentation des nombres sur le modèle de l'écriture scientifique :
\((-1)^s m \times 2 ^{n-d}\)
\(s \in \{0 ; 1\}\) | \(n \in \mathbb{N}\) | \(m \in [1 ; 2[\) |
1 bit | 8 bits | 23 bits |
signe | exposant | mantisse |
Remarque :
L'exposant est décalé de 127 pour répondre au besoin de représentation des nombres relatifs (cf complément ci-dessous).
La mantisse étant un nombre de la forme 1,... , les 23 bits de la mantisse sont en fait utilisés pour coder les chiffres après la virgule qu'on appelle la fraction :
\(m = 1 + b_1 \times 2^{-1} + b_2 \times 2^{-2} + ... + b_{23} \times 2^{-23}\)
Complément : Exposant décalé de 127
Afin de représenter les exposants positifs et négatifs, la norme IEEE 754 n'utilise pas l'encodage par complément à 2 des entiers relatifs. On stocke l'exposant en décalant la valeur sous la forme d'un entier non signé. Pour un encodage sur 32 bits on se décale de 127. Cela permet de représenter des exposants signés entre [-127, 128] en translatant de 127 pour retrouver la valeur encodée en binaire.
Exemple : Trouver le nombre décimal à partir du nombre flottant sur 32 bits.
signe | exposant | fraction |
1 | 10000110 | 10101101100000000000000 |
signe : \((-1)^1= -1\)
exposant : \(2^7+ 2^2+2^1 -127 = 7\)
mantisse : \(1+ 2^{-1}+ 2^{-3}+ 2^{-5}+ 2^{-6}+ 2^{-8}+ 2^{-9} (= 1,677734375)\)
soit\( - (1+ 2^{-1}+ 2^{-3}+ 2^{-5}+ 2^{-6}+ 2^{-8}+ 2^{-9} ) \times 2^7 = - ( 2^7 + 2^6 + 2^4 + 2^2 + 2 + \frac{1}{2} + \frac{1}{4})\)
Soit \(-214,75\)
Méthode : Arrondis
La représentation des nombres décimaux par des flottants est une représentation approximative. Par exemple le nombre décimal 1,6 ne peut être représenté exactement par cet encodage.
Le mode par défaut de la norme est "au plus près" : le flottant le plus proche de la valeur exacte.
pour 1,6 c'est 0 01111111 10011001100110011001101
ce qui correspond au nombre décimal 1,60000002384185791015625
Exemple : Donner la valeur décimale des flottants codés sur 32 bits
1 01111110 11110000000000000000000
0 10000011 11100000000000000000000
solutions :
- 0,96875
30
Exemple : Donner les représentations flottantes sur 32 bits des nombres
128
-32,75
solutions :
\(128=1,0 \times 2^7\) donc s=0, m=0 et e = 127 + 7 = 134 c'est à dire 10000110
-32,75 donne s=1 et \(32 =2^5\) et \(0,75 = \frac{1}{2} + \frac{1}{4}\) donc \(32 = (1 + \frac{1}{2^6} + \frac{1}{2^7} )\times 2^5\)
donc m = 0000011000...et e = 127+5=132 soit 10000100
Simulation : Utiliser les flottants en Python
Simulation : Une fonction pour obtenir l'écriture d'un flottant
Écrire une fonction de paramètre x qui à un nombre ici x donne son écriture flottante.
Remarque : Une fonction pour obtenir l'écriture d'un flottant
la mantisse et l'exposant d'un nombre sont accessibles via le module math (toujours accessible) et la fonction frexp
>>> help(math.frexp)
Help on built-in function frexp in module math:
frexp(...)
frexp(x)
Return the mantissa and exponent of x, as pair (m, e).
m is a float and e is an int, such that x = m * 2.**e.
If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.
>>> math.frexp(2)
(0.5, 2)
>>> math.frexp(3)
(0.75, 2)
Complément : Application à la situation des impôts français.
Un thread Twittter qui parle de la problématique des flottants appliqué aux problèmes de la gestion des impôts en France :
https://twitter.com/DMerigoux/status/1322540405712367618
A l'aide des connaissances précédentes et d'une compréhension générale de l'anglais vous pouvez comprendre les enjeux informatiques de la gestion des impôts.