Des écritures qui ne se terminent pas☘
Les nombres réels non décimaux ont une écriture décimale avec une infinité
de chiffres après la virgule.
Par exemple \frac{1}{3}, \pi ou \sqrt{2}.
Ces nombres réels auront nécessairement aussi une écriture en base deux avec une infinité de décimales.
Conséquence
Par nature, un nombre en machine ne peut avoir qu'un nombre fini de
chiffres.
Ainsi, tous les nombres réels ayant une écriture en base deux avec une
infinité de décimales ne peuvent pas être représentés de manière exacte
par des flottants.
Écriture finie en base 10, infinie en base 2☘
Il existe également des nombres en base 10 qui sont décimaux (donc ont une écriture décimale présentant un nombre fini de chiffres) mais qui n'ont pas un nombre fini de chiffres en base 2.
Ces nombres ne peuvent donc pas non plus être représentés de façon exacte en machine.
Exemple
Déterminer l'écriture en base deux du nombre (0,1)_{10}.
On a :
- 0,1 × 2 = 0,2 = 0 + 0,2
- 0,2 × 2 = 0,4 = 0 + 0,4
- 0,4 × 2 = 0,8 = 0 + 0,8
- 0,8 × 2 = 1,6 = 1 + 0,6
- 0,6 × 2 = 1,2 = 1 + 0,2
- 0,2 × 2 = 0,4 = 0 + 0,4
- 0,4 × 2 = 0,8 = 0 + 0,8
- 0,8 × 2 = 1,6 = 1 + 0,6
- 0,6 × 2 = 1,2 = 1 + 0,2
A ce stade, on voit que l'on retombe sur 0,2 : on va donc nécessairement réécrire les mêmes lignes que précédemment. Et on retombera sur 0,6 puis à nouveau sur 0,2.
On va ainsi boucler indéfiniment.
Ainsi (0,1)_{10} = (0,0 \; 0011 \; 0011 \; 0011 \; 0011...)_2 où la séquence 0011 se répète indéfiniment.
Conclusion☘
0.1
ne peut pas être traduit de façon exacte en machine puisque sa
représentation binaire n'a pas un nombre fini de 0
et de 1
.
L'exemple précédent montre que même avec un seul chiffre après la virgule en base 10, il peut y avoir une infinité de chiffres après la virgule en base 2.
Cela permet de commence à comprendre le résultat de l'instruction donnée en préambule du chapitre :
>>> 0.2 + 0.1 == 0.3
False
Pour additionner 0.1
et 0.2
, ces deux nombres sont d'abord traduit en
base 2. Comme 0.1
ne peut pas être traduit de façon exacte en machine
0.2
aussi d'ailleurs...), on doit s'attendre à ce que des calculs faisant
intervenir un tel nombre mènent à des erreurs dues à ce changement de base.
Important
En machine, le nombre décimal 0.1
est traduit en flottant en base deux.
Pour déterminer comment 0.1
est interprété en machine, on peut demander
son affichage avec 40 décimales. On peut constater que cet affichage
ne donne pas que des 0
puisqu'un arrondi a nécessairement lieu :
>>> print("{:.40f}".format(0.1))
0.1000000000000000055511151231257827021182
Le module decimal
permet d'effectuer le même constat :
>>> from decimal import Decimal
>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
Sans ce changement de base, le résultat de 0.1 + 0.2
pourrait être
correct :
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.2') == Decimal('0.3')
True