Проверьте два значения float/double для точного равенства

Что такое элегантный, читаемый и невербальный способ сравнения двух значений с плавающей запятой для точного равенства?

Проще, как это может показаться, его злая проблема. Оператор == не выполняет работу над NaN и также имеет специальное лечение для нуля:

(+0.0 == -0.0) -> true
Double.NaN == Double.NaN -> false

Но я хочу определить, являются ли два значения одинаковыми (но мне не нужны разные шаблоны NaN, поэтому любой NaN == любой другой NaN → true).

Я могу сделать это с этой уродливой частью кода монстра:

Double.doubleToLongBits(a) == Double.doubleToLongBits(b)

Есть ли лучший способ написать это (и сделать очевидным намерение)?

Ответы

Ответ 1

То, что у вас есть, - это лучший способ сделать это, я бы сказал. Это дает понять, что вас интересует поразрядное представление значения. Вы преобразовываете эти биты в long как удобный 64-битный тип, который не имеет каких-либо фанковых действий.

Если вы не хотите, чтобы он часто появлялся в вашей кодовой базе, просто добавьте метод для его переноса:

public static boolean bitwiseEqualsWithCanonicalNaN(double x, double y) {
    return Double.doubleToLongBits(x) == Double.doubleToLongBits(y);
}

Обратите внимание, что в соответствии с вашим вопросом это не отличает разные значения NaN. Если вы хотите сделать это позже, вам нужно будет использовать Double.toRawLongBits.

Ответ 2

Вы можете использовать

Double.compare(a, b) == 0

Из javadoc для compareTo

  • Double.NaN считается этим методом равным себе и больше всех других двойных значений (включая Double.POSITIVE_INFINITY).
  • 0.0d считается этим методом больше -0.0d.