ArithmeticException: «Expansion décimale sans terminaison; aucun résultat décimal représentable exact »

507

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

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

Exception:

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

Réponses:

844

Des Java 11 BigDecimaldocs :

Lorsqu'un MathContextobjet est fourni avec un paramètre de précision de 0 (par exemple, MathContext.UNLIMITED), les opérations arithmétiques sont exactes, tout comme les méthodes arithmétiques qui ne prennent aucun MathContextobjet. (Il s'agit du seul comportement pris en charge dans les versions antérieures à 5.)

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

Si le quotient a une expansion décimale non terminale et que l'opération est spécifiée pour renvoyer un résultat exact, un ArithmeticExceptionest levé. Sinon, le résultat exact de la division est renvoyé, comme pour les autres opérations.

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

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

où 2 est l'échelle et RoundingMode.HALF_UP est le mode d'arrondi

Pour plus de détails, consultez cet article de blog .

DVK
la source
3
cela fonctionne aussi pour l'erreur jasper merci community.jaspersoft.com/questions/528968/…
shareef
27
2 n'est PAS precision; c'est scale. Veuillez consulter docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
(nouveau BigDecimal (100)). divide (nouveau BigDecimal (0.90), 2, RoundingMode.HALF_UP)
egemen
@AnandVarkeyPhilips C'est l'échelle. Voir le Javadoc . Modification refusée.
Marquis de Lorne
@ user207421, je l'ai accidentellement modifié et j'ai essayé de revenir en arrière .. Mais je n'avais pas assez de points pour supprimer une modification .... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips
76

Parce que vous ne spécifiez pas une précision et un mode d'arrondi. BigDecimal se plaint qu'il pourrait utiliser 10, 20, 5000 ou décimales à l'infini, et il ne serait toujours pas en mesure de vous donner une représentation exacte du nombre. Ainsi, au lieu de vous donner un BigDecimal incorrect, il se contente de vous gémir.

Cependant, si vous fournissez un RoundingMode et une précision, il sera capable de convertir (par exemple, 1.333333333-à-infini en quelque chose comme 1.3333 ... mais vous, en tant que programmeur, devez lui dire avec quelle précision vous êtes satisfait '.

David Bullock
la source
13

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 a été résolu.

Prahlad
la source
3
en plus du code, une explication doit être fournie.
Martin Serrano
11
2 n'est PAS precision; c'est scale. Veuillez consulter docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
3
RoundingMode.HALF_EVEN est recommandé pour les applications financières. C'est ce qui est utilisé dans la banque
ACV
Pour ceux qui sont confus par le commentaire de John Mankos sur la précision, veuillez voir cette réponse stackoverflow.com/questions/4591206/…
Stimpson Cat
5

J'ai eu ce même problème, car ma ligne de code était:

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

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

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

4 est Precison Decimal

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 RoundingModeinformations ici: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Alex Montenegro1987
la source
4 est l'échelle, pas la précision.
Marquis de Lorne
3

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

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

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 dans votre appel de méthode de division et ajustez la précision et le mode d'arrondi. Cela devrait résoudre votre problème

Poorna Chander
la source
0

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

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