Das Ändern der Reihenfolge in einer Summenoperation kann zu unterschiedlichen Ergebnissen führen?

Das Ändern der Reihenfolge in einer Summenoperation kann zu unterschiedlichen Ergebnissen führen?

1. Überblick

In diesem kurzen Artikel werden wir uns ansehen, warum das Ändern der Summenreihenfolge zu einem anderen Ergebnis führt.

2. Problem

Wenn wir uns den folgenden Code ansehen, können wir die richtige Antwort leicht vorhersagen (13,22 + 4,88 + 21,45 = 39,55). Was für uns einfach ist, könnte vom Java-Compiler anders interpretiert werden:

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

Aus mathematischer Sicht sollte das Ändern der Reihenfolge einer Summe immer das gleiche Ergebnis liefern:

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

Dies ist richtig und funktioniert gut in Java (und anderen Computerprogrammiersprachen) für ganze Zahlen. Fast alle CPUs verwenden jedoch nicht ganzzahlige ZahlenIEEE 754 binary floating point standard, was zu Ungenauigkeiten führt, wenn die Dezimalzahl als Binärwert gespeichert wird. Computer können nicht alle reellen Zahlen genau darstellen.

Wenn wir die Reihenfolge ändern, ändern wir auch den Zwischenwert, der im Speicher gespeichert ist, und daher kann das Ergebnis abweichen. Im nächsten Beispiel beginnen wir einfach mit der Summe von A + B oder 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. Lösung

Wegen der berüchtigten Ungenauigkeit von Gleitkommazahlen sollte double niemals für genaue Werte verwendet werden. Dies beinhaltet die Währung. Für genaue Werte können wir die KlasseBigDecimalverwenden:

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

Jetzt können wir sehen, dass in beiden Fällen die gleichen Ergebnisse erzielt wurden.

4. Fazit

Wenn Sie mit Dezimalwerten arbeiten, müssen Sie immer berücksichtigen, dass Gleitkommazahlen nicht korrekt dargestellt werden. Dies kann zu unerwarteten und unerwünschten Ergebnissen führen. Wenn Präzision erforderlich ist, müssen wir die KlasseBigDecimalverwenden.

Wie immer ist der im gesamten Artikel verwendete Codeover on GitHub.