decimal après - Comment arrondir un nombre à n décimales en Java




coût entière (25)

Ce que je voudrais 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 consiste à utiliser la méthode String.format :

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?


Answers

Voici une solution de base offerte par jpdymond :

   public static double round(double value, int precision) {
      int scale = (int) Math.pow(10, precision);
      return (double) Math.round(value * scale) / scale;
  }

https://stackoverflow.com/a/22186845/212950


Je suis venu ici juste pour une réponse simple sur la façon d'arrondir un nombre. Ceci est une réponse supplémentaire pour fournir cela.

Comment arrondir un nombre en Java

Le cas le plus courant consiste à utiliser Math.round() .

Math.round(3.7) // 4

Les nombres sont arrondis au nombre entier le plus proche. Une valeur .5 est arrondie à la valeur supérieure. Si vous avez besoin d'un comportement d'arrondi différent, vous pouvez utiliser l'une des autres fonctions Math . Voir la comparaison ci-dessous.

round

Comme indiqué ci-dessus, cela arrondit au nombre entier le plus proche. .5 décimales arrondies. Cette méthode renvoie un int .

Math.round(3.0); // 3
Math.round(3.1); // 3
Math.round(3.5); // 4
Math.round(3.9); // 4

Math.round(-3.0); // -3
Math.round(-3.1); // -3
Math.round(-3.5); // -3 *** careful here ***
Math.round(-3.9); // -4

ceil

Toute valeur décimale est arrondie à l'entier suivant. Ça va au plafond . Cette méthode renvoie un double .

Math.ceil(3.0); // 3.0
Math.ceil(3.1); // 4.0
Math.ceil(3.5); // 4.0
Math.ceil(3.9); // 4.0

Math.ceil(-3.0); // -3.0
Math.ceil(-3.1); // -3.0
Math.ceil(-3.5); // -3.0
Math.ceil(-3.9); // -3.0

floor

Toute valeur décimale est arrondie à l'entier inférieur suivant. Cette méthode renvoie un double .

Math.floor(3.0); // 3.0
Math.floor(3.1); // 3.0
Math.floor(3.5); // 3.0
Math.floor(3.9); // 3.0

Math.floor(-3.0); // -3.0
Math.floor(-3.1); // -4.0
Math.floor(-3.5); // -4.0
Math.floor(-3.9); // -4.0

rint

Ceci est similaire à round dans les valeurs décimales arrondies à l'entier le plus proche. Cependant, contrairement à round , les valeurs .5 arrondissent à l'entier pair. Cette méthode renvoie un double .

Math.rint(3.0); // 3.0
Math.rint(3.1); // 3.0
Math.rint(3.5); // 4.0 ***
Math.rint(3.9); // 4.0
Math.rint(4.5); // 4.0 ***
Math.rint(5.5); // 6.0 ***

Math.rint(-3.0); // -3.0
Math.rint(-3.1); // -3.0
Math.rint(-3.5); // -4.0 ***
Math.rint(-3.9); // -4.0
Math.rint(-4.5); // -4.0 ***
Math.rint(-5.5); // -6.0 ***

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

vous obtiendrez un BigDecimal . Pour en extraire la chaîne, appelez simplement la méthode toString BigDecimal ou la méthode toPlainString pour Java 5+ pour une chaîne au format simple.

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

dp = lieu décimal que vous voulez, et la valeur est un double.

    double p = Math.pow(10d, dp);

    double result = Math.round(value * p)/p;

Voici un résumé de ce que vous pouvez utiliser si vous souhaitez obtenir le résultat sous forme de chaîne:

  1. DecimalFormat#setRoundingMode() :

    DecimalFormat df = new DecimalFormat("#.#####");
    df.setRoundingMode(RoundingMode.HALF_UP);
    String str1 = df.format(0.912385)); // 0.91239
    
  2. BigDecimal#setScale()

    String str2 = new BigDecimal(0.912385)
        .setScale(5, BigDecimal.ROUND_HALF_UP)
        .toString();
    

Voici une suggestion de quelles bibliothèques vous pouvez utiliser si vous voulez double en conséquence. Je ne le recommanderais pas pour la conversion de chaîne, car le double ne peut pas représenter ce que vous voulez exactement (voir par exemple here ):

  1. Precision d'Apache Commons Math

    double rounded = Precision.round(0.912385, 5, BigDecimal.ROUND_HALF_UP);
    
  2. Functions de Colt

    double rounded = Functions.round(0.00001).apply(0.912385)
    
  3. Utils de Weka

    double rounded = Utils.roundDouble(0.912385, 5)
    

