ArithmeticException: „Niekończące się rozwinięcie dziesiętne; brak dokładnego reprezentatywnego wyniku dziesiętnego ”

507

Dlaczego poniższy kod podnosi wyjątek pokazany poniżej?

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

Wyjątek:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
Jason
źródło

Odpowiedzi:

841

Z Java 11 BigDecimaldocs :

Gdy MathContextobiekt jest dostarczany z ustawieniem dokładności 0 (na przykład MathContext.UNLIMITED), operacje arytmetyczne są dokładne, podobnie jak metody arytmetyczne, które nie przyjmują MathContextobiektu. (Jest to jedyne zachowanie obsługiwane w wersjach wcześniejszych niż 5.)

W następstwie obliczenia dokładnego wyniku ustawienie trybu zaokrąglania MathContextobiektu z ustawieniem dokładności 0 nie jest używane, a zatem nie ma znaczenia. W przypadku dzielenia dokładny iloraz może mieć nieskończenie długie rozszerzenie dziesiętne; na przykład 1 podzielone przez 3.

Jeśli iloraz ma niekończące się rozwinięcie dziesiętne, a operacja jest podana w celu zwrócenia dokładnego wyniku, generowany ArithmeticExceptionjest znak an . W przeciwnym razie zwracany jest dokładny wynik podziału, tak jak w przypadku innych operacji.

Aby to naprawić, musisz zrobić coś takiego :

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

gdzie 2 to skala, a RoundingMode.HALF_UP to tryb zaokrąglania

Aby uzyskać więcej informacji, zobacz ten post na blogu .

DVK
źródło
3
działa to również w przypadku błędu jaspis dzięki community.jaspersoft.com/questions/528968/...
shareef
27
2 NIE jest precision; to jest scale. Proszę zobaczyć docs.oracle.com/javase/7/docs/api/java/math/…
John Manko
(new BigDecimal (100)). divide (new BigDecimal (0.90), 2,
RoundingMode.HALF_UP
@AnandVarkeyPhilips To jest skala. Zobacz Javadoc . Edycja odrzucona.
Markiz Lorne
@ user207421, przypadkowo go edytowałem i próbowałem przywrócić .. Ale nie miałem wystarczającej liczby punktów, aby usunąć edycję .... meta.stackexchange.com/questions/80933/
Anand Varkey Philips
76

Ponieważ nie określasz precyzji i trybu zaokrąglania. BigDecimal narzeka, że ​​mógłby użyć 10, 20, 5000 lub miejsc dziesiętnych nieskończoności i nadal nie byłby w stanie podać dokładnej reprezentacji liczby. Zamiast więc podawać niepoprawny BigDecimal, po prostu drwi z ciebie.

Jeśli jednak podasz tryb RoundingMode i precyzję, będzie on w stanie przekonwertować (np. 1.333333333 na nieskończoność do czegoś takiego jak 1.3333 ... ale jako programista musisz powiedzieć mu, z jaką precyzją jesteś zadowolony „.

David Bullock
źródło
13

Do rozwiązania takiego problemu użyłem poniższego kodu

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

2 to precyzja. Teraz problem został rozwiązany.

Prahlad
źródło
3
oprócz kodu należy podać wyjaśnienie.
Martin Serrano,
11
2 NIE jest precision; to jest scale. Zobacz docs.oracle.com/javase/7/docs/api/java/math/...
John Manko
3
RoundingMode.HALF_EVEN jest zalecany do aplikacji finansowych. Tego używa się w bankowości
ACV
Dla tych, którzy są zdezorientowani komentarzem Johna Mankosa na temat precyzji, zobacz tę odpowiedź stackoverflow.com/questions/4591206/...
Stimpson Cat
5

Miałem ten sam problem, ponieważ mój wiersz kodu to:

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

Przechodzę do tego, czytając poprzednią odpowiedź, ponieważ nie pisałem precyzji dziesiętnej:

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

4 to Precyzja dziesiętna

ORAZ RoundingMode to stałe Enum, możesz wybrać dowolną z nich UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

W tym przypadku HALF_UP będzie miał następujący wynik:

2.4 = 2   
2.5 = 3   
2.7 = 3

Możesz sprawdzić RoundingModeinformacje tutaj: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Alex Montenegro 1987
źródło
4 to skala, a nie precyzja.
Markiz Lorne
3

Problem polega na zaokrągleniu wyniku, dla mnie rozwiązanie jest następujące.

divider.divide(dividend,RoundingMode.HALF_UP);
Jorge Santos Neill
źródło
1

Odpowiedz na BigDecimal zgłasza wyjątek 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")));
    }

Dodaj obiekt MathContext do wywołania metody dzielenia i dostosuj tryb precyzji i zaokrąglania. To powinno rozwiązać twój problem

Poorna Chander
źródło
0

Twój program nie wie, jakiej precyzji użyć liczb dziesiętnych, więc rzuca:

java.lang.ArithmeticException: Non-terminating decimal expansion

Rozwiązanie w celu obejścia wyjątku:

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ć
źródło