ArithmeticException: “Expansão decimal sem finalização; nenhum resultado decimal representável exato "

507

Por que o código a seguir gera a exceção mostrada abaixo?

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

Exceção:

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

Respostas:

843

Nos documentos do Java 11BigDecimal :

Quando um MathContextobjeto é fornecido com uma configuração de MathContext.UNLIMITEDprecisão igual a 0 (por exemplo ), as operações aritméticas são exatas, assim como os métodos aritméticos que não levam MathContextobjetos. (Esse é o único comportamento que foi suportado em releases anteriores ao 5.)

Como corolário da computação do resultado exato, a configuração do modo de arredondamento de um MathContextobjeto com uma precisão de 0 não é usada e, portanto, irrelevante. No caso de divisão, o quociente exato pode ter uma expansão decimal infinitamente longa; por exemplo, 1 dividido por 3.

Se o quociente tiver uma expansão decimal não terminante e a operação for especificada para retornar um resultado exato, um ArithmeticExceptionserá lançado. Caso contrário, o resultado exato da divisão será retornado, como feito para outras operações.

Para corrigir, você precisa fazer algo assim :

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

onde 2 é a escala e RoundingMode.HALF_UP está no modo de arredondamento

Para mais detalhes, consulte esta postagem no blog .

DVK
fonte
3
Isso funciona para erro Jasper também graças community.jaspersoft.com/questions/528968/...
shareef
27
2 não é precision; ele é scale. Por favor, veja docs.oracle.com/javase/7/docs/api/java/math/...
John Manko
(new BigDecimal (100)). divide (new BigDecimal (0.90), 2,
RoundingMode.HALF_UP
@AnandVarkeyPhilips É a escala. Veja o Javadoc . Edição rejeitada.
Marquês de Lorne
@ user207421, editei-o acidentalmente e tentei reverter .. Mas não tinha pontos suficientes para excluir uma edição .... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips
76

Porque você não está especificando uma precisão e um modo de arredondamento. O BigDecimal está reclamando que poderia usar 10, 20, 5000 ou casas decimais infinitas e ainda assim não seria capaz de fornecer uma representação exata do número. Então, em vez de fornecer a você um BigDecimal incorreto, ele apenas se irrita.

No entanto, se você fornecer um RoundingMode e uma precisão, ele poderá converter (por exemplo, 1.333333333 para infinito para algo como 1,3333 ... mas você, como programador, precisa dizer com que precisão está satisfeito '

David Bullock
fonte
13

Para corrigir esse problema, usei o código abaixo

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

2 é precisão. Agora o problema foi resolvido.

Prahlad
fonte
3
Além do código, algumas explicações devem ser fornecidas.
Martin Serrano
11
2 não é precision; ele é scale. Por favor, consulte docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
3
RoundingMode.HALF_EVEN é recomendado para aplicativos financeiros. Isto é o que é usado no setor bancário
ACV
Para aqueles que estão confusos com o comentário de John Mankos sobre precisão, consulte esta resposta stackoverflow.com/questions/4591206/…
Stimpson Cat
5

Eu tive esse mesmo problema, porque minha linha de código era:

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

Eu mudo para isso, lendo a Resposta anterior, porque não estava escrevendo precisão decimal:

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

4 é Precisão Decimal

AND RoundingMode são constantes Enum, você pode escolher qualquer uma dessas UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

Nesse caso, HALF_UP, terá este resultado:

2.4 = 2   
2.5 = 3   
2.7 = 3

Você pode verificar as RoundingModeinformações aqui: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Alex Montenegro1987
fonte
4 é a escala, não a precisão.
Marquês de Lorne
3

É uma questão de arredondar o resultado, a solução para mim é a seguinte.

divider.divide(dividend,RoundingMode.HALF_UP);
Jorge Santos Neill
fonte
1

Resposta para BigDecimal lança 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")));
    }

Adicione o objeto MathContext à sua chamada ao método de divisão e ajuste a precisão e o modo de arredondamento. Isto deve corrigir o seu problema

Poorna Chander
fonte
0

Seu programa não sabe qual precisão os números decimais devem usar;

java.lang.ArithmeticException: Non-terminating decimal expansion

Solução para ignorar a exceção:

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ć
fonte