ArithmeticException: “Expansión decimal sin terminación; sin resultado decimal representable exacto "


507

¿Por qué el siguiente código genera la excepción que se muestra a continuación?

BigDecimal a = new BigDecimal("1.6");
BigDecimal b = new BigDecimal("9.2");
a.divide(b) // results in the following exception.

Excepción:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

Respuestas:


844

De los documentos de Java 11BigDecimal :

Cuando MathContextse suministra un objeto con una configuración de precisión de 0 (por ejemplo, MathContext.UNLIMITED), las operaciones aritméticas son exactas, al igual que los métodos aritméticos que no toman ningún MathContextobjeto. (Este es el único comportamiento admitido en las versiones anteriores a la 5.)

Como corolario de calcular el resultado exacto, la configuración del modo de redondeo de un MathContextobjeto con una configuración de precisión de 0 no se utiliza y, por lo tanto, es irrelevante. En el caso de dividir, el cociente exacto podría tener una expansión decimal infinitamente larga; por ejemplo, 1 dividido por 3.

Si el cociente tiene una expansión decimal no determinante y la operación se especifica para devolver un resultado exacto, ArithmeticExceptionse arroja un. De lo contrario, se devuelve el resultado exacto de la división, como se hizo para otras operaciones.

Para solucionarlo, debe hacer algo como esto :

a.divide(b, 2, RoundingMode.HALF_UP)

donde 2 es la escala y RoundingMode.HALF_UP es el modo de redondeo

Para más detalles vea esta publicación de blog .


3
esto también funciona para el error de jaspe gracias community.jaspersoft.com/questions/528968/…
shareef

27
2 NO es precision; es scale. Consulte docs.oracle.com/javase/7/docs/api/java/math/…
John Manko el

(nuevo BigDecimal (100)). divide (nuevo BigDecimal (0.90), 2, RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips Es la escala. Ver el Javadoc . Editar rechazado.
Marqués de Lorne

@ user207421, lo edité accidentalmente e intenté revertirlo ... Pero no tenía suficientes puntos para eliminar una edición ... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips

76

Porque no estás especificando una precisión y un modo de redondeo. BigDecimal se queja de que podría usar 10, 20, 5000 o infinitos decimales, y aún así no podría darle una representación exacta del número. Entonces, en lugar de darle un BigDecimal incorrecto, simplemente se queja.

Sin embargo, si proporciona un RoundingMode y una precisión, entonces podrá convertir (por ejemplo, 1.333333333 al infinito en algo así como 1.3333 ... pero usted como programador necesita decirle con qué precisión está 'contento' '.



13

Para solucionar este problema, he usado el siguiente código

a.divide(b, 2, RoundingMode.HALF_EVEN)

2 es precisión. Ahora el problema fue resuelto.


3
Además del código, se debe proporcionar alguna explicación.
Martin Serrano

11
2 NO es precision; es scale. Consulte docs.oracle.com/javase/7/docs/api/java/math/…
John Manko el

3
RoundingMode.HALF_EVEN se recomienda para aplicaciones financieras. Esto es lo que se usa en la banca
ACV

Para aquellos que están confundidos por el comentario de John Mankos sobre la precisión, vea esta respuesta stackoverflow.com/questions/4591206/…
Stimpson Cat

5

Tuve este mismo problema, porque mi línea de código era:

txtTotalInvoice.setText(var1.divide(var2).doubleValue() + "");

Me cambio a esto, leyendo la respuesta anterior, porque no estaba escribiendo precisión decimal:

txtTotalInvoice.setText(var1.divide(var2,4, RoundingMode.HALF_UP).doubleValue() + "");

4 es precisión decimal

Y RoundingMode son constantes Enum, puede elegir cualquiera de estos UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

En este caso HALF_UP, tendrá este resultado:

2.4 = 2   
2.5 = 3   
2.7 = 3

Puede consultar la RoundingModeinformación aquí: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/


4 es la escala, no la precisión.
Marqués de Lorne

3

Se trata de redondear el resultado, la solución para mí es la siguiente.

divider.divide(dividend,RoundingMode.HALF_UP);

1

Respuesta para BigDecimal lanza ArithmeticException

public static void main(String[] args) {
        int age = 30;
        BigDecimal retireMentFund = new BigDecimal("10000.00");
        retireMentFund.setScale(2,BigDecimal.ROUND_HALF_UP);
        BigDecimal yearsInRetirement = new BigDecimal("20.00");
        String name = " Dennis";
        for ( int i = age; i <=65; i++){
            recalculate(retireMentFund,new BigDecimal("0.10"));
        }
        BigDecimal monthlyPension =   retireMentFund.divide(
                yearsInRetirement.divide(new BigDecimal("12"), new MathContext(2, RoundingMode.CEILING)), new MathContext(2, RoundingMode.CEILING));      
        System.out.println(name+ " will have £" + monthlyPension +" per month for retirement");
    }
public static void recalculate (BigDecimal fundAmount, BigDecimal rate){
        fundAmount.multiply(rate.add(new BigDecimal("1.00")));
    }

Agregue el objeto MathContext en su llamada al método de división y ajuste la precisión y el modo de redondeo. Esto debería solucionar tu problema


0

Su programa no sabe qué precisión utilizar para los números decimales, por lo que arroja:

java.lang.ArithmeticException: Non-terminating decimal expansion

Solución para evitar la excepción:

MathContext precision = new MathContext(int setPrecisionYouWant); // example 2
BigDecimal a = new BigDecimal("1.6",precision);
BigDecimal b = new BigDecimal("9.2",precision);
a.divide(b) // result = 0.17
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.