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.

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 .


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 „.



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.


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/


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

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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.