Aller au contenu

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