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.
Jason
fuente

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 .

DVK
fuente
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' '.

David Bullock
fuente
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.

Prahlad
fuente
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/

Alex Montenegro1987
fuente
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);
Jorge Santos Neill
fuente
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

Poorna Chander
fuente
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
Miloš Ojdanić
fuente