java BigDecimal Subaktion fehlgeschlagen

7

Ich habe den folgenden Code ausprobiert. aber beim Subtrahieren mit BigDecimal erhalten Sie ein anderes Ergebnis.

%Vor%

Ergebnis:

%Vor%

Ich arbeite immer noch daran. Kann mir bitte jemand erklären.

    
user1514499 15.03.2013, 09:21
quelle

8 Antworten

4

Interessant, die Werte scheinen gleich zu sein und die Subtraktion gibt Ihnen null, es scheint nur ein Problem mit dem Druckcode zu sein. Der folgende Code:

%Vor%

gibt beide equal -Meldungen aus, um anzuzeigen, dass die Werte gleich sind und Sie null erhalten, wenn Sie subtrahieren.

Du könntest versuchen, dies als Bug anzuzeigen und zu sehen, womit Oracle zurückkommt. Wahrscheinlich geben sie nur an, dass 0e-59 immer noch Null ist, also kein Bug, oder dass das ziemlich komplexe Verhalten auf BigDecimal-Dokumentationsseite funktioniert wie beabsichtigt. Insbesondere der Punkt, der besagt:

  

Es gibt eine Eins-zu-Eins-Zuordnung zwischen den unterscheidbaren BigDecimal-Werten und dem Ergebnis dieser Konvertierung. Das heißt, jeder unterscheidbare BigDecimal-Wert (unskalierter Wert und Skalierung) hat eine eindeutige Zeichenfolgendarstellung als Ergebnis der Verwendung von toString. Wenn diese Zeichenfolgendarstellung mithilfe des BigDecimal (String) -Konstruktors wieder in BigDecimal konvertiert wird, wird der ursprüngliche Wert wiederhergestellt.

Die Tatsache, dass der ursprüngliche Wert wiederhergestellt werden muss, bedeutet, dass toString() eine eindeutige Zeichenfolge für jede Skala generieren muss, weshalb Sie 0e-59 erhalten. Andernfalls kann die Umwandlung der Zeichenfolge zurück in BigDecimal zu einem anderen Wert führen (nicht skalierter Wert / Tupel skalieren).

Wenn Sie möchten, dass Null unabhängig von der Skalierung als "0" angezeigt wird, können Sie Folgendes verwenden:

%Vor%     
paxdiablo 15.03.2013, 09:23
quelle
11

[ Es gibt viele Antworten hier, die Ihnen sagen, dass binärer Gleitkomma nicht genau 0,01 darstellen kann, und damit impliziert, dass das Ergebnis, das Sie sehen, irgendwie ungenau ist. Während der erste Teil davon wahr ist, ist es nicht wirklich das Kernproblem hier. ]

Die Antwort ist, dass "0E-59" gleich 0 ist. Denken Sie daran, dass ein BigDecimal die Kombination aus einem unskalierten Wert und einem Dezimalskalierungsfaktor ist:

%Vor%

wird angezeigt:

%Vor%

Der unskalierte Wert ist 0, wie erwartet. Der "seltsame" Skalierungswert ist einfach ein Artefakt der Dezimal-Erweiterung der nicht-exakten Gleitkommadarstellung von 0,01:

%Vor%

wird angezeigt:

%Vor%

Die nächste offensichtliche Frage ist, warum zeigt BigDecimal.toString nicht einfach b1 als " 0 " an, aus Gründen der Bequemlichkeit? Die Antwort ist, dass die String-Darstellung eindeutig sein muss. Aus dem Javadoc für toString :

  

Es gibt eine Eins-zu-eins-Zuordnung zwischen den unterscheidbaren BigDecimal -Werten und dem Ergebnis dieser Konvertierung. Das heißt, jeder unterscheidbare Wert BigDecimal (nicht skalierter Wert und Skalierung) hat eine eindeutige Zeichenfolgendarstellung als Ergebnis der Verwendung von toString . Wenn diese Zeichenfolgendarstellung mithilfe des Konstruktors BigDecimal wieder in BigDecimal(String) konvertiert wird, wird der ursprüngliche Wert wiederhergestellt.

