Java BigDecimal: arredondado para o valor inteiro mais próximo

89

Eu preciso dos seguintes resultados

100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

.round()ou .setScale()? Como faço isso?

n / D
fonte

Respostas:

151

Você pode usar setScale()para reduzir o número de dígitos fracionários a zero. Assumindo que valuemantém o valor a ser arredondado:

BigDecimal scaled = value.setScale(0, RoundingMode.HALF_UP);
System.out.println(value + " -> " + scaled);

Usar round()é um pouco mais complicado, pois requer que você especifique o número de dígitos a serem retidos. Em seus exemplos, seria 3, mas não é válido para todos os valores:

BigDecimal rounded = value.round(new MathContext(3, RoundingMode.HALF_UP));
System.out.println(value + " -> " + rounded);

(Observe que os BigDecimalobjetos são imutáveis; ambos setScalee roundretornarão um novo objeto.)

Grodriguez
fonte
1
Não está funcionando: 100,12: 100,12, 100,44: 100,44, 100,50: 100,5, 100,75: 100,75
Boris Pavlović
3
Não, definir a escala retorna um novo decimal que não é igual ao primeiro. Por exemplo: BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2));imprime falso
Daniel Fath
6
@Daniel: Isso já estava implícito no trecho de código que postei em minha resposta. Agora tornei isso explícito.
Grodriguez
RoundingModeo que é isso? ÉBigDecimal
trilogia de
10

Se eu for pela resposta de Grodriguez

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

Esta é a saída

100.23 -> 100
100.77 -> 101

O que não é bem o que eu quero, então acabei fazendo isso ..

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
value = value.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

Isso é o que eu recebo

100.23 -> 100.00
100.77 -> 101.00

Isso resolve meu problema por agora .. :) Obrigado a todos.

n / D
fonte
7
Estou curioso com a afirmação de que o primeiro resultado "não é bem o que eu quero ...". Se você está realmente preocupado com a formatação de saída, você pode usar DecimalFormat(como em new DecimalFormat("###.00")) para gerenciar a conversão de uma BigDecimalstring de volta em. Ele fornece "101.00"o resultado para ambos os valores que os snippets de @Grodriquez e você criaram.
joel.neely
3
A segunda vez que você está arredondando aqui é desnecessário, pois você sabe que já tem um número inteiro, então eu usaria BigDecimal.ROUND_UNNECESSARY, um pouco mais claro em minha opinião.
Kosmoplan
5

Esta é uma solução terrivelmente complicada, mas funciona:

public static BigDecimal roundBigDecimal(final BigDecimal input){
    return input.round(
        new MathContext(
            input.toBigInteger().toString().length(),
            RoundingMode.HALF_UP
        )
    );
}

Código de teste:

List<BigDecimal> bigDecimals =
    Arrays.asList(new BigDecimal("100.12"),
        new BigDecimal("100.44"),
        new BigDecimal("100.50"),
        new BigDecimal("100.75"));
for(final BigDecimal bd : bigDecimals){
    System.out.println(roundBigDecimal(bd).toPlainString());
}

Resultado:

100
100
101
101

Sean Patrick Floyd
fonte
Sem querer endossar essa solução nem nada, mas a input.toBigInteger().toString().length()parte seria muito mais eficiente usando um logaritmo, algo comoround_up(log(input)) + (1 if input is a power of ten, else 0)
Addison
0

Eu não acho que você pode contornar isso com um único comando. Experimentar

    ArrayList<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(new BigDecimal("100.12"));
    list.add(new BigDecimal("100.44"));
    list.add(new BigDecimal("100.50"));
    list.add(new BigDecimal("100.75"));

    for (BigDecimal bd : list){
        System.out.println(bd+" -> "+bd.setScale(0,RoundingMode.HALF_UP).setScale(2));
    }

Output:
100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

Testei o restante de seus exemplos e ele retorna os valores desejados, mas não garanto sua correção.

Daniel Fath
fonte
-2

Você quer

round(new MathContext(0));  // or perhaps another math context with rounding mode HALF_UP
jacobm
fonte
2
Isso não faz nada. Da documentação de round: "Se a configuração de precisão for 0, então nenhum arredondamento ocorrerá."
Grodriguez