Come arrotondare un numero a n decimali in Java

Quello che vorrei è un metodo per convertire un double in una stringa che arrotonda usando il metodo half-up – cioè se il decimale da arrotondare è 5, si arrotonda sempre al numero precedente. Questo è il metodo standard di arrotondamento che la maggior parte delle persone si aspetta nella maggior parte delle situazioni.

Vorrei anche solo visualizzare cifre significative – cioè non dovrebbero esserci zero finali.

So che un metodo per farlo è utilizzare il metodo String.format :

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

ritorna:

 0.91239 

che è ottimo, tuttavia visualizza sempre i numeri con 5 cifre decimali anche se non sono significativi:

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

ritorna:

 0.91230 

Un altro metodo è utilizzare DecimalFormatter :

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

ritorna:

 0.91238 

Tuttavia, come puoi vedere, utilizza arrotondamenti pari a metà. Cioè si arrotonderà se la cifra precedente è pari. Quello che vorrei è questo:

 0.912385 -> 0.91239 0.912300 -> 0.9123 

Qual è il modo migliore per ottenere questo in Java?

Usa setRoundingMode , imposta il setRoundingMode esplicito per gestire il tuo problema con il giro semi-uniforms, quindi usa il modello di formato per l’output richiesto.

Esempio:

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

dà l’output:

 12 123.1235 0.23 0.1 2341234.2125 

Supponendo che il value sia double , puoi fare:

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

Questo è per la precisione di 5 cifre. Il numero di zeri indica il numero di decimali.

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

ti porterà un BigDecimal . Per ottenere la stringa, basta chiamare il metodo toString toPlainString o il metodo toPlainString per Java 5+ per una stringa di formato normale.

Programma di esempio:

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

Puoi anche usare il

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

per assicurarti di avere gli 0 di coda.

Come altri hanno notato, la risposta corretta è usare DecimalFormat o BigDecimal . Il virgola mobile non ha cifre decimali, quindi non è ansible arrotondare / troncare a un numero specifico di esse in primo luogo. Devi lavorare in un decimale decimale, e questo è ciò che fanno queste due classi.

Sto postando il seguente codice come controesempio a tutte le risposte in questo thread e in effetti su StackOverflow (e altrove) che consiglia la moltiplicazione seguita da troncamento seguito da divisione. Spetta ai sostenitori di questa tecnica spiegare perché il seguente codice produce l’output sbagliato in oltre il 92% dei casi.

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

Uscita di questo programma:

 10001 trials 9251 errors 

EDIT: per indirizzare alcuni commenti sotto ho ridimensionato la parte modulo del loop di test utilizzando BigDecimal e new MathContext(16) per l'operazione modulo come segue:

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

Risultato:

 10001 trials 4401 errors 

Supponiamo di avere

 double d = 9232.129394d; 

puoi usare BigDecimal

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

o senza BigDecimal

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

con entrambe le soluzioni d == 9232.13

È ansible utilizzare la class DecimalFormat.

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

Real’s Java How-to pubblica questa soluzione, che è compatibile anche con le versioni precedenti a Java 1.6.

 BigDecimal bd = new BigDecimal(Double.toString(d)); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); return bd.doubleValue(); 
 double myNum = .912385; int precision = 10000; //keep 4 digits myNum= Math.floor(myNum * precision +.5)/precision; 

@Milhous: il formato decimale per l’arrotondamento è eccellente:

Puoi anche usare il

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

per assicurarti di avere gli 0 di coda.

Vorrei aggiungere che questo metodo è molto efficace nel fornire un effettivo meccanismo numerico di arrotondamento, non solo visivamente, ma anche durante l’elaborazione.

Ipotetico: devi implementare un meccanismo di arrotondamento in un programma GUI. Per modificare l’accuratezza / precisione di un risultato, è sufficiente modificare il formato del cursore (cioè tra parentesi). Così che:

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

ritornerebbe come uscita: 0.912385

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

ritornerebbe come output: 0.91239

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

ritornerebbe come output: 0.9124

