Новый BigDecimal(double) против нового BigDecimal(String)

Когда BigDecimal используется с вводом double а также BigDecimal с вводом String разные результаты, кажется, появляются.

BigDecimal a = new BigDecimal(0.333333333);
BigDecimal b = new BigDecimal(0.666666666);

BigDecimal c = new BigDecimal("0.333333333");
BigDecimal d = new BigDecimal("0.666666666");

BigDecimal x = a.multiply(b);
BigDecimal y = c.multiply(d);

System.out.println(x);
System.out.println(y);

х выводит как

0.222222221777777790569747304508155316795087227497352441864147715340493949298661391367204487323760986328125

пока у

0.222222221777777778

Я ошибаюсь, говоря, что это из-за двойной неточности? Но так как это BigDecimalне должно ли быть так же?

4 ответа

Решение

Я ошибаюсь, говоря, что это из-за двойной неточности?

Вы абсолютно правы, это именно из-за doubleнеточность.

Но так как это BigDecimalне должно ли быть так же?

Нет, не должно. Ошибка вводится в момент создания new BigDecimal(0.333333333), так как 0.333333333 в константу уже встроена ошибка. В этот момент вы ничего не можете сделать, чтобы исправить эту ошибку: к тому времени пресловутая лошадь уже вышла из сарая, поэтому уже слишком поздно закрывать двери.

Когда вы передаете Stringс другой стороны, десятичное представление точно соответствует строке, поэтому вы получите другой результат.

Да, это ошибка с плавающей точкой. Проблема в том, что литералы 0.333333333 а также 0.666666666 представлены как двойные числа перед передачей в качестве аргумента BigDecimal --- в частности, BigDecimal конструктор занимает double в качестве аргумента.

Это поддерживается стандартом, который говорит, что литералы с плавающей точкой по умолчанию double если не указано иное.

У Java-документации есть свой ответ. Согласно Java документам BigDecimal(двойной вал)

Результаты этого конструктора могут быть несколько непредсказуемыми. Можно предположить, что при написании нового BigDecimal(0.1) в Java создается BigDecimal, который в точности равен 0,1 (немасштабированное значение 1 со шкалой 1), но фактически равен 0,1000000000000000055511151231257827021181583404541015625. Это потому, что 0,1 не может быть представлен в точности как двойной.

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

Другие вопросы по тегам