Подтвердить что ты не робот

Умножение двух чисел с помощью BigDecimal возвращает неверное значение

Выполнение следующего кода:

new BigDecimal(0.06 * 3).toString()

возвращает 0.179999999999999993338661852249060757458209991455078125 вместо 0.18.

Выполнение

new BigDecimal(0.06).multiply(new BigDecimal(3)).toString() 

возвращает тот же результат.

Как это возможно?

4b9b3361

Ответ 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