2013-03-28 8 views
7

Kann jemand erklären, warum auf der Erde diese "gleichen" Ausdrücke unterschiedliche Werte zurückgeben?Android: Java-Rundungsfehler. Kann nicht verstehen warum?

(new BigDecimal(String.valueOf(131.7d))).multiply(new BigDecimal(String.valueOf(0.95d))).doubleValue() = 125.115 

(new BigDecimal(    131.7d)).multiply(new BigDecimal(    0.95d)).doubleValue() = 125.11499999999998 

Was macht BigDecimal zwischen ihnen?

+1

für die Stimmen, die zum Schließen als Duplikat stimmen, sind die Fragen ähnlich, aber keine Duplikate. – Woot4Moo

Antwort

5

Wenn Sie die API-Dokumentation lesen, finden Sie String.valueOf(dobule) verwendet Double.toString(double), um den Wert zu formatieren. Es ist vielleicht nicht offensichtlich, aber Double.toString(double) rundet den Wert, bevor es als String Formatierung:

Wie viele Stellen müssen für den Bruchteil m oder gedruckt werden? Es muss mindestens eine Ziffer zur Darstellung des Bruchteils und darüber hinaus so viele, aber nur so viele, mehr Ziffern, wie erforderlich sind, um den Argumentwert von benachbarten Werten des Typs doppelt zu unterscheiden. Das heißt, angenommen, dass x der exakte mathematische Wert ist, der durch die Dezimaldarstellung dargestellt wird, die durch diese Methode für ein endliches Nicht-Null-Argument d erzeugt wird. Dann muss d der doppelte Wert zu x sein; oder wenn zwei Doppelwerte gleich nahe x sind, dann müssen d einer von ihnen und das niederwertigste Bit der Mantisse von D sein muß 0.

Das Ergebnis davon ist, dass String.valueOf(131.7d) wird die Rückkehr Zeichenfolge "131.7", auch wenn der genaue Wert des Arguments 131.69999999999998863131622783839702606201171875 ist. Der Grund dafür ist, dass Dezimalbrüche nicht immer exakt mit binären Brüchen dargestellt werden können (wie bei Floats und Doubles).

So wird new BigDecimal(String.valueOf(131.7)) ein BigDecimal mit dem genauen Wert 131.7 erstellen. new BigDecimal(131.7) erstellt ein BigDecimal mit dem genauen Wert 131.69999999999998863131622783839702606201171875.

+0

Das erklärt den Punkt. Vielen Dank! – Christian

6

Wenn man sich die API documentation aussehen:

BigDecimal(double val) 
      Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. 

gegen

BigDecimal(String val) 
      Translates the string representation of a BigDecimal into a BigDecimal. 

Diese sind in der Tat nicht das Gleiche. Im Konstruktor double verwendet es eine Fließkommazahl (die von Natur aus ungenau ist). In dem String Konstruktor nimmt es den genauen Wert, den Sie angaben, und nicht, das eine Gleitkommaumwandlung vornimmt. Dies bedeutet jedoch, dass die obigen Konstruktoren nicht die "gleichen" Ausdrücke sind

+0

Es gibt also keine andere Möglichkeit, den "korrekten" Wert dieser Berechnung zu erhalten (131,7 * 0,95 = 125,115), als den Wert in einen String zu konvertieren, bevor er an BigDecimal übergeben wird. Das erscheint mir so seltsam! – Christian

+0

Ich verstehe nicht, warum 2 Konstruktoren mit den gleichen Eingabewerten, gibt 2 verschiedene Ergebnisse zurück. Wenn Double.valueOf (String.valueOf (131.7d)) == 131.7d, warum sollte BigDecimal unterschiedliche Werte zurückgeben? Es macht keinen Sinn für mich! – Christian

+2

Hmm, Sie beantworten Christian's Frage hier eigentlich nicht, da er in beiden Fällen mit 131,7d und 0,95d beginnt. Der Grund für den Unterschied, den er beobachtet, liegt nicht an den verschiedenen BigDecimal-Konstruktoren, sondern daran, dass String.valueOf (dobule) das Argument indirekt rundet, bevor es in eine Zeichenfolge konvertiert wird und keine Zeichenfolge mit dem genauen Wert des Arguments zurückgibt. – jarnbjo

Verwandte Themen