O uso de java.matemática.MathContext
-
08-06-2019 - |
Pergunta
Recentemente eu tentei compreender o uso das o java.matemática.MathContext mas não conseguiu entender corretamente.Ele é usado para arredondamento java.math.BigDecimal
.Se sim, por que não arredondar os dígitos decimais mas mesmo mantissa parte.
A partir da API do google docs, eu vim a saber que ele segue o padrão especificado no ANSI X3.274-1996
e ANSI X3.274-1996/AM 1-2000
especificações mas eu não levá-los para leitura on-line.
Por favor, deixe-me saber se você tem alguma idéia sobre isso.
Solução
@jatan
Obrigado por responder.Faz sentido.Você pode por favor me explicar MathContext no contexto de BigDecimal#método redonda.
Não há nada de especial sobre BigDecimal.round()
vs. qualquer outro BigDecimal
o método.Em todos os casos, a MathContext
especifica o número de algarismos significativos e arredondamento técnica.Basicamente, há duas peças de cada MathContext
.Há uma precisão, e há também um RoundingMode
.
A precisão novamente especifica o número de dígitos significativos.Portanto, se você especificar 123
como um número, e pedir para 2 algarismos significativos, você está indo para obter 120
.Ele pode ser mais claro se você pensar em termos de notação científica.
123
seria 1.23e2
em notação científica.Se você manter apenas 2 algarismos significativos, em seguida, você obter 1.2e2
, ou 120
.Reduzindo o número de algarismos significativos, podemos reduzir a precisão com que podemos especificar um número.
O RoundingMode
parte especifica como devemos lidar com a perda de precisão.Para reutilizar o exemplo, se você usar 123
como o número e pedir para 2 algarismos significativos, já reduzido a sua precisão.Com um RoundingMode
de HALF_UP
(modo padrão), 123
vai se tornar 120
.Com um RoundingMode
de CEILING
, você vai ter 130
.
Por exemplo:
System.out.println(new BigDecimal("123.4",
new MathContext(4,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.CEILING)));
System.out.println(new BigDecimal("123.4",
new MathContext(1,RoundingMode.CEILING)));
Saídas:
123.4
1.2E+2
1.3E+2
2E+2
Você pode ver que tanto a precisão e o modo de arredondamento afetar a saída.
Outras dicas
Para o arredondamento apenas a parte fracionária de um BigDecimal, confira o BigDecimal.setScale(int newScale, int roundingMode)
o método.
E. g.para alterar um número com três dígitos após o ponto decimal para um com dois dígitos, e o arredondamento para cima:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
O resultado disso é um BigDecimal com o valor de 1,24 (por causa da regra de arredondamento para cima)
Eu gostaria de acrescentar aqui, alguns exemplos.Eu não encontrei-os em respostas anteriores, mas eu encontrá-los úteis para aqueles que talvez enganar algarismos significativos com o número de casas decimais.Vamos supor que temos tal contexto:
MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Para que este código:
BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
é perfeitamente claro, que o resultado é 1.23E+3
como a galera disse acima.Primeiro algarismos significativos são 123...
Mas o que neste caso:
BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
seu número não será arredondado para 3 lugares após a vírgula - para alguém que não pode ser, intuitiva e vale a pena ressaltar.Em vez disso, ele será arredondado para o os primeiros 3 dígitos significativos, que neste caso são "4 5 4".Assim o código acima resulta em 4.55E-7
e não em 0.000
como alguém poderia esperar.
Exemplos semelhantes:
BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX);
System.out.println(d3); // 0.00100
BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX);
System.out.println(d4); // 0.200
BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX);
System.out.println(d5); //4.00E-9
Eu espero que isso óbvio, mas relevante exemplo seria útil...
Se eu estou entendendo bem, parece que está esperando o MathContext para controlar quantos dígitos deve ser mantido após o ponto decimal.Que não é o que ele serve.Especifica quantos dígitos para manter, total.Portanto, se você especificar que você deseja 3 algarismos significativos, isso é tudo que você vai conseguir.
Por exemplo, este:
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(20)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(10)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(5)));
saída:
1234567890.123456789
1234567890
1.2346E+9
Não é para se divertir.Na verdade, eu encontrei alguns on-line exemplo, que afirmaram que o uso de MathContext
para arredondar os valores e números armazenados na BigDecimal.
Por exemplo,
Se MathContext
está configurado para ter precision = 2
e rounding mode = ROUND_HALF_EVEN
BigDecimal Number = 0.5294
, é arredondado para 0.53
Então eu achei que é uma nova técnica e a usou para arredondamento finalidade.No entanto, ele se transformou em pesadelo, pois começou a arredondamento mesmo mentissa parte do número.
Por exemplo,
Number = 1.5294
é arredondado para 1.5
Number = 10.5294
é arredondado para 10
Number = 101.5294
é arredondado para 100
....e assim por diante
Portanto, este não é o comportamento esperado para o arredondamento (precisão = 2).
Ele parece estar tendo um pouco de lógica, pois, a partir fraseado eu posso dizer que ele leva dois primeiros dígitos (como a precisão é 2), do número e, em seguida, anexa 0 até o sem.de dígitos tornar-se mesmo como anterior não-arredondada quantidade ("checkout", a exemplo de 101.5294 ...)