ArithmeticException: “Нескінченне десяткове розширення; немає точного представницького десяткового результату "


507

Чому наступний код підвищує виняток, показаний нижче?

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.

Відповіді:


842

З Java 11 BigDecimalдокументів :

Коли MathContextоб'єкт поставляється з точністю 0 (наприклад, MathContext.UNLIMITED), арифметичні операції є точними, як і арифметичні методи, у яких немає жодного MathContextоб'єкта. (Це єдина поведінка, яку підтримували у випусках до 5.)

Як наслідок обчислення точного результату, налаштування режиму округлення MathContextоб'єкта з точністю 0 не використовується і, таким чином, не має значення. У разі поділу точний коефіцієнт може мати нескінченно довге десяткове розширення; наприклад, 1 ділиться на 3.

Якщо коефіцієнт має недетерміновану десяткове розширення і вказана операція для повернення точного результату, ArithmeticExceptionкидається а. В іншому випадку повертається точний результат поділу, як це робиться для інших операцій.

Для виправлення потрібно зробити щось подібне :

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

де 2 - масштаб, а RoundingMode.HALF_UP - режим округлення

Детальніше дивіться у цій публікації в блозі .


3
це працює і для помилки яшма, дякую спільноті.jaspersoft.com
questions/528968/…

27
2 НЕ precision; це scale. Будь ласка, дивіться docs.oracle.com/javase/7/docs/api/java/math/…
Джон Манко

(новий BigDecimal (100)). ділити (новий BigDecimal (0,90), 2, RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips Це масштаб. Дивіться Javadoc . Редагування відхилено.
Маркіз Лорн

@ user207421, я випадково відредагував його і спробував відновити .. Але не вистачило балів, щоб видалити правки .... meta.stackexchange.com/questions/80933/…
Anand Varkey Philips

76

Тому що ви не визначаєте точність та режим округлення. BigDecimal скаржиться, що він може використовувати 10, 20, 5000 або нескінченних десяткових знаків, і все одно не зможе дати вам точне представлення числа. Тож замість того, щоб дати вам неправильний BigDecimal, він просто зависає на вас.

Однак якщо ви поставите RoundingMode та точність, він зможе перетворити (наприклад, 1.333333333-до-нескінченності до чогось типу 1.3333 ..., але вам як програмісту потрібно сказати, якою точністю ви задоволені '.



13

Для виправлення такої проблеми я використав код нижче

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

2 - точність. Зараз проблема була вирішена.


3
окрім коду, слід надати певне пояснення.
Мартін Серрано

11
2 НЕ precision; це scale. Перегляньте docs.oracle.com/javase/7/docs/api/java/math/…
Джон Манко

3
RoundingMode.HALF_EVEN рекомендується використовувати для фінансових програм. Це те, що використовується в банківській справі
ACV

Для тих, кого плутає коментар Джона Манкоса щодо точності, дивіться цю відповідь stackoverflow.com/questions/4591206/…
Кіт Стімпсона

5

У мене була ця сама проблема, тому що мій рядок коду:

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

Я змінюю це, читаючи попередній відповідь, оскільки я не писав десяткової точності:

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

4 - десяткова точність

І RoundingMode - константи Enum, ви можете вибрати будь-що з цього UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

У цьому випадку HALF_UP матиме такий результат:

2.4 = 2   
2.5 = 3   
2.7 = 3

Ви можете перевірити RoundingModeінформацію тут: http://www.javabeat.net/precision-rounding-of-decimals-using-rounding-mode-enumeration/


4 - шкала, а не точність.
Маркіз Лорн


1

Відповідь за BigDecimal кидки 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")));
    }

Додайте об'єкт MathContext у свій виклик методу розділення та відрегулюйте режим точності та округлення. Це повинно вирішити вашу проблему


0

Ваша програма не знає, яку точність використовувати для десяткових чисел, тому вона кидає:

java.lang.ArithmeticException: Non-terminating decimal expansion

Рішення для обходу виключення:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.