Question Comment arrondir un nombre à n décimales en Java


Ce que j'aimerais, c'est une méthode pour convertir un double en une chaîne qui arrondit en utilisant la méthode demi-up - c'est-à-dire si la décimale à arrondir est 5, elle arrondit toujours au nombre précédent. C'est la méthode standard d'arrondi que la plupart des gens attendent dans la plupart des situations.

Je voudrais également que seuls les chiffres significatifs soient affichés, c'est-à-dire qu'il ne devrait pas y avoir de zéros de fin.

Je sais qu'une méthode de faire cela est d'utiliser le String.format méthode:

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

résultats:

0.91239

ce qui est génial, mais il affiche toujours des nombres avec 5 décimales même s'ils ne sont pas significatifs:

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

résultats:

0.91230

Une autre méthode consiste à utiliser le DecimalFormatter:

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

résultats:

0.91238

Cependant, comme vous pouvez le voir, cela utilise des arrondis à moitié égales. C'est-à-dire qu'il arrondira à la baisse si le chiffre précédent est pair. Ce que j'aimerais, c'est ceci:

0.912385 -> 0.91239
0.912300 -> 0.9123

Quel est le meilleur moyen d'y parvenir en Java?


1021
2017-09-30 16:01


origine


Réponses:


Utilisation setRoundingMode, met le RoundingMode explicitement pour gérer votre problème avec la demi-ronde, puis utilisez le modèle de format pour votre sortie requise.

Exemple:

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

donne la sortie:

12
123.1235
0.23
0.1
2341234.2125

583
2017-09-30 16:14



En supposant value est un double, tu peux faire:

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

C'est pour la précision de 5 chiffres. Le nombre de zéros indique le nombre de décimales.


397
2017-09-30 16:07



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

vous obtiendrai un BigDecimal. Pour obtenir la chaîne, appelez ça BigDecimalde toString méthode, ou la toPlainString méthode pour Java 5+ pour une chaîne de format plain.

Exemple de programme:

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



Vous pouvez également utiliser le

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

pour vous assurer que vous avez les 0 à la fin.


98
2017-09-30 16:58



Comme d'autres l'ont noté, la bonne réponse est d'utiliser soit DecimalFormat ou BigDecimal. Le flottant ne fait pas avoir décimales de sorte que vous ne pouvez pas éventuellement arrondir / tronquer à un nombre spécifique d'entre eux en premier lieu. Vous devez travailler dans une base décimale, et c'est ce que font ces deux classes.

Je poste le code suivant comme un contre-exemple pour toutes les réponses dans ce fil de discussion et en fait partout dans StackOverflow (et ailleurs) qui recommandent une multiplication suivie d'une troncature suivie d'une division. Il incombe aux partisans de cette technique d'expliquer pourquoi le code suivant produit le mauvais résultat dans plus de 92% des cas.

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

Sortie de ce programme:

10001 trials 9251 errors

MODIFIER: Pour répondre à quelques commentaires ci-dessous, j'ai refait la partie de module de la boucle de test en utilisant BigDecimal et new MathContext(16) pour le fonctionnement du module comme suit:

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

Résultat:

10001 trials 4401 errors

75
2017-10-02 03:18



Supposons que vous avez

double d = 9232.129394d;

vous pouvez utiliser BigDecimal

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

ou sans BigDecimal

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

avec les deux solutions d == 9232.13


71
2018-01-28 09:52



Vous pouvez utiliser la classe DecimalFormat.

double d = 3.76628729;

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

52
2017-09-29 07:01



Real's Java Comment-faire des postes cette solution, qui est également compatible pour les versions antérieures à Java 1.6.

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