Des écritures binaires infinies...
Écriture décimale avec une infinité de chiffres
Les nombres réels non décimaux ont une écriture décimale avec une infinité de chiffres après la virgule. On peut citer pour exemple :
\(\frac{1}{3}\), \(\pi\) ou encore \(\sqrt{2}\)
Ces nombres réels auront nécessairement aussi une écriture en base 2 avec une infinité de décimales.
Complément :
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 2 avec une infinité de décimales ne peuvent pas être représentés de manière exacte par des flottants.
Écriture décimale finie, écriture binaire infinie
Il existe également des nombres 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 décimal 0,1.
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
À 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,00011001100110011...)2 où la séquence 0011 se répète indéfiniment.
Ainsi, 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.
Conséquence
L'exemple précédent montre que même avec un seul chiffre après la virgule en décimal, il peut y avoir une infinité de chiffres après la virgule en binaire.
Cela permet de commencer à comprendre le résultat de l'instruction donnée en préambule du chapitre :
>>> 0.2 + 0.1 == 0.3
False
>>> 0.2 + 0.1
0.30000000000000004
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, on doit s'attendre à ce que des calculs faisant intervenir un tel nombre mènent à des erreurs dues à ce changement de base.
Fondamental :
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