ArithmeticException: „Nicht terminierende Dezimalerweiterung; kein genau darstellbares Dezimalergebnis “

507

Warum löst der folgende Code die unten gezeigte Ausnahme aus?

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

Ausnahme:

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

Antworten:

843

Aus den Java 11- BigDecimalDokumenten :

Wenn ein MathContextObjekt mit einer Genauigkeitseinstellung von 0 (zum Beispiel MathContext.UNLIMITED) versorgt wird , sind die arithmetischen Operationen genau, ebenso wie die arithmetischen Methoden, die no annehmenMathContext Objekt . (Dies ist das einzige Verhalten, das in Releases vor 5 unterstützt wurde.)

Als Folge der Berechnung des genauen Ergebnisses wird die Rundungsmoduseinstellung eines MathContextObjekts mit einer Genauigkeitseinstellung von 0 nicht verwendet und ist daher irrelevant. Im Fall der Teilung könnte der exakte Quotient eine unendlich lange Dezimalerweiterung haben; Zum Beispiel 1 geteilt durch 3.

Wenn der Quotient eine nicht endende Dezimalerweiterung hat und die Operation angegeben wird, um ein genaues Ergebnis zurückzugeben, wird ein ArithmeticExceptionausgelöst. Andernfalls wird das genaue Ergebnis der Aufteilung zurückgegeben, wie dies bei anderen Vorgängen der Fall ist.

Um dies zu beheben, müssen Sie Folgendes tun :

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

Dabei ist 2 die Skalierung und RoundingMode.HALF_UP der Rundungsmodus

Weitere Details finden Sie in diesem Blogbeitrag .

DVK
quelle
3
Dies funktioniert auch für Jaspis Fehler dank community.jaspersoft.com/questions/528968/…
shareef
27
2 ist NICHT precision; es ist scale. Bitte sehen Sie docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
(neues BigDecimal (100)). dividieren (neues BigDecimal (0,90), 2, RoundingMode.HALF_UP)
egemen
@AnandVarkeyPhilips Es ist die Skala. Siehe den Javadoc . Bearbeiten abgelehnt.
Marquis von Lorne
@ user207421, ich habe es versehentlich bearbeitet und versucht, es zurückzusetzen. Aber ich hatte nicht genug Punkte, um eine Bearbeitung zu löschen. meta.stackexchange.com/questions/80933/…
Anand Varkey Philips
76

Weil Sie keine Genauigkeit und keinen Rundungsmodus angeben. BigDecimal beschwert sich darüber, dass es 10, 20, 5000 oder unendlich viele Dezimalstellen verwenden könnte, und es wäre immer noch nicht in der Lage, Ihnen eine genaue Darstellung der Zahl zu geben. Anstatt dir also ein falsches BigDecimal zu geben, pfeift es dich nur an.

Wenn Sie jedoch einen RoundingMode und eine Präzision angeben, kann dieser konvertiert werden (z. B. 1.333333333-to-Infinity in etwa 1.3333 ... aber Sie als Programmierer müssen angeben, mit welcher Präzision Sie zufrieden sind '.

David Bullock
quelle
13

Um ein solches Problem zu beheben, habe ich den folgenden Code verwendet

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

2 ist Präzision. Jetzt wurde das Problem behoben.

Prahlad
quelle
3
Zusätzlich zum Code sollte eine Erklärung gegeben werden.
Martin Serrano
11
2 ist NICHT precision; es ist scale. Bitte sehen Sie docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
3
RoundingMode.HALF_EVEN wird für Finanzanwendungen empfohlen. Dies ist, was im Bankwesen verwendet wird
ACV
Für diejenigen, die durch John Mankos 'Kommentar zur Präzision verwirrt sind, lesen Sie bitte diese Antwort stackoverflow.com/questions/4591206/…
Stimpson Cat
5

Ich hatte das gleiche Problem, weil meine Codezeile war:

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

Ich ändere dies, indem ich die vorherige Antwort lese, weil ich keine Dezimalgenauigkeit geschrieben habe:

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

4 ist Dezimalpräzision

AND RoundingMode sind Enum-Konstanten. Sie können eine dieser Konstanten auswählen UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

In diesem Fall hat HALF_UP folgendes Ergebnis:

2.4 = 2   
2.5 = 3   
2.7 = 3

Sie können die RoundingModeInformationen hier überprüfen : http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Alex Montenegro1987
quelle
4 ist die Skala, nicht die Präzision.
Marquis von Lorne
3

Es geht darum, das Ergebnis abzurunden. Die Lösung für mich ist die folgende.

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

Antwort für BigDecimal löst ArithmeticException aus

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")));
    }

Fügen Sie Ihrem Divide-Methodenaufruf ein MathContext-Objekt hinzu und passen Sie die Genauigkeit und den Rundungsmodus an. Dies sollte Ihr Problem beheben

Poorna Chander
quelle
0

Ihr Programm weiß nicht, welche Genauigkeit für Dezimalzahlen verwendet werden soll, daher wird Folgendes ausgelöst:

java.lang.ArithmeticException: Non-terminating decimal expansion

Lösung zur Umgehung der Ausnahme:

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