Установите точность BigDecimal, только если десятичные дроби повторяются

Я знаю, что могу использовать метод BigDecimal.divide() для установки фиксированной точности:

BigDecimal a1 = new BigDecimal(1);
BigDecimal a2 = new BigDecimal(3);
BigDecimal division = a1.divide(a2,5,1); //equals 0.33333

Но если результат деления точен:

BigDecimal a1 = new BigDecimal(1);
BigDecimal a2 = new BigDecimal(4);
BigDecimal division = a1.divide(a2,5,1); //equals 0.25000

Как я могу установить результат деления, чтобы, если деление заканчивается точным результатом, оно просто давало результат 0,25 вместо 0,25000?

Я также пытался не указывать точность, выполнив:

BigDecimal division = a1.divide(a2);

ему удается дать результат 0.25 при выполнении 1/4, но когда он выполняет деление, такое как 1/3 или 2/3, это приводит к времени выполнения ArithmeticException.

a1 и a2 создаются из пользовательского ввода.

Есть ли способ решить эту проблему?


person user3411184    schedule 06.05.2015    source источник
comment
Вам следует предпочесть класс RoundingMode, а не передачу в целочисленном режиме округления значений. Даже если по какой-либо причине вам необходимо использовать целочисленные методы, используйте константы в BigDecimal, например. BigDecimal.ROUND_DOWN.   -  person dimo414    schedule 06.05.2015
comment
о, я вижу, я не был уверен, что выбрать, поэтому вместо этого я просто использую int. Но спасибо теперь понял.   -  person user3411184    schedule 06.05.2015


Ответы (1)


Вы получаете ArithmeticException, как описано в BigDecimal.divide(BigDecimal) - "если точное частное не имеет конечного десятичного расширения", поскольку для правильного представления результата 1/3 потребуется бесконечная память. Используя BigDecimal.divide(BigDecimal,int,RoundingMode) вы явно указываете допустимую точность, то есть любое деление может быть аппроксимировано в памяти.

Для согласованности эта версия деления всегда устанавливает масштаб в соответствии с указанным вами, даже если значение может быть точно представлено с меньшей точностью. Если бы это было не так, вам было бы трудно рассуждать о том, насколько точными будут будущие вычисления с использованием этого результата.

Чтобы уменьшить точность, используйте .stripTrailingZeros(); это эффективно уменьшает масштаб до минимально возможного. Сделайте это как можно позже (т. е. прямо перед печатью), чтобы сохранить согласованность, о которой я упоминал выше.

Вам также может понадобиться .toPlainString() если вы пытаетесь отобразить эти значения красиво, поскольку .stripTrailingZeros() сам по себе будет отображать 100 как 1E+2.

person dimo414    schedule 06.05.2015
comment
Аналогично: заголовок stackoverflow.com/questions/25541684/ (да, это бессовестная самореклама) - person jdphenix; 06.05.2015
comment
Возможно, стоит упомянуть BigDecimal(string) по сравнению с BigDecimal(double) и то, как последний может негативно повлиять на форматирование вывода. - person jdphenix; 06.05.2015
comment
@jdphenix OP использует BigDecimal(int)< /a> без потерь - я не понимаю, как ограничения BigDecimal(double) имеют отношение к этому вопросу, но есть ссылка на документацию по конструктору, если она кому-то поможет. - person dimo414; 06.05.2015
comment
Я собираюсь преобразовать значение BigInt в BigDecimal, так что, думаю, потерь нет. В любом случае большое спасибо. Работает очень хорошо, не знал, что такая функция существует.. - person user3411184; 06.05.2015