L'idée de base#
Un ordinateur n'a pas une infinité de chiffres pour écrire un nombre. Il travaille en binaire avec une boite de taille fixe (souvent 64 bits, le float dit a double précision). Des qu'un nombre ne rentre pas exactement dans cette boite, 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) # FalsePourquoi ? Parce que 0.1 en binaire, c'est comme 1/3 en décimal : 0,3333... a l'infini. La machine coupe. Trois petites coupures additionnées, et le résultat tombe a coté.
Démo : le calculateur a 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
Démo : l'accumulation qui dérape#
On additionne 0.1 un grand nombre de fois. Chaque petite erreur va dans le meme sens et finit par se voir. C'est ce genre de phénomene qui a fait rater sa cible au missile Patriot en 1991.
Somme répétée
Les deux grandes familles d'erreurs#
| Type | Ce qui se passe | Exemple parlant |
|---|---|---|
| Arrondi de représentation | Le nombre n'existe pas exactement en binaire | 0.1 n'est pas vraiment 0,1 |
| Erreur d'annulation | On soustrait deux nombres tres proches, les décimales utiles disparaissent | 1.0000001 - 1.0000000 |
Comment s'en protéger (réflexes de pro)#
1. Ne jamais tester l'égalité de deux flottants. On compare a 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).
3. Sommer du plus petit au plus grand, ou utiliser math.fsum() qui compense les erreurs :