Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Table des matières
Nombres flottants
Problématique
On souhaite pouvoir représenter un nombre à virgule, positif ou négatif. Pour une raison qui apparaîtra plus loin, on qualifie les nombres à virgule de flottants.
Dans le cas des nombres négatifs, on adoptait une astuce, le complément à 2, qui nous permettait de ne rien changer aux circuits électroniques utilisés pour les calculs. Les cas des nombres à virgule est plus complexe et est complètement différent. En conséquence, un ordinateur possède des circuits électroniques différents selon qu'il fait des calculs avec des entiers ou des flottants.
Binaire naturel
Comme on le sait, on peut écrire n'importe quel nombre entier en binaire, que ce nombre soit positif ou négatif :
- $13 = 2^3 + 2^2 + 2^0$ donc on peut écrire $13 = 1101_b$
- $-13 = - 1101_b$
Il est également possible d'écrire des nombres à virgule :
$$13,625 = 2^3 + 2^2 + 2^0 + 2^{-1} + 2^{-3} \Rightarrow 13,75 = 1101,101_b$$
Voici une technique permettant d'être un peu plus efficace, surtout pour la partie à droite de la virgule.
$13,625 = 13 + 0,625$. La partie entière ne pose pas de difficulté, on procède comme avant. $13 = 1101_b$.
Pour $0,625$ on procède en multipliant par 2 la partie après la virgule et en retenant le chiffre à gauche.
- $0,625 \times 2 = \textbf{1},25$
- $0,25 \times 2 = \textbf{0},5$
- $0,5 \times 2 = \textbf{1},0$ et inutile d'aller plus loin.
On lit de haut en bas : $101$ c'est la partie décimale, c'est à dire $,101_b$.
Donc $13,625 = 1101,101_b$.
Exercice 1
Convertir en binaire les nombres suivants :
- 21,5
- –17,75
- 1,90625
- 46,625
- 0,3
Comme vous pouvez le voir avec le dernier nombre, il est possible qu'un nombre dont l'écriture se termine en décimal, ne se termine pas en binaire : L'écriture de 0,3 en binaire est infinie. Nous verrons que cela crée une difficulté. En effet, il ne sera pas possible de stocker une écriture binaire infinie dans la machine ce qui nous amènera à tronquer l'écriture et donc à approximer. Aussi étonnant que cela paraisse, quand on écrit en Python x = 0.3, x ne contient pas vraiment 0.3 mais une approximation !
Représentation machine
mantisse et exposant
Prenons $x = 55,40625$.
- Procéder comme précédemment.
On obtient : $x = 11 0111,01101_b$ - Décaler la virgule pour la placer juste après le premier $1$.
$x = 1,1011101101_b \times 10_b^{5}$
Je rappelle que $10_b = 2$ donc $\times 10_b^5 = \times 2^5$
Le nombre $1,1011101101_b$ est appelé mantisse et le 5 est l'exposant.
On parle de virgule flottante car comme en notation scientifique, c'est l'exposant qui détermine la position de la virgule. C'est de la que vient le nom de flottant.
Exercice 2
Donnez la mantisse et l'exposant pour les nombres suivants :
- 0,3515625
- 45,625
type float - IEEE754
Je vous donne ci-dessous la version longue des flottants qui utilise 64 bits. Il en existe une version courte en 32 bits mais pas sur Python. Faites attention si vous consultez une aide sur internet de ne pas confondre les deux. Pour plus de détails...
Exemple : Le nombre 0b 0100 0000 0100 1011101101000 ... 0000
- bit de signe
0donc + exposant + 1023 = 0b100 0000 0100 = 1028doncexposant = 5- mantisse : On lit
1011101101000 ... 0000, il faut comprendre
mantisse = 1.10111011010...00
Donc le nombre est $2^5 \times 1,1011101101_b = 110111,01101_b = 55,40625$
Exercice 3
Donner les nombres correspondant aux codages suivants :
1011 1111 1101 0101 1010 ... 00000100 0001 0011 1010 1111 1101 0100 0101 1100 ... 00000011 1111 1111 0000 0000 ... 0001
Le dernier cas donne une mesure de la précision relative du dernier bit.
En virgule flottante cette précision relative est à peu près constante : 0,000 000 000 000 01 % près !
Exercice 4
Convertir les nombres suivants :
- 497,625
- 1000
- –1240
3.2e5
Le dernier cas correspond à la notation pour $3,2 \cdot 10^5$.
Simple et double précision
Dans d'autres langages (C, C++, …) le flottant ordinaire est codé en 32 bits. On peut demander des flottants plus longs (64 bits), donc plus précis. On parle de réels en double précision, ce sont des double.
float approxime
Des nombres comme $\pi$ ou $\sqrt{2}$ ne peuvent pas être écrits avec une écriture décimale finie. On n'est donc pas surpris que le type float ne permette pas non plus de les écrire exactement.
Il est plus surprenant de voir que le nombre 0,1 ne peut pas, lui non plus, être écrit en float sans approximation.
Appliquons la méthode vue plus haut pour 0,1 :
- $0,1 \times 2 = \textbf{0},2$
- $0,2 \times 2 = \textbf{0},4$
- $0,4 \times 2 = \textbf{0},8$
- $0,8 \times 2 = \textbf{1},6$
- $0,6 \times 2 = \textbf{1},2$
- $0,2 \times 2 = \textbf{0},4$
- $0,4 \times 2 = \textbf{0},8$
- $0,8 \times 2 = \textbf{1},6$
- …
On en déduit que $0,1 = 0,00011001100110011..._b$. Cette écriture est infinie et il faudra la tronquer pour l'écrire en float. On approximera donc.
Quand en Python – et aussi dans la plupart des langages – on écrit x = 0.1, la variable n'est pas exactement égale à 0,1.
Si on écrit print(x) on ne s'en rend pas compte que x != 0.1 car l'affichage est limité aux 16 premières décimales.
>>> x = 0.1 >>> print(x) 0.1
Mais on peut forcer l'affichage de 60 décimales :
>>> x = 0.1
>>> print(f"{x:0.60f}")
0.100000000000000005551115123125782702118158340454101562500000
Il est possible d'imaginer des codages qui évitent ce genre de problème. Mais cela ferait perdre la grande efficacité des float pour pas grand chose car pour les calculs scientifiques, cette approximation ne pose pas de problème. Il existe néanmoins des outils de calcul exact qui utilisent une autre façon de stocker les nombres à virgule.
Cas extrêmes
exposant + 1023 est codé sur 11 bits, il pourrait donc aller de 0 à 2047. Mais on interdit ces valeurs, on se limite à la plage 1 à 2046.
Exercice 5
- Quel est le plus grand nombre que l'on peut représenter ?
- Quel est le nombre le plus proche de
0que l'on peut représenter ?
Valeurs spéciales
Ces cas spéciaux ne sont pas à connaître.
exposant + 1023 correspond aux bits 1 à 12 de la représentation (le bit 0 étant le signe).
Les valeurs 0 et 2047 sont gardées pour des nombres spéciaux.
- Pour
0on dit que le nombre est dénormalisé.// Dans ce cas,mantisse = 0,[52 bits de la mantisse]et sur les 11 bits précédent on codeexposant + 1022.// Cette technique permet d'atteindre0ce qui serait impossible autrement. 2047sert pour des cas spéciaux comme $\infty$ ouNaN: not a number.
Exercice 6
Quelle valeur correspond aux deux flottants dénormalisés :
0000 0000 0000 0000 … 00000000 0000 0000 0000 … 0001
Remarque : 1e-324 renvoie 0.0
Les calculs
Les nombres flottants ne sont généralement pas des représentations exactes des nombres. Ils supposent une approximation qui peut avoir des effets surprenants.
Par exemple : 0.1 + 0.2 != 0.3
N'hésitez pas à tester en console les exemples proposés.
Exercice 7
Expliquer ce cas surprenant :
>>> 0.1 + 0.1 + 0.1 0.30000000000000004
Exercice 8
Expliquer la différence :
>>> 1e16 + 1 - 1e16 0.0 >>> 1e16 - 1e16 + 1 1.0
Exercice 9
Expliquer la différence :
>>> 2**1024 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216 >>> 2.0**1024 OverflowError: (34, 'Numerical result out of range')
Exercice 10
- Quel est le problème avec le code à droite ?
- Comment modifier le programme pour qu'il produise le résultat attendu ?
x = 10
while x != 0:
x -= 0.1
print("fini")

