Почему операции над значениями двойной точности не дают ожидаемых результатов?

    System.out.println(2.14656);

2.14656

    System.out.println(2.14656%2);

0.14656000000000002

ВТФ?


person user293756    schedule 08.10.2010    source источник
comment
Арифметика с плавающей запятой снова поражает! Что должен знать каждый программист об арифметике с плавающей запятой   -  person Adam Paynter    schedule 08.10.2010


Ответы (3)


Дают ожидаемые результаты. Ваши ожидания неверны.

Когда вы вводите литерал двойной точности 2.14656, вы фактически получаете ближайшее значение двойной точности, а именно:

2.14656000000000002359001882723532617092132568359375

println округляет это значение при выводе (до 17 значащих цифр), поэтому вы видите ожидаемое значение.

После операции модуля (что является точным) значение равно:

0.14656000000000002359001882723532617092132568359375

Опять же, это округляется при печати, но поскольку на одну первую цифру меньше, точка округления находится на одну цифру дальше вправо, и поэтому вы видите этот замыкающий 2.

person Stephen Canon    schedule 08.10.2010
comment
Дают ожидаемые результаты. Ваши ожидания неверны. Должен находиться в Зале славы кавычек с плавающей запятой! +1 - person Olof Forshell; 02.03.2011

Система с основанием 2 используется для хранения числа с основанием 10 произвольной точности.

При использовании целочисленного двоичного числа «круглые» числа — это 2, 4, 8, 16, 32, 64 и т. д. Вы заметите, что ни одно из них не является 10, 100, 1000, 10000 или чем-то еще, что можно было бы считать « круглое" число в базе-10.

Значения с плавающей запятой и двойные значения были созданы для быстрых операций внутри ЦП. Вычислить между несколькими числами можно быстро, даже если вы делите 1,42E-13 на 2,11E47. Они не были созданы для получения «круглых» чисел по основанию 10. Это побочный эффект этого решения.

При использовании чисел с плавающей запятой вы должны признать, что это произойдет. Это не 100% точность, но в остальном она верна. Поэтому вам никогда не следует использовать переменные с плавающей запятой там, где вам нужна 100% точность. Там, где вам нужно это сделать, найдите способ сохранить его в значении int. Это также хорошая идея, когда вы используете число с плавающей запятой, чтобы округлить вывод до числа десятичных знаков, чтобы избежать случайного отображения, как у вас там.

Например, я работаю в финансовой сфере, и мы представляем рыночные цены в виде количества тиков, а не фактической цены. Когда нам нужно отобразить цену, мы умножаем это значение на размер тика, 1/100, 1/32 или 1/20 и т. д., а затем округляем до соответствующего количества знаков после запятой. Количество тиков, числитель и знаменатель размера тика хранятся в наших базах данных как целые числа. На самом деле мы не храним значения с плавающей запятой ни для чего, кроме вычисляемых значений, таких как скользящие средние.

person Erick Robertson    schedule 08.10.2010