Vous pouvez utiliser la méthode d'utilité suivante

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

Gardez à l'esprit que String.format () et DecimalFormat produisent une chaîne utilisant Locale par défaut. Ils peuvent donc écrire un nombre formaté avec un point ou une virgule comme séparateur entre les parties entières et décimales. Pour vous assurer que la chaîne arrondie est au format que vous voulez, utilisez java.text.NumberFormat comme suit:

  Locale locale = Locale.ENGLISH;
  NumberFormat nf = NumberFormat.getNumberInstance(locale);
  // for trailing zeros:
  nf.setMinimumFractionDigits(2);
  // round to 2 digits:
  nf.setMaximumFractionDigits(2);

  System.out.println(nf.format(.99));
  System.out.println(nf.format(123.567));
  System.out.println(nf.format(123.0));

Will print in English locale (no matter what your locale is): 0.99 123.57 123.00

The example is taken from Farenda - how to convert double to String correctly .


If you're using a technology that has a minimal JDK. Here's a way without any Java libs:

double scale = 100000;    
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;

Je suis d'accord avec la réponse choisie pour utiliser DecimalFormat --- ou BigDecimal .

Veuillez lire la mise à jour ci-dessous en premier!

Cependant, si vous voulez arrondir la double valeur et obtenir un double résultat, vous pouvez utiliser org.apache.commons.math3.util.Precision.round(..) comme indiqué ci-dessus. L'implémentation utilise BigDecimal , est lente et crée des erreurs.

Une méthode similaire mais rapide et sans déchet est fournie par l'utilitaire DoubleRounder dans la bibliothèque decimal4j:

 double a = DoubleRounder.round(2.0/3.0, 3);
 double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
 double c = DoubleRounder.round(1000.0d, 17);
 double d = DoubleRounder.round(90080070060.1d, 9);
 System.out.println(a);
 System.out.println(b);
 System.out.println(c);
 System.out.println(d);

Sortira

 0.667
 0.666
 1000.0
 9.00800700601E10

Voir https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility

Disclaimer: Je suis impliqué dans le projet decimal4j.

Mise à jour: Comme l'a souligné @iaforek, DoubleRounder renvoie parfois des résultats contre-intuitifs. La raison en est qu'il effectue des arrondis mathématiquement corrects. Par exemple, DoubleRounder.round(256.025d, 2) sera arrondi à 256.02 car la valeur double représentée par 256.025d est légèrement inférieure à la valeur rationnelle 256.025 et sera donc arrondie à la valeur inférieure.

Remarques:

  • Ce comportement est très similaire à celui du constructeur BigDecimal(double) (mais pas à valueOf(double) qui utilise le constructeur de chaîne).
  • Le problème peut être contourné avec une double étape d'arrondi à une plus grande précision d'abord, mais c'est compliqué et je ne vais pas dans les détails ici

Pour ces raisons et tout ce qui est mentionné ci-dessus dans ce post, je ne peux pas recommander d'utiliser DoubleRounder .


Essayez ceci: org.apache.commons.math3.util.Precision.round (double x, échelle int)

Voir: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html

La page d'accueil Apache Commons Mathematics Library est: http://commons.apache.org/proper/commons-math/index.html

L'implémentation interne de cette méthode est:

public static double round(double x, int scale) {
    return round(x, scale, BigDecimal.ROUND_HALF_UP);
}

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new BigDecimal
               (Double.toString(x))
               .setScale(scale, roundingMethod))
               .doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}

If you Consider 5 or n number of decimal. May be this answer solve your prob.

    double a = 123.00449;
    double roundOff1 = Math.round(a*10000)/10000.00;
    double roundOff2 = Math.round(roundOff1*1000)/1000.00;
    double roundOff = Math.round(roundOff2*100)/100.00;

    System.out.println("result:"+roundOff);

Output will be: 123.0 1
this can be solve with loop and recursive function.


Si vous voulez vraiment des nombres décimaux pour le calcul (et pas seulement pour la sortie), n'utilisez pas un format à virgule flottante binaire comme double. Utilisez BigDecimal ou tout autre format décimal. - Paŭlo Ebermann

