Новый 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 не может быть представлен в точности как двойной.
Когда вы определяете двойную переменную любым способом, в большинстве случаев это будет не то значение, которое вы определили, а самое близкое двоичное представление. Вы передаете удвоитель конструктору, так что уже обеспечили эту небольшую неточность.