Умножение двух чисел с помощью BigDecimal возвращает неверное значение
Выполнение следующего кода:
new BigDecimal(0.06 * 3).toString()
возвращает 0.179999999999999993338661852249060757458209991455078125
вместо 0.18
.
Выполнение
new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()
возвращает тот же результат.
Как это возможно?
Ответы
Ответ 1
Вы не умножаете два числа, используя BigDecimal
. Вы умножаете их с помощью арифметики double
и передаете результат конструктору BigDecimal
.
Вы хотите:
new BigDecimal("0.06").multiply(new BigDecimal("3")).toString()
Обратите внимание, что вам нужны значения в строках - в противном случае вы используете значение double
для 0.06, что не совсем точно 0,06... вы потеряли информацию перед запуском. (Вам действительно не нужна строковая форма из 3, но я сделал это для согласованности.)
Например:
System.out.println(new BigDecimal(0.06));
печатает
0.059999999999999997779553950749686919152736663818359375
Ответ 2
Как пишет Джон Скит, причина, по которой вы получаете 0.179999999999999993338661852249060757458209991455078125
вместо 0.18
, состоит в том, что 0.06 * 3
вычисляется как IEEE 754 double
, а затем значение double
преобразуется в значение BigDecimal
.
Несмотря на то, что 0.06
выглядит достаточно простым в исходном коде, число 0.06 не является точно представимым как IEEE 754 double
, поэтому фактически 0.06
представляет собой приближение 0,06, равное 0,05999999999999999997779553950749686919152736663818359375. Число 0.06 в десятичной нотации не является точно представимым, потому что число равно 0b0.0 00011110101110000101 в двоичной нотации (где жирный представляет повторяющуюся последовательность цифр). Компьютер должен обрезать эту бесконечную последовательность двоичных цифр, что приведет к приближению 0.0599999...
Как я подробно рассказал в моем ответе на вопрос о IEEE 754, 64 бита double?, вы можете использовать ARIBAS 'decode_float()
для определения мантиссы и показателя числа с плавающей запятой:
==> set_floatprec(double_float).
-: 64
==> set_printbase(2).
-: 0y10
==> decode_float(0.06).
-: (0y11110101_11000010_10001111_01011100_00101000_11110101_11000010_10001111,
-0y1000100)
==> set_printbase(10).
-: 10
==> -0y1000100.
-: -68
==> set_floatprec(128).
-: 128
==> 1/2**4 + 1/2**5 + 1/2**6 + 1/2**7 + 1/2**9 + 1/2**11 + 1/2**12 + 1/2**13 + 1/2**18 + 1/2**20.
-: 0.11999_98855_59082_03125_00000_00000_00000_00
(**
является экспоненциальным в ARIBAS).
И мы имеем 0.06 = Σ я = 0..∞ 0.11999988555908203125/ 2 1 + 20 × i
Вы можете оценить эту серию в системе компьютерной алгебры, такой как Maxima:
(%i1) sum ( 0.11999988555908203125 / 2 ^ (1 + 20 * i), i, 0, inf ), simpsum;
(%o1) 0.06
http://maxima-online.org/?inc=r760264757
Ответ 3
Лучше работать с BigDecimal#valueOf
:
BigDecimal.valueOf(0.06).multiply(BigDecimal.valueOf(3))
выводит правильный результат 0.18