J'utilise BigDecimal pour les calculs, mais gardez à l'esprit que cela dépend de la taille des numéros auxquels vous avez affaire. Dans la plupart de mes implémentations, je trouve que l'analyse de double ou entier à Long est suffisante pour de très grands calculs de nombres. En fait, j'ai récemment utilisé parsed-to-Long pour obtenir des représentations précises (par opposition à des résultats hexadécimaux) dans un gui pour des nombres aussi gros que ################## ############### caractères (à titre d'exemple).


Juste au cas où quelqu'un aurait encore besoin d'aide pour ça. Cette solution fonctionne parfaitement pour moi.

private String withNoTrailingZeros(final double value, final int nrOfDecimals) {
return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals,  BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

}

renvoie une String avec la sortie souhaitée.


L'extrait de code ci-dessous montre comment afficher n chiffres. L'astuce consiste à mettre la variable pp à 1 suivie de n zéros. Dans l'exemple ci-dessous, la valeur variable pp a 5 zéros, donc 5 chiffres seront affichés.

double pp = 10000;

double myVal = 22.268699999999967;
String needVal = "22.2687";

double i = (5.0/pp);

String format = "%10.4f";
String getVal = String.format(format,(Math.round((myVal +i)*pp)/pp)-i).trim();

Si vous utilisez DecimalFormat pour convertir le double en String , c'est très simple:

DecimalFormat formatter = new DecimalFormat("0.0##");
formatter.setRoundingMode(RoundingMode.HALF_UP);

double num = 1.234567;
return formatter.format(num);

Vous pouvez sélectionner plusieurs valeurs d'énumération RoundingMode , en fonction du comportement requis.


To achieve this we can use this formatter:

 DecimalFormat df = new DecimalFormat("#.00");
 String resultado = df.format(valor)

ou:

DecimalFormat df = new DecimalFormat("0.00"); :

Use this method to get always two decimals:

   private static String getTwoDecimals(double value){
      DecimalFormat df = new DecimalFormat("0.00"); 
      return df.format(value);
    }

Defining this values:

91.32
5.22
11.5
1.2
2.6

Using the method we can get this results:

91.32
5.22
11.50
1.20
2.60

demo online.


Comme je n'ai trouvé aucune réponse complète sur ce thème, j'ai mis en place une classe qui devrait gérer cela correctement, avec le soutien de:

  • Formatage : Formate facilement un double en chaîne avec un certain nombre de décimales
  • Parsing : analyser la valeur formatée en double
  • Paramètres régionaux : Formatez et analysez en utilisant les paramètres régionaux par défaut
  • Notation exponentielle : Commencer à utiliser la notation exponentielle après un certain seuil

L'utilisation est assez simple :

(Dans l'intérêt de cet exemple, j'utilise une locale personnalisée)

public static final int DECIMAL_PLACES = 2;

NumberFormatter formatter = new NumberFormatter(DECIMAL_PLACES);

String value = formatter.format(9.319); // "9,32"
String value2 = formatter.format(0.0000005); // "5,00E-7"
String value3 = formatter.format(1324134123); // "1,32E9"

double parsedValue1 = formatter.parse("0,4E-2", 0); // 0.004
double parsedValue2 = formatter.parse("0,002", 0); // 0.002
double parsedValue3 = formatter.parse("3423,12345", 0); // 3423.12345

Voici la classe :

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;

public class NumberFormatter {

    private static final String SYMBOL_INFINITE           = "\u221e";
    private static final char   SYMBOL_MINUS              = '-';
    private static final char   SYMBOL_ZERO               = '0';
    private static final int    DECIMAL_LEADING_GROUPS    = 10;
    private static final int    EXPONENTIAL_INT_THRESHOLD = 1000000000; // After this value switch to exponential notation
    private static final double EXPONENTIAL_DEC_THRESHOLD = 0.0001; // Below this value switch to exponential notation

    private DecimalFormat decimalFormat;
    private DecimalFormat decimalFormatLong;
    private DecimalFormat exponentialFormat;

    private char groupSeparator;

    public NumberFormatter(int decimalPlaces) {
        configureDecimalPlaces(decimalPlaces);
    }

