Почему операции со значениями двойной точности не дают ожидаемых результатов? - PullRequest
4 голосов
/ 08 октября 2010
    System.out.println(2.14656);

2.14656

    System.out.println(2.14656%2);

0.14656000000000002

WTF?

Ответы [ 3 ]

13 голосов
/ 08 октября 2010

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

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

2.14656000000000002359001882723532617092132568359375

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

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

0.14656000000000002359001882723532617092132568359375

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

3 голосов
/ 08 октября 2010

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

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

Float и double значения были созданы для быстрых операций в CPU. Математика между несколькими числами может быть быстро сделана, даже если вы делите 1.42E-13 на 2.11E47. Они не были построены для обеспечения «круглых» чисел в базе-10. Это побочный эффект этого решения.

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

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

0 голосов
/ 08 октября 2010
...