BigDecimal divisão retornando resultado errado para alguns cálculos

XtremeBaumer:

Eu li algumas perguntas sobre flaoting números de ponto e sua matemática. Para mim parece que os problemas só acontecem em grandes escalas (ie 10+ decimais). Agora o meu problema acontece em 2 casas decimais já e sua muito grande fora em alguns casos:

Seguinte código:

System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()));
System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2).doubleValue()));

gera esta saída respectivamente:

0.80
0.89

Se eu executar os cálculos à mão (usando cálculos do Google), eu recebo estes resultados:

0.72351421188
0.88278388278

para os primeiros cálculos os resultados são muito grande (~ 0,08 desligado) enquanto que para o segundo um seu muito baixo (~ 0,01 desligado).

Existe alguma explicação sensata a respeito de porque thie primeiro resultado é que grande? Ou alguma maneira de obter o resultado correto usando BigDecimal?

Observe que

System.out.println(2.8/3.87);

realmente retorna o resultado correto (,7235142118863048).

Observe também que o String.formatmaterial só é utilizado para verificar se o resultado foi mudado por ele que não é o caso. BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()produz exatamente o mesmo resultado.

Kevin Cruijssen:

O problema é que você está usando o errado BigDecimal#dividepara o seu arredondamento para 2 casas decimais. Aqui estão os argumentos disponíveis para os BigDecimal#dividemétodos:

  • divide(BigDecimal divisor)
  • divide(BigDecimal divisor, int roundingMode)
  • divide(BigDecimal divisor, MathContext mc)
  • divide(BigDecimal divisor, RoundingMode roundingMode)
  • divide(BigDecimal divisor, int scale, int roundingMode)
  • divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

Desde que você está usando um dividecom um BigDecimale intargumento, portanto, usa o divide(BigDecimal divisor, int roundingMode), onde o seu 2é o modo de arredondamento e não a escala. Neste caso, 2é, na verdade ROUND_CEILING, ea escala não é especificado.

Em vez disso, você terá que usar o divide(BigDecimal divisor, int scale, int roundingMode)ou divide(BigDecimal divisor, int scale, RoundingMode roundingMode). Então mude suas chamadas para:

System.out.println(BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2, 
  BigDecimal.ROUND_HALF_UP));
System.out.println(BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2, 
  BigDecimal.ROUND_HALF_UP));

(Livremente para usar um modo de arredondamento diferente ROUND_HALF_UP.)

Experimente online.

Eu não tenho certeza do que escalá-lo usa por padrão, mas o ROUND_CEILINGque você especificou com os seus 2causaram os problemas em seus cálculos.


Quanto aos comentários mencionados, existem três maneiras possíveis para criar o BigDecimalcom os valores especificados:

  • BigDecimal.valueOf(2.8)
  • new BigDecimal(2.8)
  • new BigDecimal("2.8")

O new BigDecimal(2.8)ainda dá erros de ponto flutuante, por isso gostaria de aconselhar para usar BigDecimal.valueOf(2.8)como você já fez, ou o construtor de Cordas new BigDecimal("2.8").

Experimente online.

Isso tudo é um pouco irrelevante para os seus problemas de arredondamento no entanto, uma vez usando o correto dividemétodo vai dar os resultados corretos, independentemente da BigDecimalinicialização que você usou:

Experimente online.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=231826&siteId=1
Recomendado
Clasificación