2008-08-11 12 views
42

Kürzlich habe ich versucht, die Verwendung von java.math.MathContext zu verstehen, aber nicht richtig verstanden. Wird es für die Rundung in java.math.BigDecimal verwendet, wenn ja, warum es nicht die Dezimalziffern, sondern sogar Mentissenteil.Verwendung von java.math.MathContext

Von API-Dokumentation, ich kam zu wissen, dass es den Standard in ANSI X3.274-1996 und ANSI X3.274-1996/AM 1-2000 Spezifikationen angegebenen, aber ich habe sie nicht zum Lesen online.

Bitte lassen Sie mich wissen, wenn Sie eine Idee dazu haben.

Antwort

35

@jatan

Danke für deine Antwort wird gleich. Es macht Sinn. Kannst du mir bitte MathContext im Kontext der BigDecimal # Round Methode erklären.

Es gibt nichts besonderes über BigDecimal.round()vs. andere BigDecimal Verfahren. In allen Fällen gibt MathContext die Anzahl der signifikanten Ziffern und die Rundungstechnik an. Grundsätzlich gibt es zwei Teile von jedem MathContext. Es gibt eine Präzision, und es gibt auch eine RoundingMode.

Die Genauigkeit gibt erneut die Anzahl der signifikanten Ziffern an. Wenn Sie also 123 als Zahl angeben und nach zwei signifikanten Ziffern fragen, erhalten Sie 120. Es könnte klarer sein, wenn Sie in wissenschaftlicher Notation denken.

123 wäre 1.23e2 in wissenschaftlicher Notation. Wenn Sie nur 2 signifikante Ziffern behalten, erhalten Sie 1.2e2 oder 120. Indem wir die Anzahl der signifikanten Stellen reduzieren, reduzieren wir die Genauigkeit, mit der wir eine Zahl angeben können.

Der RoundingMode Teil gibt an, wie wir mit dem Verlust der Genauigkeit umgehen sollen. Um das Beispiel wiederzuverwenden, wenn Sie 123 als die Nummer verwenden und nach zwei signifikanten Ziffern fragen, haben Sie Ihre Genauigkeit verringert. Mit RoundingMode von HALF_UP (der Standardmodus) wird 123120 werden. Mit einem RoundingMode von CEILING erhalten Sie 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 Präzision und der Rundungsmodus den Ausgang beeinflussen.

+0

Gibt es eine Möglichkeit, '123.4' zu formatieren, indem man 2 signifikante Zahlen in einer Zeichenkette wie' 120' gibt? Das sind 2 signifikante Zahlen (wie "1.2E2"), weil abschließende Nullen normalerweise nicht beim Abrufen signifikanter Zahlen berücksichtigt werden, es sei denn, es gibt eine nachgestellte Dezimalzahl. Und für meine Zwecke, wenn die zu formatierende Zahl '103.4' war, ist es mir egal, dass Sie nicht sagen können, dass es zwei Sig-Feigen in der resultierenden' 100'-Zahl gibt. Ich möchte einfachere/sauberere Anzeige von Zahlen. – hepcat72

4

Wenn ich Sie richtig verstehe, klingt es so, als ob Sie erwarten, dass der MathContext steuert, wie viele Ziffern nach dem Dezimalpunkt beibehalten werden sollen. Dafür ist es nicht da. Es gibt an, wie viele Ziffern zu behalten sind, insgesamt. Wenn Sie also angeben, dass Sie 3 signifikante Ziffern haben wollen, ist das alles, was Sie bekommen werden.

Zum Beispiel dieser:

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))); 

AUSGABE:

1234567890.123456789 
1234567890 
1.2346E+9 
+1

Danke. Wie würde ich wählen, wie viele Ziffern nach der Dezimalzahl beibehalten werden sollen? – Drew

+1

Das ist nicht wirklich eine Frage für BigDecimal. Bei BigDecimal sollten Sie stattdessen die Anzahl der signifikanten Ziffern angeben. Wie viele Nachkommastellen sollen beim Formatieren für die Anzeige ermittelt werden? Sie können das mit String.format() oder DecimalFormat.format() steuern. –

+0

@Drew Ich denke, dass Sie [BigDecimal.setScale] verwenden können (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/math/BigDecimal.java# BigDecimal.setScale% 28int% 2Cjava.math.RoundingMode% 29) Methode dafür. Der erste Parameter (Skalierung) gibt an, wie viele Zahlen Sie hinter dem Dezimalpunkt behalten möchten, und der zweite Parameter (Rundungsmodus) gibt das gewünschte Rundungsverhalten an. –

4

Es ist nicht zum Spaß. Tatsächlich habe ich ein Online-Beispiel gefunden, das die Verwendung von MathContext zum Runden der in BigDecimal gespeicherten Mengen/Zahlen angibt.

Zum Beispiel

Wenn MathContext konfiguriert ist precision = 2 und rounding mode = ROUND_HALF_EVEN

BigDecimal Number = 0.5294 haben, ist zu gerundet I 0,53

So dachte es sich um eine neuere Technik ist und verwendet es für Rundungszweck. Jedoch wurde es zum Albtraum, weil es angefangen hat, sogar mentissa Teil der Zahl zu runden.

Zum Beispiel

Number = 1.5294 zu 1.5

Number = 10.5294 abgerundet 10 auf gerundet

Number = 101.5294 auf 100 gerundet So

.... und so weiter

Das ist nicht das Verhalten Ich habe mit Rundung gerechnet (Genauigkeit = 2).

Es scheint, etwas Logik zu haben, weil vom Geprassel ich sagen kann, dass es die ersten zwei Ziffern (wie Präzision ist 2) der Zahl nimmt und dann 0 anfügt, bis die Nr. von Ziffern als unrounded Menge (Kasse am Beispiel 101,5294 ...)

+1

also können Sie stattdessen für Lösung vorschlagen? –

52

Für nur den Bruchteil eines BigDecimal Rundungs ​​Besuche die BigDecimal.setScale(int newScale, int roundingMode) Methode.

z. eine Zahl mit drei Ziffern nach dem Dezimalpunkt einem mit zwei Ziffern zu ändern, und Aufrunden:

BigDecimal original = new BigDecimal("1.235"); 
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP); 

Das Ergebnis hiervon ist ein BigDecimal mit dem Wert 1,24 (wegen der Regel Aufrunden)

+15

Dies ist die Antwort, die die Leute wünschen, wenn sie mit festen Dezimalzahlen arbeiten und eine feste Anzahl von Dezimalstellen behalten. Ich weiß nicht, warum Sun hier eine Fließkommaart "Präzision" verpatzt hat, aber das ist MathContext. –

9

Ich würde hier ein paar Beispiele hinzufügen. Ich habe sie in vorherigen Antworten nicht gefunden, aber ich finde sie nützlich für diejenigen, die vielleicht signifikante Ziffern mit der Nummer Dezimalstellen in die Irre führen. Nehmen wir an, wir solchen Kontext haben:

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 vollkommen klar, dass Ihr Ergebnis ist 1.23E+3 wie Jungs oben gesagt. Erste signifikante Ziffern sind 123 ...

Aber was in diesem Fall:

BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX); 
System.out.println(d2); 

Ihre Nummer nicht an 3 Stellen hinter dem Komma gerundet - für jemanden kann es nicht intuitiv und wert sein zu betonen. Stattdessen wird es auf die ersten 3 signifikanten Ziffern gerundet, die in diesem Fall "4 5 4" sind. Also über Code Ergebnisse in 4.55E-7 und nicht in 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, das offensichtlich, aber relevantes Beispiel wäre hilfreich ...