Ich habe eine Klasse mit einem float
Feld. Zum Beispiel:Implementieren "tolerant" `equals` &` hashCode` für eine Klasse mit Gleitkommamitgliedern
public class MultipleFields {
final int count;
final float floatValue;
public MultipleFields(int count, float floatValue) {
this.count = count;
this.floatValue = floatValue;
}
}
Ich muss in der Lage sein, Instanzen nach Wert zu vergleichen. Nun, wie kann ich equals
& hashCode
richtig implementieren?
Die übliche Art zu implementieren equals
und hashCode
ist nur alle Felder zu berücksichtigen. Z.B. Eclipse wird die folgende equals
erzeugen:
public boolean equals(Object obj) {
// irrelevant type checks removed
....
MultipleFields other = (MultipleFields) obj;
if (count != other.count)
return false;
if (Float.floatToIntBits(floatValue) != Float.floatToIntBits(other.floatValue))
return false;
return true;
}
(und eine ähnliche hashCode
, daß im wesentlichen berechnet count* 31 + Float.floatToIntBits(floatValue)
).
Das Problem dabei ist, dass meine FP-Werte Rundungsfehler unterliegen (sie können von Benutzereingaben, von einem DB, etc. stammen). Also brauche ich einen "toleranten" Vergleich. Die gemeinsame Lösung besteht darin, einen Epsilon-Wert zu vergleichen (siehe z.B. Comparing IEEE floats and doubles for equality). Allerdings bin ich nicht ganz sicher, wie ich equals
mit dieser Methode implementieren kann, und immer noch eine hashCode
, die mit equals
konsistent ist.
Meine Idee ist es, die Anzahl der signifikanten Stellen für den Vergleich, dann immer rund auf diese Anzahl von Ziffern in beide equals
und hashCode
zu definieren:
long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));
Dann, wenn ich alle Verwendungen von floatValue
mit comparisonFloatValue
in equals
ersetzen und sollte ich einen "toleranten" Vergleich bekommen, der mit hashCode
übereinstimmt.
- Funktioniert das?
- Sehen Sie irgendwelche Probleme mit diesem Ansatz?
- Gibt es einen besseren Weg, dies zu tun? Es scheint ziemlich kompliziert.
Haben Sie nur in Betracht gezogen, ** Fließkomma ** nicht zu verwenden und stattdessen zu einer Festkommadarstellung zu wechseln? –
@Karl: Ja, guter Punkt, und ja, tat ich. Das Problem ist, dass die DB den Wert als FP enthält (was schwer zu ändern ist, da es nicht unter unserer Kontrolle steht), so dass ich beim Lesen aus der DB runden müsste. Ich möchte das nicht tun, da ich denke, dass es besser ist, FP intern zu verwenden und nur die Ausgabe zu runden. – sleske
Hoppla, habe gerade bemerkt, dass ich den Operator^benutzt habe. Natürlich meinte ich die Potenzierung, nicht den binären Operator. Fixed um 'Math.pow' zu verwenden. – sleske