Groovy - путаница double vs float

Я использую два следующих утверждения: -

double foo = 20.00
float bar = 20.00
println foo == bar

А также

double foo = 20.01
float bar = 20.01
println foo == bar

Он дает результат как: -

true 
false

Может ли кто-нибудь знать, в чем разница между этими двумя утверждениями?


person Saurabh Gaur    schedule 10.09.2016    source источник
comment
Разрешает ли мой ответ ваши сомнения? Или еще что-то не понятно? :)   -  person Jose Ignacio Acin Pozo    schedule 10.09.2016
comment
@JoseIgnacioAcinPozo Нет, ваш ответ хорош и очень полезен, я просто жду других комментариев. Спасибо   -  person Saurabh Gaur    schedule 10.09.2016


Ответы (3)


Часть 0,1 числа 20.01 бесконечно повторяется в двоичном формате; 20.01 =

10100.00000010100011110101110000101000111101011100001010001111010111...

числа с плавающей запятой округляются (до ближайшего значения) до 24 значащих битов; двойные округляются до 53. Таким образом, число с плавающей запятой

10100.0000001010001111011

и двойной

10100.000000101000111101011100001010001111010111000011

В десятичном виде это

20.0100002288818359375 и

20.010000000000001563194018672220408916473388671875 соответственно.

(Вы могли убедиться в этом напрямую, используя мой преобразователь десятичных чисел в числа с плавающей запятой.)

person Rick Regan    schedule 10.09.2016
comment
Этот ответ добавляет дополнительную информацию о различиях низкого уровня между 20.01, представленными float и double, но не дает прямого ответа на вопрос о том, почему 20.00 дает результат true, а 20.01 дает результат false. - person Jose Ignacio Acin Pozo; 15.09.2016
comment
@JoseIgnacioAcinPozo 20 является целым числом, поэтому он представлен точно в любом формате. 20.01 - это значение с плавающей запятой, которое различается в зависимости от того, является ли оно числом с плавающей запятой или двойным. (Вы также не упоминаете об этом явно в своем ответе.) - person Rick Regan; 15.09.2016
comment
Без обид! Я только указывал на настоящую цель вопроса, вы всегда можете отредактировать свой ответ. Мой ответ гласит: остальные представления всегда будут немного отличаться, с небольшими различиями между двойными и плавающими. Я думаю, что это предложение достаточно явное о том, что будет разница в значениях между числами с плавающей запятой и числами типа double. Особенно учитывая тот факт, что один представлен 32-битным, а другой 64-битным. - person Jose Ignacio Acin Pozo; 15.09.2016

Значения double и float не имеют точного внутреннего представления для каждого значения. Единственными десятичными значениями, которые могут быть представлены как двоичные числа с плавающей запятой IEEE-754 для двух десятичных запятых, являются 0, 0,25, 0,5, 0,75 и 1. Остальные представления всегда будут немного отличаться, с небольшими различиями между числами типа double и float, создающими это неравенство в поведении.

Это справедливо не только для Groovy, но и для Java.

Например:

double foo = 20.25
float bar = 20.25
println foo == bar

Выход:

правда

person Jose Ignacio Acin Pozo    schedule 10.09.2016

Groovy Float не хранится точно в памяти. Это основная причина ваших различий.

В Groovy определение точности по количеству цифр после правой части точки может быть достигнуто с помощью следующей сигнатуры метода:

public float trunc (int precision)
precision - количество сохраняемых десятичных знаков.

Дополнительные сведения см. В документации по классам Float .

При использовании языка Groovy более предпочтительно использовать класс BigDecimal в качестве плавающего числа. Преобразование из Number в String намного проще, и есть возможность определить точность плавающего числа ** в конструкторе.

BigDecimal (BigInteger unscaledVal, int scale) преобразует немасштабированное значение BigInteger и масштаб int в BigDecimal.

Дополнительную информацию можно найти в документации Java BigDecimal . Поскольку язык Groovy основан на языке Java. Более того, BigDecimal будет представлять точное значение числа.

person Rotem    schedule 10.09.2016