Frage Wie man eine Zahl auf n Dezimalstellen in Java rundet


Was ich möchte, ist eine Methode, um ein Double in eine Zeichenkette zu konvertieren, die mit der Half-Up-Methode rundet - d. H. Wenn die zu gerundete Dezimalzahl 5 ist, wird sie immer auf die vorherige Zahl aufgerundet. Dies ist die Standardmethode der Rundung, die die meisten Menschen in den meisten Situationen erwarten.

Ich möchte auch, dass nur signifikante Ziffern angezeigt werden - d. H. Es sollte keine abschließenden Nullen geben.

Ich weiß, eine Methode, dies zu tun, ist die Verwendung der String.format Methode:

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

kehrt zurück:

0.91239

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

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

kehrt zurück:

0.91230

Eine andere Methode ist die Verwendung der DecimalFormatter:

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

kehrt zurück:

0.91238

Wie Sie jedoch sehen können, wird hier eine halbrunde Rundung verwendet. Das heißt, es wird abgerundet, wenn die vorherige Ziffer gerade ist. Was ich möchte ist das:

0.912385 -> 0.91239
0.912300 -> 0.9123

Was ist der beste Weg, dies in Java zu erreichen?


1021
2017-09-30 16:01


Ursprung


Antworten:


Benutzen setRoundingModeStellen Sie die RoundingMode explizit, um Ihr Problem mit der Half-Even-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));
}

gibt die Ausgabe:

12
123.1235
0.23
0.1
2341234.2125

583
2017-09-30 16:14



Angenommen value ist ein double, du kannst tun:

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

Das ist für 5-stellige Genauigkeit. Die Anzahl der Nullen gibt die Anzahl der Dezimalstellen an.


397
2017-09-30 16:07



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

Ich werde dir ein BigDecimal. Um die Saite rauszuholen, rufen Sie sie einfach an BigDecimalist es toString Methode oder die toPlainString Methode für Java 5+ für eine einfache Formatzeichenfolge.

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

164
2017-09-30 18:33



Sie können auch die

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

um sicher zu stellen, dass Sie die abschließenden Nullen haben.


98
2017-09-30 16:58



Wie einige andere bemerkt haben, ist die richtige Antwort, entweder zu verwenden DecimalFormat oder BigDecimal. Gleitkomma nicht haben Nachkommastellen, so dass Sie nicht auf eine bestimmte Anzahl von ihnen an erster Stelle runden / abschneiden können. Sie müssen in einer Dezimalzahl arbeiten, und genau das tun diese beiden Klassen.

Ich poste den folgenden Code als ein Gegenbeispiel zu allen Antworten in diesem Thread und tatsächlich überall in StackOverflow (und anderswo), die Multiplikation gefolgt von Abschneiden gefolgt von Division empfehlen. Den Verfechtern dieser Technik obliegt es zu erklären, warum der folgende Code in über 92% der Fälle die falsche Ausgabe liefert.

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

BEARBEITEN: Um einige der folgenden Kommentare zu beantworten, habe ich den Modulo-Teil der Testschleife mit Hilfe von BigDecimal und new MathContext(16) für die Moduloperation 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

75
2017-10-02 03:18



Angenommen, du hast

double d = 9232.129394d;

Sie können verwenden BigDecimal

BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();

oder ohne BigDecimal

d = Math.round(d*100)/100.0d;

mit beiden Lösungen d == 9232.13


71
2018-01-28 09:52



Sie können die DecimalFormat-Klasse verwenden.

double d = 3.76628729;

DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal =  Double.valueOf(newFormat.format(d));

52
2017-09-29 07:01



Real's Java Anleitung Beiträge Diese Lösung, die auch für Versionen vor Java 1.6 kompatibel ist.

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();

34
2017-09-01 11:14



double myNum = .912385;
int precision = 10000; //keep 4 digits
myNum= Math.floor(myNum * precision +.5)/precision;

30
2017-09-30 16:09



@Milhous: Das Dezimalformat für das Runden ist ausgezeichnet:

Sie können auch die

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

um sicher zu stellen, dass Sie die abschließenden Nullen haben.

Ich möchte hinzufügen, dass diese Methode sehr gut darin ist, ein tatsächliches zu liefern numerische, Rundungsmechanismus - nicht nur visuell, sondern auch bei der Verarbeitung.

Hypothetisch: Sie müssen einen Rundungsmechanismus in eine GUI implementieren Programm. Um die Genauigkeit / Genauigkeit einer Ergebnisausgabe einfach zu ändern Ändern Sie das Caret-Format (d. h. innerhalb der Klammern). Damit:

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

würde als Ausgabe zurückkehren: 0.912385

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

würde als Ausgabe zurückkehren: 0.91239

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

würde als Ausgabe zurückkehren: 0.9124

[EDIT: auch wenn das Caret-Format so ist ("# 0. ############") und du Geben Sie eine Dezimalzahl ein, z. 3.1415926, um des Arguments willen, DecimalFormat erzeugt keinen Müll (z. B. nachgestellte Nullen) und gibt zurück: 3.1415926 .. wenn du so geneigt bist. Zugegeben, es ist ein wenig wortreich für den Geschmack einiger Entwickler - aber hey, es hat einen geringen Speicherbedarf während der Verarbeitung und ist sehr einfach zu implementieren.]

Im Wesentlichen ist die Schönheit von DecimalFormat, dass es gleichzeitig die Zeichenfolge verarbeitet Aussehen - sowie das Niveau der Rundungsgenauigkeit eingestellt. Ergo: du erhalten Sie zwei Vorteile für den Preis einer Code-Implementierung. ;)


27
2017-07-03 15:50



Sie könnten die folgende Hilfsmethode verwenden:

public static double round(double valueToRound, int numberOfDecimalPlaces)
{
    double multipicationFactor = Math.pow(10, numberOfDecimalPlaces);
    double interestedInZeroDPs = valueToRound * multipicationFactor;
    return Math.round(interestedInZeroDPs) / multipicationFactor;
}

17
2018-04-27 15:56