1475 Stimmen

Wie rundet man eine Zahl in Java auf n Dezimalstellen?

Was ich möchte, ist eine Methode zum Konvertieren eines Double in eine Zeichenfolge, die mit der Hälfte-up-Methode rundet - d.h. wenn die Dezimalzahl zu runden ist 5, es rundet immer auf die nächste Zahl. Dies ist die Standard-Rundungsmethode, die die meisten Menschen in den meisten Situationen erwarten.

Außerdem möchte ich, dass nur signifikante Ziffern angezeigt werden, d. h. es sollten keine Nullen am Ende stehen.

Ich weiß, dass eine Methode, dies zu tun, in der Verwendung der String.format Methode:

String.format("%.5g%n", 0.912385);

zurück:

0.91239

was großartig ist, aber es zeigt Zahlen immer mit 5 Dezimalstellen an, auch wenn sie nicht signifikant sind:

String.format("%.5g%n", 0.912300);

zurück:

0.91230

Eine andere Methode ist die Verwendung der DecimalFormatter :

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);

zurück:

0.91238

Wie Sie sehen können, wird dabei jedoch halbwegs gerade gerundet. Das heißt, es wird abgerundet, wenn die vorherige Ziffer gerade ist. Was ich möchte, ist dies:

0.912385 -> 0.91239
0.912300 -> 0.9123

Wie lässt sich dies in Java am besten erreichen?

886voto

curtisk Punkte 19336

Verwenden Sie setRoundingMode setzen Sie die RoundingMode explizit, um Ihr Problem mit der halben geraden Runde zu behandeln, dann verwenden Sie das Formatmuster für Ihre gewünschte Ausgabe.

Beispiel:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}

ergibt die Ausgabe:

12
123.1235
0.23
0.1
2341234.2125

EDIT : In der ursprünglichen Antwort wird nicht auf die Genauigkeit der doppelten Werte eingegangen. Das ist in Ordnung, wenn es Ihnen egal ist, ob auf- oder abgerundet wird. Wenn Sie aber eine genaue Rundung wünschen, müssen Sie die erwartete Genauigkeit der Werte berücksichtigen. Fließkommawerte haben intern eine binäre Darstellung. Das bedeutet, dass ein Wert wie 2,7735 intern nicht genau diesen Wert hat. Er kann etwas größer oder etwas kleiner sein. Wenn der interne Wert etwas kleiner ist, wird er nicht auf 2,7740 aufgerundet. Um hier Abhilfe zu schaffen, müssen Sie sich über die Genauigkeit der Werte, mit denen Sie arbeiten, im Klaren sein und diesen Wert vor dem Runden addieren oder subtrahieren. Wenn Sie z. B. wissen, dass Ihre Werte bis auf 6 Stellen genau sind, dann addieren Sie diese Genauigkeit zum Wert, um die Hälfte der Werte aufzurunden:

Double d = n.doubleValue() + 1e-6;

Um abzurunden, ziehen Sie die Genauigkeit ab.

530voto

asterite Punkte 7607

Angenommen, value ist eine double können Sie tun:

(double)Math.round(value * 100000d) / 100000d

Das gilt für eine Genauigkeit von 5 Ziffern. Die Anzahl der Nullen gibt die Anzahl der Dezimalstellen an.

214voto

MetroidFan2002 Punkte 28293
new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);

erhalten Sie eine BigDecimal . Um die Zeichenkette herauszuholen, rufen Sie einfach die BigDecimal 's toString Methode, oder die toPlainString Methode für Java 5+ für eine einfache Formatzeichenkette.

Beispielprogramm:

package trials;
import java.math.BigDecimal;

public class Trials {

    public static void main(String[] args) {
        int yourScale = 10;
        System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
    }

135voto

Milhous Punkte 14201

Sie können auch die

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);

um sicherzugehen, dass Sie die nachgestellten 0er haben.

99voto

user207421 Punkte 297318

Wie einige andere bereits angemerkt haben, ist die richtige Antwort, entweder DecimalFormat o BigDecimal . Fließkomma bedeutet nicht haben Nachkommastellen, so dass man gar nicht erst auf eine bestimmte Anzahl von Stellen runden/abschneiden kann. Sie müssen in einem Dezimalradix arbeiten, und genau das tun diese beiden Klassen.

Ich poste den folgenden Code als Gegenbeispiel zu all den Antworten in diesem Thread und in der Tat überall auf StackOverflow (und anderswo), die Multiplikation gefolgt von Trunkierung gefolgt von Division empfehlen. Es obliegt den Befürwortern dieser Technik zu erklären, warum der folgende Code in über 92 % der Fälle die falsche Ausgabe erzeugt.

public class RoundingCounterExample
{

    static float roundOff(float x, int position)
    {
        float a = x;
        double temp = Math.pow(10.0, position);
        a *= temp;
        a = Math.round(a);
        return (a / (float)temp);
    }

    public static void main(String[] args)
    {
        float a = roundOff(0.0009434f,3);
        System.out.println("a="+a+" (a % .001)="+(a % 0.001));
        int count = 0, errors = 0;
        for (double x = 0.0; x < 1; x += 0.0001)
        {
            count++;
            double d = x;
            int scale = 2;
            double factor = Math.pow(10, scale);
            d = Math.round(d * factor) / factor;
            if ((d % 0.01) != 0.0)
            {
                System.out.println(d + " " + (d % 0.01));
                errors++;
            }
        }
        System.out.println(count + " trials " + errors + " errors");
    }
}

Ausgabe dieses Programms:

10001 trials 9251 errors

EDIT : Um auf einige Kommentare einzugehen, habe ich den Modulus-Teil der Testschleife mit BigDecimal y new MathContext(16) für die Modulus-Operation wie folgt:

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

Ergebnis:

10001 trials 4401 errors

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X