2016-02-23 4 views
0

Я получаю неправильный результат при выполнении деления с помощью BigDecimal. Number1 = 221500.0 Number2 = 12,0 Вот мой фрагмент кода:BigDecimal.Divide дает неверный результат

BigDecimal d1 = new BigDecimal(String.valueOf(number1)).setScale(13, 4); 
BigDecimal d2 = new BigDecimal(String.valueOf(number2)).setScale(13, 4); 
return (d1.divide(d2, 13, 4)).doubleValue(); 

18458,333333333332

, если я выполнил те же вычисления с помощью калькулятора дает 18458,333333333333333333333333333

Позвольте мне знать, какие проблемы с обрабатывая масштаб в BigDecimal. Будет полезно, если кто-то даст мне знать, как получить тот же результат с калькулятором.

+1

Это правильный результат. Вам действительно нужен такой длинный результат? –

+0

* Точный * такой же результат? Ваш калькулятор выплевывает только правильное количество 3s, или? На самом деле существует бесконечное количество 3-х. –

+1

BigDecimal работает точно так, как должно быть, учитывая, что вам нужно 13 значений. Если ваши цели требуют «точных результатов деления», скажем, для целей сравнения, пожалуйста, умножьте на некоторое предопределенное пороговое значение и сравните как int. В вашем случае 'double' не может удерживать значение, поэтому округление. –

ответ

4

Вы запросили divide() звонок за 13 цифр точности, и это то, что он вам дал.

Затем вы преобразовываете это в double и замечаете, что double не может справиться с этой точностью.

BigDecimal d1 = new BigDecimal(String.valueOf(221500.0)).setScale(13, BigDecimal.ROUND_HALF_UP); 
BigDecimal d2 = new BigDecimal(String.valueOf(12.0)).setScale(13, BigDecimal.ROUND_HALF_UP); 
BigDecimal d3 = d1.divide(d2, 13, BigDecimal.ROUND_HALF_UP); 
System.out.println("BigDecimal: " + d3); 
System.out.println("as double : " + d3.doubleValue()); 

ВЫВОД

BigDecimal: 18458.3333333333333 
as double : 18458.333333333332 

Если вы собираетесь выбросить лишнюю точность, полученную с помощью BigDecimal, почему бы просто не сделать математику в double?


На другой ноте:
Не делайте new BigDecimal(String.valueOf(doubleValue)).
Использование BigDecimal.valueOf(doubleValue).

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

+2

Что @Andreas говорит, не звоните .doubleValue(), так как это сделает ваше точное число в не столь точное двойное – Arkiliknam

3

Есть некоторые вещи, которые вы будете делать по-другому.

Как вы уже знаете, BigDecimal является отличным инструментом, так как:

  • он может сохранить десятичных цифр точно, в отличие от любого представления с плавающей запятой, такие как двойной или поплавок

  • это может работать с произвольными большими десятичными числами, в отличие от int, double и float

Однако, чтобы сделать его работу, вы должны держать несколько вещей в виду:

  • При установке значения в BigDecimal, всегда использовать представление типа String, так как только строки представление будет обрабатывать десятичную точность. Например, новый BigDecimal (String.valueOf (number1)) - плохая идея, если число является двойным (не может обрабатывать точные десятичные знаки), тогда вы будете скрывать нечеткое число в BigDecimal.

  • Не ограничивайте точность при создании BigDecimal. Обычно BigDecimal будет поддерживать точность ввода, т. Е. Новый BigDecimal («3.234») будет иметь 3 десятичных цифры.

  • Устанавливайте режим roudingMode после каждого деления. Обратитесь к JavaDoc для возможных режимов рутинга, HALF_EVEN - лучший выбор для обычных случаев использования.

  • Устанавливайте десятичную точность при делении, поскольку деление может вызвать бесконечное число десятичных знаков.

Рассмотрим следующий пример:

public class BigDecimalTest { 

    public static void main(final String[] args) { 
     final BigDecimal d1 = new BigDecimal("221500"); 
     final BigDecimal d2 = new BigDecimal("12"); 
     final BigDecimal result=d1.divide(d2,30,RoundingMode.HALF_EVEN); 
     System.out.println(result); 
    } 

} 

который дает

18458,333333333333333333333333333333

со всеми 30 знаков после запятой запрошенных. Вы можете изменить 30 до 300, что дает

18458,333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

Много лучше, чем калькулятор, не так ли? :)