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.
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%[ 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:
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 WertBigDecimal
(nicht skalierter Wert und Skalierung) hat eine eindeutige Zeichenfolgendarstellung als Ergebnis der Verwendung vontoString
. Wenn diese Zeichenfolgendarstellung mithilfe des KonstruktorsBigDecimal
wieder inBigDecimal(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.
Verwenden Sie Konstruktor aus String: b1 = new BigDecimal("0.01");
(Folie 23) Ссылка
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.
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.
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%Tags und Links java bigdecimal