    public void configureDecimalPlaces(int decimalPlaces) {
        if (decimalPlaces <= 0) {
            throw new IllegalArgumentException("Invalid decimal places");
        }

        DecimalFormatSymbols separators = new DecimalFormatSymbols(Locale.getDefault());
        separators.setMinusSign(SYMBOL_MINUS);
        separators.setZeroDigit(SYMBOL_ZERO);

        groupSeparator = separators.getGroupingSeparator();

        StringBuilder decimal = new StringBuilder();
        StringBuilder exponential = new StringBuilder("0.");

        for (int i = 0; i < DECIMAL_LEADING_GROUPS; i++) {
            decimal.append("###").append(i == DECIMAL_LEADING_GROUPS - 1 ? "." : ",");
        }

        for (int i = 0; i < decimalPlaces; i++) {
            decimal.append("#");
            exponential.append("0");
        }

        exponential.append("E0");

        decimalFormat = new DecimalFormat(decimal.toString(), separators);
        decimalFormatLong = new DecimalFormat(decimal.append("####").toString(), separators);
        exponentialFormat = new DecimalFormat(exponential.toString(), separators);

        decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
        decimalFormatLong.setRoundingMode(RoundingMode.HALF_UP);
        exponentialFormat.setRoundingMode(RoundingMode.HALF_UP);
    }

    public String format(double value) {
        String result;
        if (Double.isNaN(value)) {
            result = "";
        } else if (Double.isInfinite(value)) {
            result = String.valueOf(SYMBOL_INFINITE);
        } else {
            double absValue = Math.abs(value);
            if (absValue >= 1) {
                if (absValue >= EXPONENTIAL_INT_THRESHOLD) {
                    value = Math.floor(value);
                    result = exponentialFormat.format(value);
                } else {
                    result = decimalFormat.format(value);
                }
            } else if (absValue < 1 && absValue > 0) {
                if (absValue >= EXPONENTIAL_DEC_THRESHOLD) {
                    result = decimalFormat.format(value);
                    if (result.equalsIgnoreCase("0")) {
                        result = decimalFormatLong.format(value);
                    }
                } else {
                    result = exponentialFormat.format(value);
                }
            } else {
                result = "0";
            }
        }
        return result;
    }

    public String formatWithoutGroupSeparators(double value) {
        return removeGroupSeparators(format(value));
    }

    public double parse(String value, double defValue) {
        try {
            return decimalFormat.parse(value).doubleValue();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return defValue;
    }

    private String removeGroupSeparators(String number) {
        return number.replace(String.valueOf(groupSeparator), "");
    }

}

Utilisez setRoundingMode , définissez explicitement le RoundingMode pour gérer votre problème avec le demi-rond, 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

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

DecimalFormat myFormatter = new DecimalFormat("0.000");
String output = myFormatter.format(2.34d);

Vous pouvez utiliser la classe DecimalFormat.

double d = 3.76628729;

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

In general, rounding is done by scaling: round(num / p) * p

/**
 * MidpointRounding away from zero ('arithmetic' rounding)
 * Uses a half-epsilon for correction. (This offsets IEEE-754
 * half-to-even rounding that was applied at the edge cases).
 */
double RoundCorrect(double num, int precision) {
	double c = 0.5 * EPSILON * num;
//	double p = Math.pow(10, precision); //slow
	double p = 1; while (precision--> 0) p *= 10;
	if (num < 0)
		p *= -1;
	return Math.round((num + c) * p) / p;
}

// testing edge cases
RoundCorrect(1.005, 2);   // 1.01 correct
RoundCorrect(2.175, 2);   // 2.18 correct
RoundCorrect(5.015, 2);   // 5.02 correct

RoundCorrect(-1.005, 2);  // -1.01 correct
RoundCorrect(-2.175, 2);  // -2.18 correct
RoundCorrect(-5.015, 2);  // -5.02 correct


Vous pouvez également utiliser le

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

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


Real's Java How-to posts cette solution, qui est également compatible avec 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();

Une manière simple de le faire est:

var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals); //Returns 0.20000000000000018

Malheureusement, cela ne renvoie pas la valeur exacte. Cependant, cela est facilement corrigé:

var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals.toFixed(1)); //Returns 0.2

Vous pouvez l'utiliser si vous ne connaissez pas le nombre de décimales:

var x = 3.2;
var decimals = x - Math.floor(x);

var decimalPlaces = x.toString().split('.')[1].length;
decimals = decimals.toFixed(decimalPlaces);

console.log(decimals); //Returns 0.2





java decimal rounding digits