[EDIT: anche se il formato di accento è come tale (“# 0. ############”) e si immette un decimale, ad esempio 3,1415926, per ragioni di argomento, DecimalFormat non produce alcuna immondizia ( es. zero finali) e ritornerà: 3.1415926 .. se sei così inclinato. Certo, è un po ‘prolisso per il piacere di alcuni sviluppatori – ma, hey, ha un basso ingombro di memoria durante l’elaborazione ed è molto facile da implementare.]

Quindi, in sostanza, la bellezza di DecimalFormat è che gestisce simultaneamente l’aspetto della stringa e il livello di precisione dell’arrotondamento. Ergo: ottieni due vantaggi per il prezzo di un’implementazione del codice. 😉

È ansible utilizzare il seguente metodo di utilità-

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

Ecco un riepilogo di cosa puoi usare se vuoi che il risultato sia String:

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

Ecco un suggerimento su quali librerie puoi usare se vuoi double di conseguenza. Non lo consiglierei per la conversione delle stringhe, tuttavia, poiché il doppio potrebbe non essere in grado di rappresentare esattamente quello che vuoi (vedi ad esempio qui ):

  1. Precisione da Apache Commons Math

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

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

     double rounded = Utils.roundDouble(0.912385, 5) 

Una soluzione succinta:

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

Vedi anche, https://stackoverflow.com/a/22186845/212950 Grazie a jpdymond per aver offerto questo.

Puoi usare 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); 

Fare riferimento a: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Prova questo: org.apache.commons.math3.util.Precision.round (doppia x, scala int)

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

La homepage della Biblioteca Mathematica di Apache Commons è: http://commons.apache.org/proper/commons-math/index.html

L’implementazione interna di questo metodo è:

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

Dal momento che non ho trovato una risposta completa su questo tema, ho messo insieme una class che dovrebbe gestirlo correttamente, con il supporto di:

  • Formattazione : formatta facilmente un doppio in una stringa con un determinato numero di posizioni decimali
  • Parsing : ripassa il valore formattato per raddoppiare
  • Locale : formatta e analizza usando le impostazioni locali predefinite
  • Notazione esponenziale : inizia a utilizzare la notazione esponenziale dopo una certa soglia

L’utilizzo è piuttosto semplice :

(Per il bene di questo esempio sto usando una locale personalizzata)

 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 

Ecco la class :

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

Nel caso qualcuno abbia ancora bisogno di aiuto con questo. Questa soluzione funziona perfettamente per me.

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

restituisce una String con l’output desiderato.

Se si desidera realmente i numeri decimali per il calcolo (e non solo per l’output), non utilizzare un formato in virgola mobile basato su binario come il doppio.

 Use BigDecimal or any other decimal-based format. 

Io uso BigDecimal per i calcoli, ma tenete a mente che dipende dalla dimensione dei numeri con cui avete a che fare. Nella maggior parte delle mie implementazioni, trovo che l’analisi da doppio o intero a Long è sufficiente per calcoli numerici molto grandi.

In effetti, recentemente ho usato parsed-to-Long per ottenere rappresentazioni accurate (al contrario dei risultati hex) in una GUI per numeri grandi come ################## ############### caratteri (come esempio).

Se stai utilizzando DecimalFormat per convertire il double in String , è molto semplice:

 DecimalFormat formatter = new DecimalFormat("0.0##"); formatter.setRoundingMode(RoundingMode.HALF_UP); double num = 1.234567; return formatter.format(num); 

Esistono diversi valori di RoundingMode RoundingMode da cui selezionare, in base al comportamento richiesto.

Il frammento di codice qui sotto mostra come visualizzare n cifre. Il trucco è impostare la variabile pp su 1 seguito da n zeri. Nell’esempio seguente, il valore della pp variabile ha 5 zeri, quindi verranno visualizzate 5 cifre.

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

Sono venuto qui solo volendo una semplice risposta su come arrotondare un numero. Questa è una risposta supplementare per fornire questo.

Come arrotondare un numero in Java

Il caso più comune è usare Math.round() .

 Math.round(3.7) // 4 

I numeri sono arrotondati al numero intero più vicino. Un valore .5 viene arrotondato. Se è necessario un diverso comportamento di arrotondamento, è ansible utilizzare una delle altre funzioni matematiche . Vedi il confronto qui sotto.

il giro

Come detto sopra, questo round al numero intero più vicino. .5 decimali arrotondati per eccesso. Questo metodo restituisce 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

Qualsiasi valore decimale viene arrotondato al numero intero successivo. Va al soffitto . Questo metodo restituisce 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 

pavimento

Qualsiasi valore decimale viene arrotondato al numero intero successivo. Questo metodo restituisce 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

Questo è simile al round in quei valori decimali arrotondati al numero intero più vicino. Tuttavia, a differenza dei valori arrotondati, .5 attorno al numero intero uniforms. Questo metodo restituisce 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 *** 

Sono d’accordo con la risposta scelta per usare DecimalFormat — o in alternativa BigDecimal .

Per favore leggi prima l’ Aggiornamento qui sotto!

Tuttavia, se si desidera arrotondare il doppio valore e ottenere un risultato a double valore, è ansible utilizzare org.apache.commons.math3.util.Precision.round(..) come indicato sopra. L’implementazione utilizza BigDecimal , è lento e crea spazzatura.

Un metodo simile, ma veloce e senza spazzatura, è fornito dall’utilità DoubleRounder nella libreria 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); 

