2012-08-14 12 views
58

Ich mache eine einfache Multiplikation mit BigDecimal und ich habe ein seltsames Verhalten bei der Multiplikation mit Null gefunden (Multiplikation mit Null ist in diesem Anwendungsfall korrekt).BigDecimal multiplizieren mit Null

Grund Mathematik sagt mir, dass alles, was von Null multipliziert wird gleich Null sein (siehe: Zero Product Property und Multiplication Properties)

Allerdings wird der folgende Code konsequent mit dem gleichen Fehler fehlschlagen:

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0))); 
java.lang.AssertionError: 
Expected :0 
Actual :0E-48 

Ist das eine Ungenauigkeit mit BigDecimal oder gibt es einen Nischenzweig der Mathematik, den ich irgendwo vermisse?

Hinweise: JDK 1.6.0_27 in IntelliJ 11

+3

Ja numerische Analyse schauen und insbesondere Annäherung und Abschneidefehler –

+0

Oder in 'double' Sie könnten schreiben 'assertEquals (0, 23.3 * 0, 0);';) –

+11

Und schauen Sie auch in 'BigDecimal.ZERO'. – EJP

Antwort

84

Sie können nicht verwenden, um die equals() Methode BigDecimals vergleichen läuft, wie diese Behauptung tut. Das ist, weil diese Funktion gleich die Skala vergleicht. Wenn die Skala anders ist, gibt equals() false zurück, auch wenn sie mathematisch gleich sind.

Sie können jedoch compareTo() verwenden zu tun, was Sie wollen:

Wie @assylias weist darauf hin, sollten Sie auch die new BigDecimal("22.3") Konstruktor verwenden doppelte Genauigkeit Probleme zu vermeiden.

BigDecimal expected = BigDecimal.ZERO; 
BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO); 
assertEquals(0, expected.compareTo(actual)); 

Es gibt auch eine Methode namens signum(), die -1, 0 oder 1 für negative Renditen, Null und positiv.So können Sie auch mit

assertEquals(0, actual.signum()); 
20

equals() auf BigDecimal prüft den internen Zustand BigDecimal zum Vergleich

finden Sie den Code unten

public boolean equals(Object x) { 
    if (!(x instanceof BigDecimal)) 
     return false; 
    BigDecimal xDec = (BigDecimal) x; 
    if (x == this) 
     return true; 
    if (scale != xDec.scale) 
     return false; 
    long s = this.intCompact; 
    long xs = xDec.intCompact; 
    if (s != INFLATED) { 
     if (xs == INFLATED) 
      xs = compactValFor(xDec.intVal); 
     return xs == s; 
    } else if (xs != INFLATED) 
     return xs == compactValFor(this.intVal); 

    return this.inflate().equals(xDec.inflate()); 
} 

für Null testen, ob Sie die Werte verwenden compareTo() vergleichen wollen

Ändern Sie Ihren Code in

assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0))); 

Update:

Verwenden Konstruktor String als Parameter für BigDecimal für Genauigkeit in Präzision überprüfen die entsprechenden Links unten


nehmen Siehe auch

47

Es gibt zwei Probleme mit dem Code:

  • Sie sollten BigDecimal mit compareTo vergleichen anstelle von Gleichen, wie die anderen Antworten geraten
  • aber Sie sollten auch Verwenden Sie den Zeichenkettenkonstruktor: new BigDecimal("22.3") anstelle des Doppelkonstruktors new BigDecimal(22.3), um doppelte Genauigkeitsprobleme zu vermeiden

Mit anderen Worten, der folgende Code (die compareTo korrekt verwendet) gibt nach wie vor falsch:

BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10)); 
System.out.println(bd.compareTo(BigDecimal.ONE) == 0); 

weil 0.1d * 10d != 1

+0

Danke für das Hervorheben der Konstruktoränderung – Richard

+0

@assylias "aber Sie sollten auch den Zeichenfolgenkonstruktor verwenden: new BigDecimal (" 22.3 ") anstelle des doppelten Konstruktors new BigDecimal (22.3), um doppelte Genauigkeitsprobleme zu vermeiden". Können Sie das Problem der doppelten Genauigkeit erklären? – Geek

+1

@Geek probiere diese 'System.out.println (new BigDecimal (" 0.1 "));' und diese 'System.out.println (new BigDecimal (0.1d));'. Der erste (String-Konstruktor) gibt "0.1" aus, während der zweite (Doppelkonstruktor) "0.100000000000000000055511151231257827021181583404541015625" ausgibt. Dies geschieht, weil ein Double nicht genau 0,1 darstellen kann. Mehr dazu [auf dieser Seite zum Beispiel] (http: // stackoverflow.com/questions/4937402/Verschieben-Dezimal-Stellen-über-in-einem-Doppel). – assylias