Domanda

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

Vorrei anche visualizzare solo cifre significative, ovvero non dovrebbero esserci zero finali.

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

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

restituisce:

0.91239

che è fantastico, tuttavia mostra sempre numeri con 5 cifre decimali anche se non sono significativi:

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

restituisce:

0.91230

Un altro metodo è usare DecimalFormatter :

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

restituisce:

0.91238

Tuttavia, come puoi vedere, usa un arrotondamento a metà. Cioè arrotonderà se la cifra precedente è pari. Quello che mi piacerebbe è questo:

0.912385 -> 0.91239
0.912300 -> 0.9123

Qual è il modo migliore per raggiungere questo obiettivo in Java?

È stato utile?

Soluzione

Usa setRoundingMode , imposta RoundingMode in modo esplicito per gestire il problema con il round semi-uniforme, quindi utilizzare 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));
}

fornisce l'output:

12
123.1235
0.23
0.1
2341234.2125

Altri suggerimenti

Supponendo che value sia un double , puoi fare:

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

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

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

ti darà un BigDecimal . Per estrarne la stringa, basta chiamare il metodo BigDecimal toString o il metodo toPlainString per Java 5+ per un formato semplice stringa.

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

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

per assicurarti di avere gli 0 finali.

Come altri hanno notato, la risposta corretta è usare DecimalFormat o BigDecimal . Il virgola mobile non ha posizioni decimali, quindi non è possibile arrotondare / troncare a un numero specifico di esse in primo luogo. Devi lavorare con un decimale decimale, ed è quello che fanno queste due classi.

Sto pubblicando il seguente codice come contro-esempio a tutte le risposte in questo thread e in effetti su StackOverflow (e altrove) che raccomandano la moltiplicazione seguita dal troncamento seguito dalla divisione. Spetta ai sostenitori di questa tecnica spiegare perché il codice seguente produce un output errato 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");
    }
}

Output di questo programma:

10001 trials 9251 errors

MODIFICA: Per rispondere ad alcuni commenti di seguito ho rifatto la parte del modulo del loop di test usando BigDecimal e new MathContext (16) per il funzionamento del 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

Supponi 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

Puoi usare la classe DecimalFormat.

double d = 3.76628729;

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

Real's Java How-to posts questa soluzione, che è anche compatibile per 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

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

per assicurarti di avere gli 0 finali.

Aggiungo che questo metodo è molto efficace nel fornire un metodo reale meccanismo di arrotondamento numerico, non solo visivamente, ma anche durante l'elaborazione.

Ipotetico: devi implementare un meccanismo di arrotondamento in una GUI programma. Per modificare semplicemente l'accuratezza / precisione di un risultato cambia il formato del punto di inserimento (cioè tra parentesi). In modo che:

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

restituisce come output: 0.912385

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

restituisce come output: 0.91239

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

restituisce come output: 0.9124

[MODIFICA: anche se il formato del cursore è simile (" # 0. ############ ") e tu inserire un decimale, ad es. 3.1415926, per amor di argomenti, DecimalFormat non produce immondizia (ad esempio zero finali) e restituirà: 3.1415926 .. se sei così incline. Certo, è un po 'prolisso per i gusti di alcuni sviluppatori - ma hey, ha un ingombro di memoria ridotto durante l'elaborazione ed è molto facile da implementare.]

In sostanza, la bellezza di DecimalFormat è che gestisce contemporaneamente la stringa aspetto - così come il livello di precisione di arrotondamento impostato. Ergo: tu ottieni due vantaggi al prezzo di una implementazione di codice. ;)

È possibile 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 ciò che è possibile utilizzare se si desidera il risultato come 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 come risultato. Non lo consiglierei per la conversione di stringhe, tuttavia, poiché double potrebbe non essere in grado di rappresentare esattamente ciò che desideri (vedi ad esempio qui ):

  1. Precisione di Apache Commons Math

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

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

    double rounded = Utils.roundDouble(0.912385, 5)
    

Una soluzione concisa:

   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 averlo offerto.

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

Consultare: http://www.javabeat.net/precise- arrotondamento-of-decimali-using-arrotondamento-mode-censimento /

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

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

La home page della Biblioteca di matematica 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;
        }
    }
}

