setscale - Uso de java.math.MathContext
bigdecimal java (5)
@jatan
Gracias por tu respuesta. Que tiene sentido. ¿Puedes explicarme MathContext en el contexto del método BigDecimal # round?
No hay nada especial acerca de BigDecimal.round()
frente a cualquier otro método BigDecimal
. En todos los casos, MathContext
especifica el número de dígitos significativos y la técnica de redondeo. Básicamente, hay dos partes de cada MathContext
. Hay una precisión, y también hay un RoundingMode
.
La precisión nuevamente especifica el número de dígitos significativos. Entonces, si especifica 123
como un número y pide 2 dígitos significativos, obtendrá 120
. Podría ser más claro si piensas en términos de notación científica.
123
sería 1.23e2
en notación científica. Si solo conserva dos dígitos significativos, obtiene 1.2e2
o 120
. Al reducir el número de dígitos significativos, reducimos la precisión con la que podemos especificar un número.
La parte RoundingMode
especifica cómo debemos manejar la pérdida de precisión. Para reutilizar el ejemplo, si usa 123
como número y solicita 2 dígitos significativos, ha reducido su precisión. Con un RoundingMode
de HALF_UP
(el modo predeterminado), 123
se convertirá en 120
. Con un RoundingMode
de CEILING
, obtendrá 130
.
Por ejemplo:
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)));
Productos:
123.4
1.2E+2
1.3E+2
2E+2
Puede ver que tanto la precisión como el modo de redondeo afectan la salida.
Recientemente intenté entender el uso de java.math.MathContext pero no entendí bien. ¿Se utiliza para redondear en java.math.BigDecimal
, si es así, por qué no redondea los dígitos decimales, sino incluso la parte mentissa.
De los documentos de la API, llegué a saber que sigue el estándar especificado en las especificaciones ANSI X3.274-1996
y ANSI X3.274-1996/AM 1-2000
pero no conseguí que se leyeran en línea.
Por favor, avíseme si tiene alguna idea al respecto.
No es por diversión De hecho, encontré algunos ejemplos en línea, que indicaban el uso de MathContext
para redondear las cantidades / números almacenados en BigDecimal.
Por ejemplo,
Si MathContext
está configurado para tener precision = 2
y rounding mode = ROUND_HALF_EVEN
BigDecimal Number = 0.5294
, se redondea a 0.53
Entonces pensé que era una técnica más nueva y la usé para redondear el propósito. Sin embargo, se convirtió en una pesadilla porque comenzó a redondear incluso a mentissa como parte del número.
Por ejemplo,
Number = 1.5294
se redondea a 1.5
Number = 10.5294
se redondea a 10
Number = 101.5294
se redondea a 100
.... y así
Entonces este no es el comportamiento que esperaba para redondear (como precisión = 2).
Parece tener algo de lógica porque de golpeteo puedo decir que toma los primeros dos dígitos (como la precisión es 2) de número y luego agrega 0 hasta el no. de dígitos se vuelven iguales a la cantidad no redondeada (consulte el ejemplo de 101.5294 ...)
Para redondear solo la parte fraccional de un BigDecimal, consulte el BigDecimal.setScale(int newScale, int roundingMode)
.
Por ejemplo, para cambiar un número con tres dígitos después del punto decimal a uno con dos dígitos, y redondeando hacia arriba:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
El resultado de esto es un BigDecimal con el valor 1.24 (debido a la regla de redondeo)
Si te entiendo correctamente, parece que esperas que MathContext controle cuántos dígitos se deben guardar después del punto decimal. Para eso no es para eso. Especifica cuántos dígitos conservar, total . Entonces, si especifica que desea 3 dígitos significativos, eso es todo lo que obtendrá.
Por ejemplo, esto:
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)));
dará salida:
1234567890.123456789
1234567890
1.2346E+9
Yo agregaría aquí, algunos ejemplos. No los he encontrado en respuestas anteriores, pero los considero útiles para aquellos que pueden confundir dígitos significativos con el número de decimales . Supongamos, tenemos ese contexto:
MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Para este código:
BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
está perfectamente claro, que tu resultado es 1.23E+3
como dicen los chicos arriba. Los primeros dígitos significativos son 123 ...
Pero que en este caso:
BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
su número no se redondeará a 3 lugares después de la coma ; para alguien, puede no ser intuitivo y vale la pena destacarlo. En cambio, se redondeará a los primeros 3 dígitos significativos , que en este caso son "4 5 4". Por lo tanto, el código anterior da como resultado 4.55E-7
y no en 0.000
como podría esperarse.
Ejemplos similares:
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
Espero que este ejemplo obvio pero relevante sea útil ...