En savoir plus

Les erreurs d'arrondi

Pourquoi un ordinateur affirme que 0,1 + 0,2 ne fait pas tout à fait 0,3, et comment ne jamais se faire piéger.

L'idée de base

Un ordinateur n'a pas une infinité de chiffres pour écrire un nombre. Il travaille en binaire avec une boîte de taille fixe (souvent 64 bits, le float dit à double précision). Dès qu'un nombre ne rentre pas exactement dans cette boîte, la machine l'arrondit au plus proche qu'elle sait représenter. Cette petite erreur, invisible au début, peut s'accumuler.

Ce n'est pas un défaut de Python ou de JavaScript : c'est la norme IEEE 754, identique dans presque tous les langages.

Le grand classique qui choque tout le monde

print(0.1 + 0.2) # 0.30000000000000004 print(0.1 + 0.2 == 0.3) # False

Pourquoi ? Parce que 0.1 en binaire, c'est comme 1/3 en décimal : 0,3333... à l'infini. La machine coupe. Trois petites coupures additionnées, et le résultat tombe à côté.

Démo : le calculateur à double affichage

Tape deux nombres décimaux et compare ce que voit l'humain (calcul exact) avec ce que voit la machine (calcul en float).

Addition

+
Vue machine (float)
-
Vue exacte (décimal)
-

Démo : l'accumulation qui dérape

On additionne 0.1 un grand nombre de fois. Chaque petite erreur va dans le même sens et finit par se voir. C'est ce genre de phénomène qui a fait rater sa cible au missile Patriot en 1991.

Somme répétée

Résultat attendu
-
Résultat obtenu (float)
-

Les deux grandes familles d'erreurs

TypeCe qui se passeExemple parlant
Arrondi de représentationLe nombre n'existe pas exactement en binaire0.1 n'est pas vraiment 0,1
Erreur d'annulationOn soustrait deux nombres très proches, les décimales utiles disparaissent1.0000001 - 1.0000000

Comment s'en protéger (réflexes de pro)

1. Ne jamais tester l'égalité de deux flottants. On compare à une tolérance :

if abs(a - b) < 1e-9: # assez proche ...

2. Pour l'argent : pas de float. On utilise decimal.Decimal ou on travaille en cents (entiers).

from decimal import Decimal print(Decimal("0.1") + Decimal("0.2")) # 0.3 exact

3. Sommer du plus petit au plus grand, ou utiliser math.fsum() qui compense les erreurs :

import math print(math.fsum([0.1] * 1_000_000)) # 100000.0 pile

Complément jumeau : les débordements de variables, quand c'est la taille de la boîte qui trahit.