Почему мы должны преобразовать double в строку, прежде чем мы сможем преобразовать его в BigDecimal? - PullRequest
5 голосов
/ 10 ноября 2011

Источник для round в Apache Commons выглядит следующим образом:

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new java.math.BigDecimal(Double.toString(x)).setScale(scale, roundingMethod)).doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}

Мне было интересно, когда при создании BigDecimal почему они решили преобразовать double в строку (используя Double.toString) вместо простого использования самого double?

Другими словами, что с этим не так? :

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new java.math.BigDecimal(x).setScale(scale, roundingMethod)).doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}

Ответы [ 5 ]

7 голосов
/ 10 ноября 2011

Это потому, что результат конструктора BigDecimal(double) непредсказуем, как упомянуто в javadoc.

Можно предположить, что написание нового BigDecimal (0.1) в Java создает BigDecimal, который точно равен 0,1 (немасштабированное значение 1, с шкала 1), но на самом деле она равна 0.1000000000000000055511151231257827021181583404541015625

Конструктор String, с другой стороны, совершенно предсказуем: при написании нового BigDecimal ("0.1") создается BigDecimal, который точно равен 0,1, как и следовало ожидать. Поэтому, как правило, Рекомендуется использовать конструктор String вместо этого один.

Контрольный пример:

System.out.println(java.math.BigDecimal.valueOf(0.1).toString());
System.out.println(new java.math.BigDecimal(0.1).toString());
4 голосов
/ 10 ноября 2011

Из документации здесь для конструктора BigDecimal(String val):

Примечание: для значений, отличных от float и double NaN и ± Infinity, этот конструктор совместим со значениямивозвращается Float.toString (float) и Double.toString (double).Как правило, это предпочтительный способ преобразования числа с плавающей запятой или двойного в BigDecimal, поскольку он не страдает от непредсказуемости конструктора BigDecimal (double).

1 голос
/ 10 ноября 2011

Однако я нашел один вопрос:

System.out.println(java.math.BigDecimal.valueOf(0.1000000000000000055511151231257827021181583404541015625).toString());

Будет напечатано 0.1 .

Я думаю, что ключ java.lang.Double.toString (double d) . Когда мы вводим 0.1 (в Java точное значение равно 0.1000000000000000055511151231257827021181583404541015625 ), функция сбросит хвост, и мы получим 0.1 . Тем не мение. если мы введем 0.1000000000000000055511151231257827021181583404541015625 , это всегда опускает хвост, и мы также получаем 0.1 , что не соответствует нашим ожиданиям.

Таким образом, мы должны знать о нашем требовании выбрать java.math.BigDecimal.valueOf (double val) или java.math.BigDecimal.BigDecimal (double val) .

1 голос
/ 10 ноября 2011

Мне кажется, что ключ в этом утверждении:

BigDecimal (double val)Переводит double в BigDecimal, который является точным десятичным представлением двоичного значения с плавающей точкой в ​​двоичном коде.

против

BigDecimal (String val)Переводит строковое представление BigDecimal в BigDecimal.

Переходя сначала к String, вы просто видите двойное как BigDecimal, но если конструировать непосредственно из двойного, вы работаете с битомЯ хочу поспорить, что вы получите немного другой ответ.Помните, что значения с плавающей точкой представлены с использованием 64-битных секций для всей части, а также для дробной части и секции для представления показателя степени (в базе 2) - все это очень эзотерически, отличаетсяот машины к машине, и я думаю, что единственное формальное определение можно найти в проклятом Necronomicon .

Обновление: что сказал Бородин .

1 голос
/ 10 ноября 2011

Вам не нужно преобразовывать в строку.
Используйте статический метод BigDecimal.valueOf(double val):

Для использования в своем коде:

...
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue();
....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...