Vergleichen von Fließkommawerten unter Java

Einen Integerwert unter Java zu vergleichen ist trivial. Man nehme zwei Variablen vom Typ Integer und vergleiche sie, unter Zuhilfenahme des entsprechenden Operators, miteinander:

int a = 7;
int b = 7;

boolean equal = a == b;

Am Ende ist der Wert in der Variable equal true, da die Werte in der Variable a und b identisch sind. Nun könnte das Ganze bei Fließkommazahlen ebenso funktionieren:

double a = 7;
double b = 7;

boolean equal = a == b;

Auch in diesem Fall ist das Ergebnis am Ende true. Trotzdem sollten Fließkommazahlen niemals auf diese Weise verglichen werden. Spätestens bei folgendem Beispiel fällt dies auf:

double a = 4.1 + 0.8;
double b = 5.7 - 0.8;

boolean equal = a == b;

Obwohl beide Rechnungen eigentlich 5,9 ergeben sollten, wird in der Variable equal der Wert false enthalten sein. Hintergrund hierfür ist die Speicherung der Fließkommazahlen. Diese ist im Standard IEEE 754 festgelegt. Bei dieser Darstellung besteht die Zahl aus einem Vorzeichen, einem Exponent und einer Mantisse. Bei der Umwandlung der Dezimalzahl in ihre binäre Darstellung und der Verrechnung kann es zu Ungenauigkeiten (z.B. bei der Rundung im Prozessor) kommen. Wenn diese Werte nun binär verglichen werden, sind sie nicht identisch. Statt durch direkten Vergleich, sollte die „Gleichheit“ durch eine Differenzrechnung ermittelt werden:

public static boolean compare(double a, double b) {
    return Math.abs(a - b) < 0.0001; // Diff smaller epsilon?
}

Nachdem die Differenz der beiden Werte gebildet wurde, wird überprüft ob diese kleiner als Epsilon sind. Epsilon stellt den Threshold bzw. eine Schwelle oder Toleranz dar. Solange die Differenz unter diesem Wert liegt, werden beide Werte als identisch angenommen. Natürlich fehlt in dieser Methode noch eine Absicherung gegenüber NaN-Werten.

Statt sich eine solche Methode selber zu schreiben, können Methoden aus bekannten Utility-Bibliotheken wie Guava (DoubleMath.fuzzyCompare) genutzt werden.

2 Kommentare » Schreibe einen Kommentar

  1. Das gefährliche ist, wenn man sowas auf Strings anwendet. Ich denke wenn man

    String a = „foo“
    String b = „foo“
    boolean c = a == b

    macht, bekommt man false raus, da man hier einen pointer-vergleich durchführt. Ich denke man sollte im generellen eher die methoden als == nutzen

    • In anderen Sprachen wie C#; in denen das Overloading von Operatoren erlaubt ist, funktioniert das wieder. Dann ist es wirklich schwierig das unter Java wieder abzulegen ;)

Schreibe einen Kommentar zu Martin Antworten abbrechen

Pflichtfelder sind mit * markiert.