Почему Java Double.compare (double, double) реализован таким, какой он есть? - PullRequest
34 голосов
/ 13 ноября 2009

Я смотрел на реализацию сравни (двойной, двойной) в стандартной библиотеке Java (6). Читается:

public static int compare(double d1, double d2) {
    if (d1 < d2)
        return -1;       // Neither val is NaN, thisVal is smaller
    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: "Достоинства" - это (очень) плохой выбор слов. Я хотел знать, как это работает.

Ответы [ 4 ]

43 голосов
/ 13 ноября 2009

Объяснение в комментариях к коду. В Java есть двойные значения как 0.0 и -0.0, так и "не число" (NaN). Вы не можете использовать простой оператор == для этих значений. Взгляните на источник doubleToLongBits() и на Javadoc для метода Double.equals() :

Обратите внимание, что в большинстве случаев на двоих экземпляры класса 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.

Это определение позволяет хэш-таблицам работать правильно.

40 голосов
/ 13 ноября 2009

@ Ответ Шовера верен (читай!), Но здесь есть кое-что еще.

Как Javadoc для Double::equals состояния:

"Это определение позволяет хэш-таблицам работать правильно."

Предположим, что разработчики Java решили реализовать equals(...) и compare(...) с той же семантикой, что и == в обернутых double экземплярах. Это будет означать, что equals() всегда будет возвращать false для завернутого NaN. Теперь подумайте, что произойдет, если вы попытаетесь использовать завернутый NaN в карте или коллекции.

List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
    // this wont be executed.
}

Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
    // this wont be executed.
}

Не имеет большого смысла, не так ли!

Другие аномалии могут существовать, потому что -0.0 и +0.0 имеют разные битовые комбинации, но равны согласно ==.

Таким образом, разработчики Java решили (справедливо IMO) более сложное (но более интуитивное) определение для этих методов Double, которое мы имеем сегодня.

2 голосов
/ 13 ноября 2009

Заслуга в том, что это самый простой код, который соответствует спецификации.

Одной из общих характеристик программистов-новичков является завышение чтения исходного кода и занижение чтения спецификации . В этом случае спецификация:

http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29

... делает поведение и причину поведения (соответствие равно ()) совершенно ясными.

0 голосов
/ 13 ноября 2009

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

...