Se vuoi davvero numeri decimali per il calcolo (e non solo per l'output), non utilizzare un formato a virgola mobile basato su binario come double.

Use BigDecimal or any other decimal-based format.

Uso BigDecimal per i calcoli, ma tieni presente che dipende dalla dimensione di numeri con cui hai a che fare. Nella maggior parte delle mie implementazioni, trovo l'analisi dal doppio o intero a lungo è sufficiente per calcoli con numeri molto grandi.

In effetti, l'ho fatto recentemente utilizzato parsed-to-Long per ottenere rappresentazioni accurate (al contrario di risultati esadecimali) in una GUI per numeri grandi come ################################# come un esempio).

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

  • Formattazione : formatta facilmente un doppio in stringa con un certo numero di cifre decimali
  • Analisi : analizza nuovamente il valore formattato per raddoppiare
  • Impostazioni internazionali : formatta e analizza utilizzando le impostazioni internazionali predefinite
  • Notazione esponenziale : inizia a utilizzare la notazione esponenziale dopo una determinata soglia

L'utilizzo è piuttosto semplice :

(Per il bene di questo esempio sto usando una localizzazione 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 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), "");
    }

}

Nel caso in cui 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.

Lo snippet di codice seguente mostra come visualizzare n cifre. Il trucco è impostare la variabile pp su 1 seguita da n zeri. Nell'esempio seguente, il valore di variabile PP 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();

Se stai usando DecimalFormat per convertire 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 enum RoundingMode tra cui scegliere, a seconda del comportamento richiesto.

Sono venuto qui solo per avere una semplice risposta su come arrotondare un numero. Questa è una risposta supplementare per fornirlo.

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 per eccesso. Se hai bisogno di un comportamento di arrotondamento diverso da quello, puoi usare uno degli altri Funzioni matematiche . Vedi il confronto di seguito.

round

Come indicato sopra, questo arrotonda al numero intero più vicino. I decimali .5 vengono 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 per eccesso al numero intero successivo. Va al ceil ing. 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

floor

Qualsiasi valore decimale viene arrotondato per difetto all'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

È simile al arrotondamento in quei valori decimali arrotondati al numero intero più vicino. Tuttavia, a differenza di round , i valori .5 sono arrotondati all'intero pari. 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 ***

Per raggiungere questo obiettivo 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);
    }

Definizione di 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.

Sono d'accordo con la risposta scelta per utilizzare DecimalFormat --- o in alternativa BigDecimal .

Prima leggi Aggiorna prima!

Tuttavia, se si si desidera arrotondare il doppio valore e ottenere un risultato doppio , è possibile utilizzare org.apache.commons.math3 .util.Precision.round (..) come menzionato sopra. L'implementazione utilizza BigDecimal , è lenta e crea immondizia.

Un metodo simile ma rapido e privo di immondizia è 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);

Produrrà

 0.667
 0.666
 1000.0
 9.00800700601E10

Vedere 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 per difetto a 256.02 perché il doppio valore rappresentato come 256.025d è leggermente più piccolo del valore razionale 256.025 e quindi verrà arrotondato per difetto.

Note:

  • Questo comportamento è molto simile a quello del costruttore BigDecimal (double) (ma non a valueOf (double) che utilizza il costruttore di stringhe).
  • Il problema può essere aggirato con un doppio passaggio di arrotondamento per prima una maggiore precisione, ma è complicato e non entrerò nei dettagli qui

Per quei motivi e tutto quanto menzionato sopra in questo post, non posso raccomandare di usare DoubleRounder .

Se stai usando una tecnologia che ha un JDK minimo. Ecco un modo senza librerie Java:

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

DecimalFormat è il modo migliore per produrre, ma non lo preferisco. Lo faccio sempre tutto il tempo, perché restituisce il doppio valore. Quindi posso usarlo più di un semplice output.

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

o

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

Se hai bisogno di grandi cifre decimali, puoi usare BigDecimal. Comunque .0 è importante. Senza di essa, l'arrotondamento di 0,33333d5 restituisce 0,33333 e sono consentite solo 9 cifre. La seconda funzione senza .0 presenta problemi con la restituzione di 0.30000 0.30000000000000004.

Dove dp = posizione decimale che desideri, e valore è un doppio.

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

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

Tieni presente che String.format () e DecimalFormat producono string usando le impostazioni internazionali predefinite. Quindi possono scrivere un numero formattato con punto o virgola come separatore tra parti intere e decimali. Per assicurarti che String sia arrotondato nel formato che desideri, usa 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));

Stampa in lingua inglese (non importa quale sia la tua lingua):   0.99   123.57   123.00

L'esempio è tratto da Farenda - come convertire il doppio in String correttamente .

Se si considera il numero 5 o n del decimale. Potrebbe essere questa risposta a risolvere il tuo problema.

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

L'output sarà: 123.0 1
questo può essere risolto con la funzione loop e ricorsiva.

In generale, l'arrotondamento viene eseguito ridimensionando: 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top