Uscirà

  0.667 0.666 1000.0 9.00800700601E10 

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

Disclaimer: sono coinvolto nel progetto decimal4j.

Aggiornamento: come ha sottolineato @iaforek, DoubleRounder a volte restituisce risultati controintuitivi. Il motivo è che esegue arrotondamenti matematicamente corretti. Ad esempio DoubleRounder.round(256.025d, 2) verrà arrotondato a 256.02 perché il doppio valore rappresentato come 256.025d è leggermente inferiore al valore razionale 256.025 e quindi verrà arrotondato per difetto.

Gli appunti:

  • Questo comportamento è molto simile a quello del BigDecimal(double) (ma non a valueOf(double) che usa il costruttore di stringhe).
  • Il problema può essere aggirato con un doppio passaggio di arrotondamento ad una precisione più alta, ma è complicato e non sto entrando nei dettagli qui

Per questi motivi e tutto quanto sopra menzionato in questo post non posso raccomandare di utilizzare DoubleRounder .

DecimalFormat è il modo migliore per produrre, ma io non lo preferisco. Lo faccio sempre, perché restituisce il doppio valore. Quindi posso usarlo più della semplice produzione.

 Math.round(selfEvaluate*100000d.0)/100000d.0; 

O

 Math.round(selfEvaluate*100000d.0)*0.00000d1; 

Se hai bisogno di valori decimali grandi, puoi invece utilizzare BigDecimal. Comunque .0 è importante. Senza di esso l’arrotondamento di 0.33333d5 restituisce 0.33333 e sono consentite solo 9 cifre. La seconda funzione senza .0 ha problemi con 0,30000 restituisce 0,30000000000000004.

Per ottenere questo possiamo usare questo formattatore:

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

o:

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

Usa questo metodo per ottenere sempre due decimali:

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

Definire questi valori:

 91.32 5.22 11.5 1.2 2.6 

Usando il metodo possiamo ottenere questi risultati:

 91.32 5.22 11.50 1.20 2.60 

demo online.

Tieni presente che String.format () e DecimalFormat producono string utilizzando le impostazioni internazionali predefinite. In tal modo possono scrivere il numero formattato con punto o virgola come separatore tra parti intere e decimali. Per assicurarti che la stringa arrotondata sia nel formato, devi utilizzare java.text.NumberFormat in questo modo:

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

Stamperà in locale in inglese (indipendentemente dalle impostazioni locali): 0,99 123,57 123,00

L’esempio è tratto da Farenda: come convertire correttamente il doppio in stringa .

Dove dp = posizione decimale desiderata e valore è un doppio.

  double p = Math.pow(10d, dp); double result = Math.round(value * p)/p; 

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.

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; 

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