Changer l’ordre dans une opération de somme peut produire des résultats différents?

Changer l'ordre dans une opération de somme peut produire des résultats différents?

1. Vue d'ensemble

Dans cet article rapide, nous allons voir pourquoi la modification de l'ordre de somme renvoie un résultat différent.

2. Problème

Quand on regarde le code suivant, on peut facilement prédire la bonne réponse (13.22 + 4.88 + 21.45 = 39.55). Ce qui est facile pour nous pourrait être interprété différemment par le compilateur Java:

double a = 13.22;
double b = 4.88;
double c = 21.45;

double abc = a + b + c;
System.out.println("a + b + c = " + abc); // Outputs: a + b + c = 39.55

double acb = a + c + b;
System.out.println("a + c + b = " + acb); // Outputs: a + c + b = 39.550000000000004

D'un point de vue mathématique, changer l'ordre d'une somme devrait toujours donner le même résultat:

(A + B) + C = (A + C) + B

Cela est vrai et fonctionne bien en Java (et autres langages de programmation) pour les entiers. Cependant, presque tous les processeurs utilisent pour les nombres non entiersIEEE 754 binary floating point standard, ce qui introduit une imprécision lorsque le nombre décimal est stocké comme valeur binaire. Les ordinateurs ne peuvent pas représenter tous les nombres réels avec précision.

Lorsque nous modifions l'ordre, nous modifions également la valeur intermédiaire stockée dans la mémoire. Le résultat peut donc être différent. Dans l'exemple suivant, nous commençons simplement par la somme de A + B ou A + C:

double ab = 18.1; // = 13.22 + 4.88
double ac = 34.67; // = 13.22 + 21.45
double sum_ab_c = ab + c;
double sum_ac_b = ac + b;
System.out.println("ab + c = " + sum_ab_c); // Outputs: 39.55
System.out.println("ac + b = " + sum_ac_b); // Outputs: 39.550000000000004

3. Solution

En raison de l'inexactitude notoire des nombres en virgule flottante, double ne doit jamais être utilisé pour des valeurs précises. Cela comprend la monnaie. Pour des valeurs précises, nous pouvons utiliser la classeBigDecimal:

BigDecimal d = new BigDecimal(String.valueOf(a));
BigDecimal e = new BigDecimal(String.valueOf(b));
BigDecimal f = new BigDecimal(String.valueOf(c));

BigDecimal def = d.add(e).add(f);
BigDecimal dfe = d.add(f).add(e);

System.out.println("d + e + f = " + def); // Outputs: 39.55
System.out.println("d + f + e = " + dfe); // Outputs: 39.55

Maintenant, nous pouvons voir que dans les deux cas, les résultats étaient les mêmes.

4. Conclusion

Lorsque vous travaillez avec des valeurs décimales, nous devons toujours nous rappeler que les nombres en virgule flottante ne sont pas représentés correctement, ce qui peut entraîner des résultats inattendus et indésirables. Lorsque la précision est requise, nous devons utiliser la classeBigDecimal.

Comme toujours, le code utilisé tout au long de l'article se trouveover on GitHub.