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.

Ответы:


844

Из документов Java 11BigDecimal :

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

Как следствие вычисления точного результата, настройка режима округления MathContextобъекта с точностью настройки 0 не используется и, таким образом, не имеет значения. В случае деления точный фактор может иметь бесконечно длинное десятичное разложение; например, 1 делится на 3.

Если частное имеет неопределенное десятичное разложение, и указана операция для получения точного результата, генерируется значение ArithmeticException. В противном случае возвращается точный результат деления, как и для других операций.

Чтобы исправить, вам нужно сделать что-то вроде этого :

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

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

Для более подробной информации смотрите этот пост в блоге .


3
это работает и из-за ошибки яшмы, благодаря community.jaspersoft.com/questions/528968/…
shareef

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/…
Stimpson Cat,

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/precise-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.