Wenn nur " 0 " angezeigt wird, können Sie nicht zu genau diesem BigDecimal -Objekt zurückkehren.

    
Oliver Charlesworth 15.03.2013 09:35
quelle
7

Verwenden Sie Konstruktor aus String: b1 = new BigDecimal("0.01");

Java Genauigkeitsverlust

(Folie 23) Ссылка

    
Ivan Borisov 15.03.2013 09:24
quelle
2

Sie müssen den Rückgabewert erhalten:

%Vor%     
ghdalum 15.03.2013 09:23
quelle
2

BigDecimal (doppelter Wert)

  

1.Die Ergebnisse dieses Konstruktors können etwas unvorhersehbar sein. Man könnte annehmen, dass das Schreiben neuer BigDecimal (0.1) in Java ein erzeugt   BigDecimal, das genau gleich 0,1 ist (ein unskalierter Wert von 1, mit   eine Skala von 1), aber es ist tatsächlich gleich   0.1000000000000000055511151231257827021181583404541015625. Dies liegt daran, dass 0.1 nicht genau als ein Doppel dargestellt werden kann   Materie als binärer Bruchteil beliebiger endlicher Länge). Also der Wert   das dem Konstruktor übergeben wird, ist nicht genau gleich   0,1, Erscheinungen ungeachtet.

     

2.Der String-Konstruktor hingegen ist perfekt vorhersagbar: Das Schreiben neuer BigDecimal ("0.1") erzeugt ein BigDecimal, das genau ist   gleich 0,1, wie man erwarten würde. Daher ist es allgemein   empfohlen, dass stattdessen der String-Konstruktor verwendet wird   eins.

     

3.Wenn ein double als Quelle für ein BigDecimal verwendet werden muss, beachten Sie, dass dieser Konstruktor eine exakte Konvertierung bereitstellt. es gibt nicht die   Das gleiche Ergebnis wie das Konvertieren des Double in einen String mit dem   Double.toString (double) -Methode und dann BigDecimal (String) verwenden   Konstrukteur. Um dieses Ergebnis zu erhalten, verwenden Sie den statischen WertOf (double)   Methode.

    
Achintya Jha 15.03.2013 09:31
quelle
2

Die eigentliche Frage ist also: mit dem folgenden Code,

%Vor%

Warum wird b1.toString() als "0E-59" ausgewertet und nicht als "0.0" , "0E0" oder nur "0" ?

Der Grund dafür ist, dass toString() das kanonische Format von BigDecimal ausgibt. Weitere Informationen finden Sie BigDecimal.toString () Informationen.

Am Ende ist 0E-59 ist 0.0 - es ist 0*10^59 , was mathematisch zu 0 auswertet. Das unerwartete Ergebnis ist also eine Frage der internen Repräsentation von BigDecimal .

Um die Float- oder Double-Werte zu erhalten, verwenden Sie

%Vor%

oder

%Vor%

Beide werden als 0.0 ausgewertet.

    
Andreas Fester 15.03.2013 09:26
quelle
1

Es ist ein bekanntes Problem, BigDecimal (double val) API Die Ergebnisse dieses Konstruktors können etwas unvorhersehbar sein. Obwohl es in dieser Interpertation wirklich seltsam aussieht. Der tatsächliche Grund ist, dass ein neues BigDecimal (0.01) ein BigDecimal mit ungefähren Werten

erzeugt %Vor%

, das eine hohe Genauigkeit hat, und so hat das Ergebnis der Subtraktion auch eine lange Genauigkeit.

Wie auch immer, wir können das "Problem" auf diese Weise lösen

%Vor%

oder wir können einen Konstruktor verwenden, der eine Genauigkeit festlegt

%Vor%     
Evgeniy Dorofeev 15.03.2013 09:28
quelle
1

Verwenden Sie so:

%Vor%     
user7046332 20.10.2016 07:08
quelle

Tags und Links