Verwendung von java.math.MathContext
-
08-06-2019 - |
Frage
Kürzlich habe ich versucht, die Verwendung von zu verstehen java.math.MathContext aber nicht richtig verstanden.Wird es zum Aufrunden verwendet? java.math.BigDecimal
.Wenn ja, warum werden nicht die Dezimalstellen, sondern sogar der Mantissenteil gerundet?
Aus API-Dokumenten habe ich erfahren, dass es dem in angegebenen Standard entspricht ANSI X3.274-1996
Und ANSI X3.274-1996/AM 1-2000
Spezifikationen, aber ich konnte sie nicht online lesen.
Bitte lassen Sie mich wissen, wenn Sie dazu eine Idee haben.
Lösung
@jatan
Danke für deine Antwort.Es ergibt Sinn.Können Sie mir bitte MathContext im Kontext der BigDecimal#round-Methode erklären?
Daran ist nichts Besonderes BigDecimal.round()
vs. irgendein anderes BigDecimal
Methode.In allen Fällen ist die MathContext
Gibt die Anzahl der signifikanten Ziffern und die Rundungstechnik an.Grundsätzlich besteht jedes aus zwei Teilen MathContext
.Es gibt eine Präzision, und es gibt auch eine RoundingMode
.
Die Präzision gibt wiederum die Anzahl der signifikanten Stellen an.Also, wenn Sie angeben 123
als Zahl und fragen Sie nach zwei signifikanten Ziffern, die Sie erhalten werden 120
.Es könnte klarer sein, wenn Sie in wissenschaftlicher Notation denken.
123
wäre 1.23e2
in wissenschaftlicher Notation.Wenn Sie nur zwei signifikante Ziffern behalten, erhalten Sie 1.2e2
, oder 120
.Indem wir die Anzahl der signifikanten Ziffern verringern, verringern wir die Genauigkeit, mit der wir eine Zahl angeben können.
Der RoundingMode
Teil gibt an, wie wir mit dem Präzisionsverlust umgehen sollen.Um das Beispiel wiederzuverwenden, wenn Sie es verwenden 123
als Zahl eingeben und nach zwei signifikanten Ziffern fragen, haben Sie Ihre Genauigkeit verringert.Mit einem RoundingMode
von HALF_UP
(der Standardmodus), 123
wird werden 120
.Mit einem RoundingMode
von CEILING
, Du wirst kriegen 130
.
Zum Beispiel:
System.out.println(new BigDecimal("123.4",
new MathContext(4,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.CEILING)));
System.out.println(new BigDecimal("123.4",
new MathContext(1,RoundingMode.CEILING)));
Ausgänge:
123.4
1.2E+2
1.3E+2
2E+2
Sie können sehen, dass sowohl die Genauigkeit als auch der Rundungsmodus die Ausgabe beeinflussen.
Andere Tipps
Informationen zum Runden nur des Bruchteils einer BigDecimal-Zahl finden Sie unter BigDecimal.setScale(int newScale, int roundingMode)
Methode.
Z.B.Um eine Zahl mit drei Nachkommastellen in eine mit zwei Nachkommastellen zu ändern und aufzurunden:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
Das Ergebnis ist ein BigDecimal mit dem Wert 1,24 (wegen der Aufrundungsregel)
Ich möchte hier einige Beispiele hinzufügen.Ich habe sie in früheren Antworten nicht gefunden, aber ich finde sie nützlich für diejenigen, die vielleicht irreführen wichtige Ziffer mit Anzahl Nachkommastellen.Nehmen wir an, wir haben einen solchen Kontext:
MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Für diesen Code:
BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
Es ist völlig klar, dass Ihr Ergebnis so ist 1.23E+3
wie die Jungs oben sagten.Die ersten signifikanten Ziffern sind 123...
Aber was ist in diesem Fall:
BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
Ihre Nummer wird nicht auf 3 Stellen nach dem Komma gerundet - Für jemanden ist es möglicherweise nicht intuitiv und es lohnt sich, es hervorzuheben.Stattdessen wird auf gerundet ersten 3 signifikanten Ziffern, die in diesem Fall „4 5 4“ sind.Der obige Code ergibt also 4.55E-7
und nicht drin 0.000
wie jemand erwarten konnte.
Ähnliche Beispiele:
BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX);
System.out.println(d3); // 0.00100
BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX);
System.out.println(d4); // 0.200
BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX);
System.out.println(d5); //4.00E-9
Ich hoffe, dieses offensichtliche, aber relevante Beispiel wäre hilfreich ...
Wenn ich Sie richtig verstehe, hört es sich so an, als würden Sie erwarten, dass der MathContext steuert, wie viele Ziffern nach dem Dezimalpunkt beibehalten werden sollen.Dafür ist es nicht gedacht.Es gibt an, wie viele Ziffern beibehalten werden sollen. gesamt.Wenn Sie also angeben, dass Sie drei signifikante Ziffern wünschen, erhalten Sie nur diese.
Zum Beispiel dies:
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(20)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(10)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(5)));
wird ausgeben:
1234567890.123456789
1234567890
1.2346E+9
Es ist nicht zum Spaß.Tatsächlich habe ich ein Online-Beispiel gefunden, in dem die Verwendung von angegeben ist MathContext
um die in BigDecimal gespeicherten Beträge/Zahlen zu runden.
Zum Beispiel,
Wenn MathContext
konfiguriert ist precision = 2
Und rounding mode = ROUND_HALF_EVEN
BigDecimal Number = 0.5294
, Ist gerundet Zu 0.53
Deshalb dachte ich, dass es sich um eine neuere Technik handelt und nutzte sie zum Abrunden.Es wurde jedoch zu einem Albtraum, weil es anfing, sogar einen Mentissa-Teil der Zahl zu runden.
Zum Beispiel,
Number = 1.5294
wird auf gerundet 1.5
Number = 10.5294
wird auf gerundet 10
Number = 101.5294
wird auf gerundet 100
....und so weiter
Das ist also nicht das Verhalten, das ich beim Runden erwartet habe (da Präzision = 2).
Es scheint eine gewisse Logik zu haben, denn anhand des Musters kann ich sagen, dass es die ersten beiden Ziffern (da die Genauigkeit 2 ist) der Zahl nimmt und dann Nullen bis zur Nummer anhängt.Anzahl der Ziffern entspricht dem ungerundeten Betrag (sehen Sie sich das Beispiel 101,5294 an ...)