Java подписанный ноль и бокс

Недавно я написал проект на Java и заметил очень странную особенность с реализацией double/Double. Тип double в Java имеет два нуля, то есть 0.0 и -0.0 (нули со знаком). Странно то, что:

0.0 == -0.0

оценивается как true, но:

new Double(0.0).equals(new Double(-0.0))

оценивается как false. Кто-нибудь знает причину этого?


person uhz    schedule 08.02.2013    source источник
comment
Обычный способ избежать этого — добавить 0.0. Подробнее см. здесь.   -  person OldCurmudgeon    schedule 08.02.2013


Ответы (3)


Все это объясняется в javadoc:

Обратите внимание, что в большинстве случаев для двух экземпляров класса Double, d1 и d2, значение d1.equals(d2) истинно тогда и только тогда, когда

   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.

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


Теперь вы можете спросить, почему 0.0 == -0.0 верно. На самом деле они не являются строго идентичными. Например:

Double.doubleToRawLongBits(0.0) == Double.doubleToRawLongBits(-0.0); //false

является ложным. Однако JLS требует ("в соответствии с правилами стандарта IEEE 754"), чтобы:

Положительный нуль и отрицательный нуль считаются равными.

следовательно, 0.0 == -0.0 верно.

person assylias    schedule 08.02.2013
comment
И JLS требует этого, потому что этого требует IEEE 754. - person ninjalj; 09.02.2013
comment
@ninjalj Действительно - добавил это уточнение. - person assylias; 09.02.2013

Важно понимать использование нуля со знаком в классе Double. (Многие опытные Java-программисты этого не делают).

Короткий ответ заключается в том, что (по определению) "-0,0 меньше 0,0" во всех методах, предоставляемых классом Double (то есть equals(), compare(), compareTo() и т. д.)

Double позволяет всем числам с плавающей запятой быть «полностью упорядоченными в числовой строке». Примитивы ведут себя так, как пользователь будет думать о вещах (определение реального мира) ... 0d = -0d

Следующие фрагменты иллюстрируют поведение...

final double d1 = 0d, d2 = -0d;

System.out.println(d1 == d2); //prints ... true
System.out.println(d1 < d2);  //prints ... false
System.out.println(d2 < d1);  //prints ... false
System.out.println(Double.compare(d1, d2)); //prints ... 1
System.out.println(Double.compare(d2, d1)); //prints ... -1

Есть и другие сообщения, которые имеют отношение к делу и хорошо объясняют предысторию ...

1: Почему числа с плавающей запятой имеют нули со знаком?

2: Почему Java Double. compare(double, double) реализован так, как есть?

И слово предостережения...

Если вы не знаете, что в классе Double "-0,0 меньше 0,0", вы можете запутаться при использовании таких методов, как equals() и < strong>compare() и compareTo() из Double в логических тестах. Например, посмотрите на...

final double d3 = -0d; // try this code with d3 = 0d; for comparison

if (d3 < 0d) {     
    System.out.println("Pay 1 million pounds penalty");
} else {           
    System.out.println("Good things happen"); // this line prints
}


if (Double.compare(d3, 0d) < 0) { //use Double.compare(d3, -0d) to match the above behaviour
    System.out.println("Pay 1 million pounds penalty"); // this line prints
} else {                              
    System.out.println("Good things happen"); 
}

а для равных вы можете попробовать... new Double(d3).equals(0d) || новый двойной (d3) .равно (-0d)

person K John Smith    schedule 09.02.2013

Используя оператор ==, вы сравниваете значения. С равными вы сравниваете объекты.

person MiSu    schedule 08.02.2013