web-dev-qa-db-fra.com

ArithmeticException: "Expansion décimale non terminale; pas de résultat décimal représentable exact"

Pourquoi le code suivant déclenche-t-il l'exception ci-dessous?

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

-

Java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
440
Jason

Depuis le Java 8 docs: 

Lorsqu'un objet MathContext est fourni avec un paramètre de précision de 0 (pour Exemple, MathContext.UNLIMITED), les opérations arithmétiques sont exactes, comme sont les méthodes arithmétiques qui ne prennent aucun objet MathContext. (Ceci est le seul comportement pris en charge dans les versions antérieures à la version 5.) 

Corollaire du calcul du résultat exact, réglage du mode d'arrondi d'un MathContext objet avec un réglage de précision de 0 n'est pas utilisé et donc sans importance. Dans Dans le cas d'une division, le quotient exact pourrait avoir une décimale infiniment longue expansion; par exemple, 1 divisé par 3. 

Si le quotient a une expansion décimale non-terminale et l'opération est spécifiée pour retourner un résultat exact, une exception ArithmeticException est levée . Autrement, le résultat exact de la division est renvoyé, comme indiqué pour autres opérations.

Pour résoudre ce problème, vous devez faire quelque chose comme ceci:

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

where 2 is precision and RoundingMode.HALF_UP is rounding mode

Plus de détails: http://jaydeepm.wordpress.com/2009/06/04/bigdecimal-and-non-terminating-decimal-expansion-error/

746
DVK

Parce que vous ne spécifiez pas une précision et un mode d'arrondi. BigDecimal se plaint de pouvoir utiliser 10 décimales, 20 décimales, 5 000 décimales ou une infinité de décimales, sans pouvoir vous donner une représentation exacte du nombre. Donc, au lieu de vous donner un BigDecimal incorrect, cela vous blesse.

Cependant, si vous fournissez un RoundingMode et une précision, il sera alors capable de convertir (par exemple, 1,333333333-à-l'infini en quelque chose comme 1,3333 ... mais vous en tant que programmeur devez lui indiquer quelle précision vous êtes satisfait '.

71
David Bullock

Tu peux faire 

a.divide(b, MathContext.DECIMAL128)

Vous pouvez choisir le nombre de bits que vous voulez soit 32,64,128.

Découvrez ce lien:

http://edelstein.pebbles.cs.cmu.edu/jadeite/main.php?api=Java6&state=class&package=Java.math&class=MathContext

46
MindBrain

Pour résoudre un tel problème, j'ai utilisé le code ci-dessous

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

2 est la précision. Maintenant le problème était résolu.

13
Prahlad

J'ai eu le même problème parce que ma ligne de code était:

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

Je change en lisant la réponse précédente, car je n'écrivais pas de précision décimale:

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

4 est la précision décimale 

ET RoundingMode sont des constantes Enum, vous pouvez choisir l'une de ces options UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

Dans ce cas, HALF_UP, aura ce résultat:

2.4 = 2   
2.5 = 3   
2.7 = 3

Vous pouvez vérifier les informations RoundingMode ici: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mound-enumeration/

6

C'est une question d'arrondir le résultat, la solution pour moi est la suivante.

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

Réponse pour BigDecimal lève 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")));
    }

Ajoutez un objet MathContext à votre appel à la méthode de division et ajustez le mode de précision et d'arrondissement. Cela devrait résoudre votre problème

1
Poorna Chander

C'est parce que le Bigdecimal n'a pas perdu, et si vous divisez 1/3 par exemple, le résultat sera un nombre décimal répété à l'infini. 0.33333333 ... théoriquement, si vous multipliez, vous obtenez le résultat exact. Mais, un nombre infini générera un débordement de pile et dans ce cas l'exception sera lancée. 

Ma solution:

 try {
     result = n1.divide(n2);
 } catch (ArithmeticException e){
     Log.d("Error bigdecimal", e.toString());
     result = (n1.doubleValue() / n2.doubleValue());
 };

dans ce cas, votre résultat ne sera pas réduit par l'arrondi

0
Leo Lima

Votre programme ne sait pas quelle précision utiliser pour les nombres décimaux, il jette:

Java.lang.ArithmeticException: Non-terminating decimal expansion

Solution pour contourner l'exception:

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
0
Miloš Ojdanić