Почему Double.NaN равняется себе, когда оборачивается в экземпляр Double? - PullRequest
10 голосов
/ 11 сентября 2009

Из этот вопрос Я узнал, что Double.NaN не равен самому себе.

Я проверял это для себя и заметил, что это не тот случай, когда вы оборачиваете Double.NaN в экземпляр Double. Например:

public class DoubleNaNTest {
    public static void main(String[] args) {
        double primitive = Double.NaN;
        Double object = new Double(primitive);

        // test 1 - is the primitive is equal to itself?
        boolean test1 = primitive == primitive;

        // test 2 - is the object equal to itself?
        boolean test2 = object.equals(object);

        // test 3 - is the double value of the object equal to itself?
        boolean test3 = object.doubleValue() == object.doubleValue();

        System.out.println("Test 1 = " + test1);
        System.out.println("Test 2 = " + test2);
        System.out.println("Test 3 = " + test3);
    }
}

Выходы:

Test 1 = false
Test 2 = true
Test 3 = false

Мне кажется, что все три теста должны быть оценены как ложные, поскольку все три операции эквивалентны (как если бы вы использовали что-то другое, чем Double.NaN).

Может ли кто-нибудь объяснить, что здесь происходит?

Ответы [ 3 ]

11 голосов
/ 11 сентября 2009

То, что происходит, заключается в том, что метод equals преднамеренно отклоняется от плавающей запятой IEE. Цитирование из Javadoc для equals(Object) метода java.lang.Double .

Однако есть два исключения:

  • Если d1 и d2 оба представляют Double.NaN, то метод equals возвращает истину, хотя Double.NaN == Double.NaN имеет значение ложь.
  • Если d1 представляет +0.0, в то время как d2 представляет -0.0, или наоборот,
    равный тест имеет значение false, даже
    хотя +0.0 == - 0.0 имеет значение true.

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

В результате, если вам нужна 100% -ная совместимость с плавающей точкой IEE, вам нужно явно распаковать экземпляры java.lang.Double и сравнить полученные значения double.

5 голосов
/ 11 сентября 2009

Это так, хэш-таблицы работают правильно

Они преднамеренно отклоняются от способа IEEE, поэтому хэш-таблицы будут работать.

Вы можете получить часть истории в api docs . Остальная часть истории такова: каждый класс, унаследованный от Object, то есть все они, имеет контракт для поддержки инвариантов Object. Контракт существует для того, чтобы остальная часть библиотеки могла реализовать все эти прекрасные коллекции и тому подобное. Ничто на самом деле не мешает вам повредить это, но тогда вы не можете быть уверены, что вещи, которые принимают Объект, будут работать.

0 голосов
/ 27 августа 2012

Если у одного есть два неизменных объекта, которые определяют Equals для возврата true, когда каждое поле в одном объекте сообщает Equal соответствующему полю в другом, и если ни один из кода, который использует объекты, не заботится о равенстве ссылок , тогда должна быть возможность заменить все ссылки на один объект ссылками на другой. Если объекты создаются, например, парсинг данных, считанных с диска, и если многие объекты будут сравниваться, замена множества различных экземпляров ссылками на один экземпляр может значительно повысить производительность. Обратите внимание, что правильность такой замены не зависит от того, являются ли объекты мелкими или глубокими неизменяемыми, при условии, что любые изменяемые объекты, вложенные в них, будут сообщать о себе как о неравных чему-либо, кроме самих себя.

Для правильной работы такой логики важно, чтобы рассматриваемые объекты были полностью эквивалентны. Каждый объект должен быть равен самому себе, поэтому Double.NaN должно равняться Double.NaN. Требование полной эквивалентности подразумевает, что положительный ноль не должен сообщать о себе равным отрицательному нулю (поскольку, если это так, объект, содержащий положительный ноль, может вести себя иначе, чем объект, содержащий отрицательный ноль).

Обратите внимание, что это область, в которой .net отличается от Java (некоторые неэквивалентные значения с плавающей точкой и Decimal являются отчетными Equals); Во многих отношениях я считаю, что .net лучше, но эта деталь - та, в которой .net ошибся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...