Почему Java Double.compare (double, double) реализован так, как есть?
Я рассматривал реализацию сравнения (double, double) в стандартной библиотеке Java (6). В нем говорится:
public static int compare(double d1, double d2) { if (d1 d2) return 1; // Neither val is NaN, thisVal is larger long thisBits = Double.doubleToLongBits(d1); long anotherBits = Double.doubleToLongBits(d2); return (thisBits == anotherBits ? 0 : // Values are equal (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN) 1)); // (0.0, -0.0) or (NaN, !NaN) }
Каковы достоинства этой реализации?
edit: «Merits» был (очень) плохим выбором слов. Я хотел знать, как это работает.
- Деление с плавающей запятой против умножения с плавающей запятой
- Манипулирование и сравнение плавающих точек в java
- Преобразовать float в строку с заданной точностью и количеством десятичных цифр?
- Эмуляция «double» с использованием 2 "float" s
- Почему я не могу использовать значение float в качестве параметра шаблона?
- Преобразование String для плавания в Apple Swift
- Преобразование с двойным преобразованием без научной нотации
- Что на самом деле делает fcc-math gcc?
- Как отобразить двоичное представление float или double?
- Вставить в int vs floor
- Проблемы с двойной суммой Java
- почему f помещается после значений float?
- Как преобразовать целое число в float в Java?
@ Ответ Shoover правильный, но есть немного больше, чем это.
Поскольку javadoc для Double::equals
состояний:
«Это определение позволяет hash-таблицам работать правильно».
Предположим, что разработчики Java решили реализовать equals(...)
и compare(...)
с той же семантикой, что и ==
на обернутых double
экземплярах. Это означало бы, что equals()
всегда будет возвращать false
для упакованного NaN. Теперь рассмотрим, что произойдет, если вы попытаетесь использовать завернутый NaN в Map или Collection.
List l = new ArrayList (); l.add(Double.NaN); if (l.contains(Double.NaN)) { // this wont be executed. } Map
Это не имеет большого смысла!
Другие аномалии существовали бы потому, что -0.0
и +0.0
имеют разные битовые шаблоны, но равны в соответствии с ==
.
Поэтому разработчики Java решили (справедливо ИМО) более сложное (но более интуитивное) определение этих двойных методов, которые мы имеем сегодня.
Объяснение содержится в комментариях в коде. Java имеет двойные значения для 0.0
и -0.0
, а также «не число» ( NaN
). Вы не можете использовать оператор simple ==
для этих значений. doubleToLongBits()
источник doubleToLongBits()
и в Javadoc для Double.equals()
:
Обратите внимание, что в большинстве случаев для двух экземпляров classа
Double
,d1
иd2
значениеd1.equals(d2)
true
тогда и только тогда, когдаd1.doubleValue() == d2.doubleValue()
также имеет значение
true
. Однако есть два исключения:
- Если
d1
иd2
оба представляютDouble.NaN
, то метод equals возвращаетtrue
, хотяDouble.NaN == Double.NaN
имеет значениеfalse
.- Если
d1
представляет+0.0
тогда какd2
представляет-0.0
, или наоборот, равный тест имеет значениеfalse
, хотя значение+0.0 == -0.0
имеет значениеtrue
.Это определение позволяет hash-таблицам работать правильно.
Достоинством является то, что это самый простой код, который выполняет спецификацию.
Одной из характерных черт новичков-программистов является переоценка исходного кода чтения и недооцененных значений чтения. В этом случае спецификация:
http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29
… делает поведение и причину поведения (согласованность с equals ()) совершенно ясным.
Эта реализация позволяет определить действительное число как