2010-10-05 8 views
35

Eigentlich habe ich mögliche LösungWarum BigDecimal ("5.50") nicht gleich BigDecimal ("5.5") ist und wie Sie dieses Problem umgehen können?

//returns true 
new BigDecimal ("5.50").doubleValue() == new BigDecimal("5.5").doubleValue() 

Natürlich gefunden, kann es mit so etwas wie Math.abs (v1 - v2) < EPS verbessert wird der Vergleich robuster zu machen, aber die Frage ist, ob diese Technik akzeptabel oder gibt es eine bessere Lösung?

Wenn jemand weiß, warum sich Java-Entwickler dafür entschieden, BigDecimal auf diese Weise zu implementieren, wäre es interessant zu lesen.

+7

Wenn Ihre BigDecimal Objekte garantiert werden durch Doppel immer darstellbare sein, dann sollten Sie nicht sowieso mit BigDecimal sein. Wenn dies nicht der Fall ist, wird diese Methode fehlschlagen. – DJClayworth

+2

Schlechte Lösung. Wenn Doppelpunkte für Ihr Programm geeignet sind, verwenden Sie Doppel. Wenn BigDecimals geeignet sind, verwenden Sie BigDecimals. Es ist fast nie sinnvoll, hin und her zu konvertieren. – Jay

+0

@DJClayworth: Wo siehst du "editierte" Label? – Roman

Antwort

68

Vom javadoc von BigDecimal

gleich

public boolean equals(Object x)

Vergleicht diese BigDecimal mit dem angegebenen Object auf Gleichheit. Im Gegensatz zu compareTo berücksichtigt diese Methode zwei BigDecimal Objekte gleich nur, wenn sie in Wert und Maßstab gleich sind (also 2,0 ist nicht gleich 2,00 im Vergleich mit dieser Methode). verwenden

einfach compareTo() == 0

+0

....... Aber warum? – bacar

+0

Da die Implementierung von 'equals' nicht nur auf dem Wert, sondern auch auf der Skala basiert, vermeiden Sie' new BigDecimal ("5.01"). Equals (new BigDecimal ("5.0")) == false 'while' new BigDecimal ("5.0"). gleich (new BigDecimal ("5.01")) == true'. All dies, weil ['equals()' symmetrisch ist] (http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals (java.lang.Object)). –

+2

Sie müssen nicht auf Symmetrie verzichten, um 'equals' als Zahlenwertvergleich zu implementieren, also ist Symmetrie nicht der Grund. Ich habe die "Warum" -Frage hier explizit gestellt: [Warum wird BigDecimal.equals angegeben, um sowohl den Wert als auch den Maßstab individuell zu vergleichen?] (Http://stackoverflow.com/questions/14102083/why-is-bigdecimal-equals-specified (sowohl einzeln als auch einzeln) – bacar

7

== Mit Doppel seems like a bad idea im Allgemeinen zu vergleichen.

Sie könnten setScale auf die gleiche Sache auf die Zahlen rufen Sie vergleichen:

new BigDecimal ("5.50").setScale(2).equals(new BigDecimal("5.5").setScale (2)) 

, wo Sie die Skala auf den größeren der beiden Einstellung würde:

BigDecimal a1 = new BigDecimal("5.051"); 
BigDecimal b1 = new BigDecimal("5.05"); 
// wow, this is awkward in Java 
int maxScale = Collections.max(new ArrayList() {{ a1.scale(), b1.scale()}}); 
System.out.println(
    a1.setScale(maxScale).equals(b1.setScale(maxScale)) 
    ? "are equal" 
    : "are different"); 

Mit compareTo() == 0 ist aber die beste Antwort. Die Erhöhung der Skala von einem der Zahlen in meinem Ansatz oben ist wahrscheinlich die „unnötige Inflation“, dass die compareMagnitude Methode Dokumentation zu erwähnen ist, wenn er sagt:

/** 
* Version of compareTo that ignores sign. 
*/ 
private int compareMagnitude(BigDecimal val) { 
    // Match scales, avoid unnecessary inflation 
    long ys = val.intCompact; 
    long xs = this.intCompact; 

und natürlich compareTo viel einfacher ist, da zu verwenden, Es ist bereits für Sie implementiert.

+6

tun Sie dies nur, wenn Sie "5.051" == "5.05" berücksichtigen möchten, da die setScale (2) diese zusätzliche Ziffer ablegt, während .compareTo (andere) die Werte ohne Berücksichtigung der Skalierung –

+3

Gareth, 'setScale' vergleicht Ohne Parameter für den Rundungsmodus werden die zusätzlichen Ziffern nicht gelöscht, stattdessen wird eine ArithmeticException ausgelöst. Dies würde nur funktionieren, wenn die zusätzlichen Ziffern nur Nullen sind. –

+0

@Gareth: Danke für die Rückmeldung. Zu der Zeit, als ich das vor langer Zeit schrieb, wurde ich nicht in Kommentare und Benachrichtigungen eingeweiht, also habe ich das verpasst. endlich aufgefallen und aktualisiert unter Berücksichtigung Ihres Kommentars. –

4

der einfachste Ausdruck ignorieren führende Nullen zu vergleichen, ist seit Java 1.5:

bd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())