2015-04-14 3 views
4

Когда BigDecimal используется при вводе double и BigDecimal со входом String, похоже, что появляются разные результаты.новый BigDecimal (double) vs new 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, разве это не должно быть одинаково?

+0

имеют вид на а, б и в, г ... это уже другая;) посмотрим на http://stackoverflow.com/questions/12395281/convert- double-to-bigdecimal-and-set-bigdecimal-precision – pL4Gu33

+1

Это потому, что 'double' имеет ограниченную точность; Это IEEE 754 для вас. – fge

+1

вы можете исправить его, используя '.setScale (10, BigDecimal.ROUND_HALF_UP);' – SnakeDoc

ответ

10

Am I wrong in saying that this is because of double imprecision?

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

But since this is a BigDecimal , shouldn't it be the same?

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

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

6

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

Это подтверждается стандартом, который гласит, что floating point literals default to double unless otherwise specified.

+0

Это не плавающая точка _error_. Код с плавающей запятой ведет себя точно так, как он должен вести себя. Единственная проблема заключается в том, что разработчик программирует, как он будет себя вести. «Проблема» заключается в том, что '0.333333333' не представляет собой такое же рациональное число, которое представлено' new BigDecimal («0.333333333») '. Но это не ошибка, и она не может быть «исправлена», за исключением изменения спецификации языка Java, так что '0.333333333' больше не интерпретируется как двойной двоичный код IEEE. –

+0

@jameslarge Я знаю, как работают двоичные удвоения IEEE - неточность, возникающая в результате их использования, обычно называется «ошибкой». См., Например, [wikipedia] (http://en.wikipedia.org/wiki/Floating_point#Machine_precision_and_backward_error_analysis) или [документы Oracle] (http://docs.oracle.com/cd/E19957-01/806 -3568/ncg_goldberg.html).Это ошибка в смысле [статистической ошибки] (http://en.wikipedia.org/wiki/Errors_and_residuals_in_statistics), а не 'FileNotFoundError'. –

+0

О, ... правая ... _that_ ошибка. Наверное, в последнее время я немного озабочен недостатками программного обеспечения (пожалуйста, не спрашивайте меня почему), и я начинаю их видеть, даже если они не являются. –

0

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

4

Java-документы имеют свой ответ. В соответствии с Java Документов BigDecimal(double val)

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double.

+0

Хорошо, это имеет смысл. Благодаря! – dardeshna