Como arredondar um número para n casas decimais em Java




14 Answers

Assumindo que o value é um double , você pode fazer:

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

Isso é para precisão de 5 dígitos. O número de zeros indica o número de decimais.

java decimal rounding digits

O que eu gostaria é um método para converter um double em uma string que arredonda usando o método half-up - ou seja, se o decimal a ser arredondado é 5, ele sempre arredonda para o número anterior. Esse é o método padrão de arredondamento que a maioria das pessoas espera na maioria das situações.

Eu também gostaria que apenas dígitos significativos fossem exibidos - ou seja, não deveria haver nenhum zeros à direita.

Eu sei que um método de fazer isso é usar o método String.format :

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

retorna:

0.91239

o que é ótimo, no entanto, sempre exibe números com 5 casas decimais, mesmo que não sejam significativas:

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

retorna:

0.91230

Outro método é usar o DecimalFormatter :

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

retorna:

0.91238

No entanto, como você pode ver isso usa arredondamento de meia-par. Isso é arredondar para baixo se o dígito anterior é par. O que eu gostaria é isto:

0.912385 -> 0.91239
0.912300 -> 0.9123

Qual é a melhor maneira de conseguir isso em Java?




Você também pode usar o

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

para ter certeza de que você tem o 0 à direita.




Suponha que você tenha

double d = 9232.129394d;

você pode usar BigDecimal

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

ou sem BigDecimal

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

com ambas as soluções d == 9232.13




O Java How-to da Real posts esta solução, que também é compatível com versões anteriores ao Java 1.6.

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();



@Milhous: o formato decimal para arredondamento é excelente:

Você também pode usar o

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

para ter certeza de que você tem o 0 à direita.

Gostaria de acrescentar que este método é muito bom em fornecer um mecanismo numérico real de arredondamento - não apenas visualmente, mas também durante o processamento.

Hipotética: você precisa implementar um mecanismo de arredondamento em um programa GUI. Para alterar a exatidão / precisão de uma saída de resultado, basta alterar o formato do cursor (ou seja, dentro dos colchetes). De modo a:

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

retornaria como saída: 0.912385

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

retornaria como saída: 0.91239

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

retornaria como saída: 0.9124

[EDIT: também se o formato de circunflexo é assim ("# 0. ############") e você digitar um decimal, por exemplo, 3,1415926, por causa do argumento, DecimalFormat não produz qualquer lixo ( por exemplo, zeros à direita) e irá retornar: 3.1415926 .. se você está assim inclinado. Concedido, é um pouco detalhado para o gosto de alguns desenvolvedores - mas, ei, ele tem pouca memória durante o processamento e é muito fácil de implementar.]

Então, essencialmente, a beleza do DecimalFormat é que ele lida simultaneamente com a aparência da string - bem como o nível de precisão do arredondamento definido. Ergo: você obtém dois benefícios pelo preço de uma implementação de código. ;)




Aqui está um resumo do que você pode usar se você quiser o resultado como 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();

Aqui está uma sugestão de quais bibliotecas você pode usar se quiser double como resultado. Eu não recomendaria isso para a conversão de strings, já que o dobro pode não ser capaz de representar exatamente o que você quer (veja, por exemplo, here ):

  1. Precision do Apache Commons Math

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

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

    double rounded = Utils.roundDouble(0.912385, 5)






Desde que eu não encontrei nenhuma resposta completa sobre este tema eu coloquei uma classe que deve lidar com isso corretamente, com suporte para:

  • Formatação : formate facilmente um duplo para string com um certo número de casas decimais
  • Análise : Analisar o valor formatado de volta para o dobro
  • Localidade : formatar e analisar usando a localidade padrão
  • Notação exponencial : Comece a usar a notação exponencial após um certo limite

O uso é bem simples :

(Por causa deste exemplo, estou usando uma localidade personalizada)

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

Aqui está a aula :

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

}



Apenas no caso de alguém ainda precisar de ajuda com isso. Esta solução funciona perfeitamente para mim.

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

}

retorna um String com a saída desejada.




Eu vim aqui apenas querendo uma resposta simples sobre como arredondar um número. Esta é uma resposta suplementar para fornecer isso.

Como arredondar um número em Java

O caso mais comum é usar Math.round() .

Math.round(3.7) // 4

Os números são arredondados para o número inteiro mais próximo. Um valor de .5 é arredondado para cima. Se você precisar de um comportamento de arredondamento diferente daquele, poderá usar uma das outras funções Math . Veja a comparação abaixo.

round

Como dito acima, isso arredonda para o número inteiro mais próximo. .5 casas decimais arredondadas. Este método retorna um 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

Qualquer valor decimal é arredondado para o próximo inteiro. Isso vai para o teto . Este método retorna um 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

Qualquer valor decimal é arredondado para o próximo inteiro. Este método retorna um 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

Isso é semelhante a arredondar esses valores decimais para o inteiro mais próximo. No entanto, ao contrário de round , os valores de .5 arredondam para o inteiro par. Este método retorna um 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 ***



Concordo com a resposta escolhida para usar DecimalFormat --- ou, em alternativa, BigDecimal .

Por favor, leia Atualização abaixo primeiro!

No entanto, se você quiser arredondar o valor duplo e obter um resultado com valor double , poderá usar org.apache.commons.math3.util.Precision.round(..) conforme mencionado acima. A implementação usa BigDecimal , é lenta e cria lixo.

Um método semelhante, mas rápido e sem lixo, é fornecido pelo utilitário DoubleRounder na biblioteca 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);

Saída

 0.667
 0.666
 1000.0
 9.00800700601E10

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

Disclaimer: Estou envolvido no projeto decimal4j.

Update: Como @iaforek apontou DoubleRounder, por vezes, retorna resultados contra-intuitivos. A razão é que ele realiza um arredondamento matematicamente correto. Por exemplo, DoubleRounder.round(256.025d, 2) será arredondado para 256.02 porque o valor double representado como 256.025d é um pouco menor que o valor racional 256.025 e, portanto, será arredondado para baixo.

Notas:

  • Esse comportamento é muito semelhante ao do construtor BigDecimal(double) (mas não para valueOf(double) que usa o construtor de string).
  • O problema pode ser contornado com um passo de arredondamento duplo para uma precisão maior primeiro, mas é complicado e eu não vou entrar nos detalhes aqui

Por essas razões e tudo mencionado acima neste post não posso recomendar o uso do DoubleRounder .




Para conseguir isso, podemos usar este formatador:

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

ou:

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

Use este método para obter sempre duas casas decimais:

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

Definindo esses valores:

91.32
5.22
11.5
1.2
2.6

Usando o método, podemos obter os seguintes resultados:

91.32
5.22
11.50
1.20
2.60

demonstração online.




Onde dp = casa decimal que você quer, e o valor é um duplo.

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

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



Se você estiver usando uma tecnologia que tenha um mínimo de JDK. Aqui está uma maneira sem quaisquer bibliotecas Java:

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





Related