Comment arrondir un nombre à n décimales en Java
ce que je voudrais c'est une méthode pour convertir un double en chaîne qui tourne en utilisant la méthode half-up - i.e. si la décimale à arrondir est 5, il arrondit toujours au nombre précédent. C'est la méthode standard pour arrondir la plupart des gens attendent dans la plupart des situations.
je voudrais aussi que seuls les chiffres significatifs soient affichés - c'est-à-dire qu'il ne devrait pas y avoir de zéros de queue.
je sais que l'une des méthodes est d'utiliser le String.format
méthode:
String.format("%.5g%n", 0.912385);
retourne:
0.91239
qui est grand, mais il affiche toujours des nombres avec 5 décimales même si elles ne sont pas significatives:
String.format("%.5g%n", 0.912300);
retourne:
0.91230
une autre méthode consiste à utiliser le DecimalFormatter
:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
retourne:
0.91238
cependant comme vous pouvez voir ces utilisations demi-même arrondissement. Qu'en est-il arrondir à la baisse si le chiffre est pair. Ce que j'aimerais c'est ceci:
0.912385 -> 0.91239
0.912300 -> 0.9123
Quelle est la meilleure façon D'y parvenir en Java?
29 réponses
Use setRoundingMode
, définissez le RoundingMode
explicitement pour gérer votre problème avec le demi-rond Pair, 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
en supposant que value
est un double
, vous pouvez faire:
(double)Math.round(value * 100000d) / 100000d
pour une précision à 5 chiffres. Le nombre de zéros indiquent le nombre de décimales.
new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);
vous obtiendra un BigDecimal
. Pour en extraire la chaîne, il suffit d'appeler la méthode BigDecimal
's toString
, ou la méthode toPlainString
pour Java 5+ pour une chaîne de 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));
}
vous pouvez également utiliser le
DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
pour être sûr que vous avez les 0 de derrière.
comme d'autres l'ont fait remarquer, la bonne réponse est d'utiliser DecimalFormat
ou BigDecimal
. Virgule flottante n'est pas ont décimales de sorte que vous ne peut pas rond/truncate à un certain nombre d'entre eux dans la première place. Vous devez travailler dans un radix décimal, et c'est ce que font ces deux classes.
je poste le code suivant comme un contre-exemple à toutes les réponses dans ce fil et en effet tout over 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
EDIT: pour répondre À certains commentaires ci-dessous j'ai refait le module de la partie de la boucle de test à l'aide de BigDecimal
et new MathContext(16)
pour le modulo comme
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
supposons que vous ayez
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
vous pouvez utiliser la classe Décimalformat.
double d = 3.76628729;
DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal = Double.valueOf(newFormat.format(d));
double myNum = .912385;
int precision = 10000; //keep 4 digits
myNum= Math.floor(myNum * precision +.5)/precision;
@Milhous: le format décimal pour l'arrondissement est excellent:
vous pouvez également utiliser le
DecimalFormat df = new DecimalFormat("#.00000"); df.format(0.912385);
pour être sûr que vous avez les 0 de derrière.
j'ajouterais que cette méthode est très bonne pour fournir une mécanisme d'arrondissement numérique - non seulement visuellement, mais aussi lors du traitement.
hypothétique: vous devez mettre en œuvre un mécanisme d'arrondi dans un GUI programme. Pour modifier la précision / précision d'une sortie de résultat simplement modifier le format caret (c'est-à-dire entre parenthèses). De sorte que:
DecimalFormat df = new DecimalFormat("#0.######");
df.format(0.912385);
retournerait en sortie: 0.912385
DecimalFormat df = new DecimalFormat("#0.#####");
df.format(0.912385);
retournerait en sortie: 0.91239
DecimalFormat df = new DecimalFormat("#0.####");
df.format(0.912385);
retournerait en sortie: 0.9124
[EDIT: si le curseur de format, c'est comme si ("#0.############") et vous
entrez un nombre décimal, par exemple 3.1415926, for argue's sake, DecimalFormat
ne produit pas de déchets (par ex. zéros de queue) et retourne:
3.1415926
.. si vous êtes de cette façon inclinée. Certes, c'est un peu verbeux
pour le goût de certains dev - mais bon, il a une faible empreinte mémoire
pendant le traitement et est très facile à mettre en œuvre.]
donc essentiellement, la beauté de DecimalFormat est qu'il gère simultanément la corde apparence-ainsi que le niveau de précision d'arrondi ensemble. Ergo: vous obtenez deux avantages pour le prix d'une mise en œuvre du code. ;)
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;
}
voici un résumé de ce que vous pouvez utiliser si vous voulez le résultat sous forme de chaîne:
-
DecimalFormat#setRoundingMode () :
DecimalFormat df = new DecimalFormat("#.#####"); df.setRoundingMode(RoundingMode.HALF_UP); String str1 = df.format(0.912385)); // 0.91239
-
String str2 = new BigDecimal(0.912385) .setScale(5, BigDecimal.ROUND_HALF_UP) .toString();
Voici une suggestion des bibliothèques que vous pouvez utiliser si vous voulez double
comme résultat. Je ne le recommande pas il pour la conversion de chaîne, cependant, comme double peut ne pas être en mesure de représenter ce que vous voulez exactement (voir par exemple ici ):
une solution succincte:
public static double round(double value, int precision) {
int scale = (int) Math.pow(10, precision);
return (double) Math.round(value * scale) / scale;
}
Voir aussi, https://stackoverflow.com/a/22186845/212950 Merci à jpdymond pour cette offre.
vous pouvez utiliser BigDecimal
BigDecimal value = new BigDecimal("2.3");
value = value.setScale(0, RoundingMode.UP);
BigDecimal value1 = new BigDecimal("-2.3");
value1 = value1.setScale(0, RoundingMode.UP);
System.out.println(value + "n" + value1);
Refer: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration /
Essayez ceci: org.Apache.commun.math3.util.Précision.rond (double x, échelle int)
voir: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
Apache Commons Bibliothèque de Mathématiques page d'accueil 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;
}
}
}
depuis que je n'ai pas trouvé de réponse complète sur ce thème, j'ai mis en place une classe qui devrait gérer cela correctement, avec un soutien pour:
- formatage : formater facilement un double à la chaîne avec un certain nombre de décimales " 15198090920"
- Parsing : analyser la valeur formatée retour au double
- Locale : Format et analyse en utilisant la locale par défaut
- notation exponentielle : utiliser la notation exponentielle après un certain seuil
L'Usage est assez simple :
(pour cet exemple, j'utilise un local personnalisé)
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), "");
}
}
au cas où quelqu'un aurait encore besoin d'aide. 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 un String
avec la sortie désirée.
si vous voulez vraiment des nombres décimaux pour le calcul (et pas seulement pour la sortie), n'utilisez pas un format binaire flottant point comme double.
Use BigDecimal or any other decimal-based format.
j'utilise BigDecimal pour les calculs, mais gardez à l'esprit qu'il dépend de la taille de les numéros que vous avez affaire. Dans la plupart de mes réalisations, je trouve l'analyse de double ou entier à Long est suffisant pour des calculs de très grand nombre.
en fait, j'ai récemment utilisé analysé-à-temps pour obtenir des représentations précises (par opposition à l'hex résultats) dans une interface graphique, pour des nombres aussi grands que ################################# les personnages (comme un exemple.)
si vous utilisez DecimalFormat
pour convertir 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);
il y a plusieurs RoundingMode
valeurs enum à choisir, selon le comportement que vous souhaitez.
l'extrait de code ci-dessous montre comment afficher n chiffres. Le truc est de mettre la Variable pp à 1 suivie de n zéros. Dans l'exemple ci-dessous, la variable valeur 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();
je suis venu ici juste pour avoir une réponse simple sur comment arrondir un nombre. C'est un complément de réponse à fournir.
comment arrondir un nombre en Java
le cas Le plus courant est d'utiliser des Math.round()
.
Math.round(3.7) // 4
Les nombres sont arrondis au nombre entier le plus proche. Une valeur de .5
est arrondie au haut. Si vous avez besoin d'un comportement d'arrondi différent de celui-ci, vous pouvez utiliser l'un des autres mathématiques des fonctions. Voir le comparatif ci-dessous.
rond
comme indiqué ci-dessus, ce chiffre est arrondi au nombre entier le plus proche. .5
décimales arrondies. Cette méthode retourne 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 supérieur. Il va à la ceil ing. 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
plancher
toute valeur décimale est arrondie à l'entier inférieur. Cette méthode retourne 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
c'est similaire au rond dans les valeurs décimales arrondies à l'entier le plus proche. Cependant, contrairement à round
, .5
valeurs arrondies à l'entier pair. Ce la méthode retourne 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 ***
je suis d'accord avec la réponse choisie pour utiliser DecimalFormat
- - - ou alternativement BigDecimal
.
s'il vous Plaît lire mise à Jour ci-dessous!
Toutefois si vous faire voulez arrondir la valeur de type double et d'obtenir un double
valeur résultat, vous pouvez utiliser org.apache.commons.math3.util.Precision.round(..)
comme mentionné ci-dessus. L'implémentation utilise BigDecimal
, est lente et crée des déchets.
une méthode similaire mais rapide et sans déchets 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);
sortie Will
0.667
0.666
1000.0
9.00800700601E10
voir https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility
clause de non-responsabilité: je participe au projet decimal4j.
mise à Jour:
Comme @iaforek a fait remarquer que les doubleurs donnent 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 parce que la double valeur représentée par 256,025 d est un peu plus petite que la valeur rationnelle 256,025 et sera donc arrondie à la baisse.
Notes:
- ce comportement est très similaire à celui de la
BigDecimal(double)
constructeur (mais pas devalueOf(double)
qui utilise la chaîne constructeur). - le problème peut être contourné avec un double arrondi à une plus grande précision d'abord, mais il 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 peut pas recommander d'utiliser DoubleRounder .
DecimalFormat est le meilleur moyen de sortie, mais je ne le préfère pas. Je fais toujours ça tout le temps, parce que ça rapporte la double valeur. Donc je peux l'utiliser plus que juste sortie.
Math.round(selfEvaluate*100000d.0)/100000d.0;
ou
Math.round(selfEvaluate*100000d.0)*0.00000d1;
si vous avez besoin d'une grande valeur décimale, vous pouvez utiliser BigDecimal à la place. De toute façon, .0
est important. Sans elle, l'arrondissement de 0.33333d5 retour 0.33333 et seulement 9 chiffres permet. La deuxième fonction sans .0
a des problèmes avec 0.30000 retour 0.30000000000000004.
pour ce faire, nous pouvons utiliser ce formatteur:
DecimalFormat df = new DecimalFormat("#.00");
String resultado = df.format(valor)
ou:
DecimalFormat df = new DecimalFormat("0.00"); :
utilisez cette méthode pour obtenir toujours deux décimales:
private static String getTwoDecimals(double value){
DecimalFormat df = new DecimalFormat("0.00");
return df.format(value);
}
définissant ces valeurs:
91.32
5.22
11.5
1.2
2.6
en utilisant la méthode nous pouvons obtenir ce résultat:
91.32
5.22
11.50
1.20
2.60
gardez à l'esprit cette chaîne.format () et Décimalformat produisent la chaîne de caractères en utilisant la Locale par défaut. Ainsi ils peuvent écrire le nombre formaté avec le point ou la virgule comme séparateur entre le nombre entier et les parties décimales. Pour s'assurer que la chaîne arrondie est dans le format que vous voulez utiliser java.texte.Numéro tel que:
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));
Sera imprimé en anglais locale (peu importe ce que votre locale): 0,99 123,57 123,00
L'exemple est tiré de Farenda - comment convertir double en chaîne correctement .
où dp = place décimale que vous voulez, et valeur est un double.
double p = Math.pow(10d, dp);
double result = Math.round(value * p)/p;
si vous considérez 5 ou n nombre de décimales. Peut-être que cette réponse résoudra votre problème.
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);
sortie sera: 123.0 1
cela peut être résolu avec boucle et fonction récursive.
si vous utilisez une technologie qui a un minimum JDK. Voici un moyen sans les libs Java:
double scale = 100000;
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;
en général, l'arrondissement se fait par mise à l'échelle: 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