Pourquoi 0.1 + 0.2 != 0.3 ?
Une histoire de changement de base
Si vous avez déjà un peu programmé, quel que soit le langage que vous ayez utilisé vous avez sûrement dû vous heurter à ce problème.
À titre d'exemple, l'opération 0.1 + 0.2
ne retourne pas exactement 0.3
comme attendu mais plutôt 0.30000000000000004
.
Mais que se passe-t-il donc ?
Pour ce faire, il faut tout d'abord comprendre comment les nombres à virgule flottante sont représentés par votre ordinateur. La norme utilisée par quasiment tous les matériels est l'IEEE-754. Elle définit deux codages ; un sur 4 octets (32 bits) et un autre sur 8 octets (64 bits) mais l'implémentation reste globalement la même pour les deux. Les valeurs que je vais donner correspondent au codage sur 8 octets car étant le plus utilisé.
Vous connaissez très certainement la notation scientifique d'un nombre ; au lieu d'écrire c = 300 000 000 m/s
on préfère utiliser c = 3*10^8 m/s
ou c = 3E8 m/s
.
Cela permet d'écrire de grands nombres sans utiliser trop de caractères. Figurez-vous que c'est exactement la même chose pour l'ordinateur.
Sur les 64 bits de codage :
- 1 bit est utilisé pour coder le signe
- 11 bits sont utilisés pour coder l'exposant
- 52 bits sont utilisés pour coder la mantisse
L'exposant représente la puissance de 10 et la mantisse un nombre entre 0 inclus et 10 exclu. Sauf qu'ils sont tous deux stockés en binaire ce qui pose un problème car nous comptons en base 10 ! Pour résoudre ce problème, votre ordinateur va procéder à un changement de base et c'est justement ce changement de base qui est la source de cette particularité.
Il se trouve que 0.1
est représenté comme valant légèrement plus, mais cette imprécision est corrigée par votre ordinateur en tronquant les décimales trop imprécises (lorsque supérieures à 16).
De la même façon, 0.2
vaut lui aussi légèrement plus et encore une fois l'erreur est corrigée.
Mais lorsqu'il s'agit de les additionner, les erreurs se cumulent et l'arrondi le plus proche est tranché : c'est 0.30000000000000004
qui est choisi à la place de 0.3
.
Comment y remédier
Les moyens pour contourner ce problème sont variables suivant les langages. Mais certaines choses restent valables quelque soit la plateforme utilisée :
- N'affichez pas directement les nombres à virgule flottante, utilisez plutôt un formateur.
- Lorsque vous effectuez une comparaison, assurez vous de toujours définir un seuil de précision (threshold). Pour tester si un nombre est égal à zéro, il faudra par exemple procéder de la manière suivante
abs(value) < threshold
à la place devalue == 0.0
. - Si vous avez la possibilité de travailler avec des entiers à la place de nombres à virgule flottante (en vous assurant que les valeurs ne soient pas trop grande), faites le.