Frage

Wie kommt es, dass die Java BigDecimal kann dies schmerzhaft sein?

Double d = 13.3D;

BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(String.valueOf(d));


System.out.println("RESULT 1: "+bd1.toString());
System.out.println("RESULT 2: "+bd2.toString());

RESULT 1: 13.300000000000000710542735760100185871124267578125
RESULT 2: 13.3

Gibt es eine Situation, in der ein Ergebnis erwünscht wäre? Ich weiß, dass Java 1.5 die toString() Methode geändert, aber das war die beabsichtigte Konsequenz?

Auch merke ich, dass BigDecimal doubleValue() etc, aber die Bibliothek, die ich mit helfend arbeite verwendet eine toString() und das kann ich nicht ändern: - (

Prost.

War es hilfreich?

Lösung

Nun, die API Genügt diese scheinbare Widersprüchlichkeit im Konstruktor BigDecimal(double val):

  
      
  1. Die Ergebnisse dieses Konstruktor können etwas unberechenbar sein. Man könnte   davon ausgehen, dass das Schreiben neuer   BigDecimal (0.1) in Java erstellt ein   BigDecimal, die genau gleich ist,   0,1 (ein nicht-skalierte Wert von 1, mit einer Skala von 1), aber es ist tatsächlich gleich   zu   0,1000000000000000055511151231257827021181583404541015625. Dies liegt daran, dass 0,1 kann nicht sein,   genau wie ein Doppel dargestellt (oder,   was das betrifft, als ein binärer Bruch   jeder endlicher Länge). Somit wird der Wert   daß Weise wird die übergebenen   Konstruktor ist nicht genau gleich   0,1, Erscheinungen ungeachtet.

  2.   
  3. Das String-Konstruktor, auf der anderen Seite, ist vollkommen vorhersehbar:   Schreiben neue BigDecimal ( „0,1“) erstellt   ein BigDecimal, die genau gleich ist   0,1, wie man erwarten würde. Daher ist es in der Regel, dass die empfohlene   String-Konstruktor verwendet werden, in   Vorzug dieser.

  4.   
  5. Wenn ein Doppel muss für eine BigDecimal , Anmerkung als Quelle verwendet werden, die   Dieser Konstruktor stellt eine exakte   Umwandlung; es gibt nicht die gleiche   Ergebnis wie die doppelt auf eine Umwandlungs   String mit der   Double.toString (Doppel) Verfahren und   dann unter Verwendung der BigDecimal (String)   Konstrukteur. Um dieses Ergebnis zu erhalten, Verwendung   die statische valueOf (Doppel) Methode .

  6.   

Die Moral der Geschichte: Der Schmerz scheint selbstverschuldet, nur href verwenden <= "http://java.sun.com/javase/6/docs/api/java/math/BigDecimal.html#BigDecimal ( java.lang.String) "rel = "noreferrer"> new BigDecimal(String val) oder BigDecimal.valueOf(double val) statt =)

Andere Tipps

Ihr Problem hat nichts mit BigDecimal zu tun, und alles, was mit Double, die 13,3 nicht genau darstellen kann, da es Binärbrüche intern verwendet.

So Ihre Fehler werden in der ersten Zeile eingeführt. Die erste BigDecimal einfach bewahrt, während String.valueOf() hat einige fischig Runden, die die zweite führt den gewünschten Inhalt haben, ziemlich viel durch Glück.

Sie möchten sich darüber informieren, wie Fließkommawerte umgesetzt werden ( IEEE 754-1985 ). Und plötzlich wird alles werden kristallklar.

Dies ist nicht die Schuld der BigDecimal - es ist die Schuld von double ist. BigDecimal genau, die den genau Wert von d. String.valueOf wird nur das Ergebnis auf wenige Dezimalstellen zeigt.

Die Fraktionen mit binären Zahlentypen dargestellt (d. double, float) nicht genau in diesen Typen gespeichert werden.

    Double d = 13.3;        
    BigDecimal bdNotOk = new BigDecimal(d);
    System.out.println("not ok: " + bdNotOk.toString());

    BigDecimal bdNotOk2 = new BigDecimal(13.3);
    System.out.println("not ok2: " + bdNotOk2.toString());

    double x = 13.3;
    BigDecimal ok = BigDecimal.valueOf(x);
    System.out.println("ok: " + ok.toString());

    double y = 13.3;
    // pretty lame, constructor's behavior is different from valueOf static method
    BigDecimal bdNotOk3 = new BigDecimal(y);
    System.out.println("not ok3: " + bdNotOk3.toString());

    BigDecimal ok2 = new BigDecimal("13.3");
    System.out.println("ok2: " + ok2.toString());

    Double e = 0.0;
    for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary
    System.out.println("not ok4: " + e.toString()); // should be 1


    BigDecimal notOk5 = BigDecimal.valueOf(e);
    System.out.println("not ok5: " + notOk5.toString()); // should be 1

    /* 
     * here are some fractions that can be represented exactly in binary:
     * 0.5   = 0.1   = 1 / 2
     * 0.25  = 0.01  = 1 / 4
     * 0.75  = 0.11  = 3 / 4
     * 0.125 = 0.001 = 1 / 8
     */

Ausgabe:

not ok: 13.300000000000000710542735760100185871124267578125
not ok2: 13.300000000000000710542735760100185871124267578125
ok: 13.3
not ok3: 13.300000000000000710542735760100185871124267578125
ok2: 13.3
not ok4: 0.9999999999999999
not ok5: 0.9999999999999999

Verwenden Sie einfach BigDecimal.valueOf(d) oder new BigDecimal(s) .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top