Почему 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» был (очень) плохим выбором слов. Я хотел знать, как это работает.

@ Ответ 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 m = new HashMap(); m.put(Double.NaN, "Hi mum"); if (m.get(Double.NaN) != null) { // this wont be executed. } 

Это не имеет большого смысла!

Другие аномалии существовали бы потому, что -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 ()) совершенно ясным.

Эта реализация позволяет определить действительное число как

  • Почему это вычитание не равно нулю?
  • Почему преобразование из float в double изменяет значение?
  • Эффективная реализация log2 (__ m256d) в AVX2
  • Double vs float на iPhone
  • самое большое целое число, которое может быть сохранено в двойном
  • Почему изменение 0.1f to 0 замедляет производительность на 10x?
  • Что означают F и D в конце числовых литералов?
  • Как вы печатаете EXACT значение числа с плавающей запятой?
  • Почему (360/24) / 60 = 0 ... в Java
  • Целочисленное деление всегда равно нулю
  • Float vs Decimal в ActiveRecord
  • Interesting Posts
    Давайте будем гением компьютера.