Почему NaN не равно NaN?
Почему если проверить, равно ли NaN самому себе, возвратится false? Например:
console.log(NaN == NaN); // Выведет false
Ответы (3 шт):
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/NaN
NaN является неравным (посредством сравнения через ==, !=, ===, and !==) любому другому значению, включая другое значение NaN. Используйте Number.isNaN() или isNaN(), чтобы наиболее понятным образом определить является ли значение значением NaN. Или выполните само-сравнение: NaN, и только NaN, в результате такого сравнения будет неравным самому себе.
NaN === NaN; // false
Number.NaN === NaN; // false
isNaN(NaN); // true
isNaN(Number.NaN); // true
function valueIsNaN(v) {
return v !== v;
}
valueIsNaN(1); // false
valueIsNaN(NaN); // true
valueIsNaN(Number.NaN); // true
NaN – Not-a-Number, нечисло. Это значение типа Number, которое указывает что вычислить значение не удалось, нельзя придать результату никакое осмысленное значение. Понятие NaN пришло в JavaScript из стандарта IEEE 754, который JavaScript использует для вычислений.
Это всё про порядок на числах:
2/3 – конечное значение, известно где его искать, как сравнивать с другими числами.
2/0 – бесконечное значение равное +∞. В рамках классической арифметики так делать нельзя. Но машинную арифметику оказалось полезно дополнить бесконечностями. +∞ – такое число, которое больше любого другого числа. На числовой прямой оно где-то очень далеко справа.
0/0 – этому выражению нельзя придать значение. Если в предыдущем случае классическая арифметика была расширена, и это было полезно, тут так не выйдет. Какое бы значение мы не приписали этому выражению, можно привести пример, когда это будет плохо. Нельзя сказать где на числовой прямой находится результат деления нуля на ноль. Раз нельзя приписать значение, приписываем NaN – значение про которое мы не знаем где оно на числовой прямой.
Так как мы не знаем где NaN, то для сравнений с ним приняты специальные правила. Сравнение NaN c любым другим числом x, включая бесконечности и сам NaN:
| сравнение | NaN ≥ x | NaN ≤ x | NaN > x | NaN < x | NaN = x | NaN ≠ x |
|---|---|---|---|---|---|---|
| результат | ложь | ложь | ложь | ложь | ложь | истина |
Повторю ещё раз логику: если мы не знаем где NaN на числовой прямой, то мы не можем утверждать, что NaN больше x, например. Раз не можем утверждать, логично сказать что утверждение ложно.
Всё это верно и когда x хранит значение NaN. В итоге имеем NaN ≠ NaN, потому что у нас есть два значения неизвестно где на прямой, значит мы не можем сказать что они равны. Мы не знаем, значит вынуждены сказать что они не равны.
Это имеет кучу нехороших последствий:
нельзя рефакторить код:
if (x < y) less else greater;и
if (x >= y) greater else less;
вычисляются одинаково если x и y числа, но по разному, если одно из них NaN.нельзя сортировать массивы с NaN. Сортировка может вернуть любую чепуху, даже если у вас в массиве только одно значение NaN на миллион нормальных чисел.
если у вас три условия, то NaN проскочит их все. Полная неожиданность:
if (x < 0)
...
else if (x > 0)
...
else if (x == 0)
...
else
<сюда может попасть только NaN>
Но есть хорошие новости.
Если в середине сложных вычислений получилась чепуха, вы об этом узнаете: NaN в любой арифметике и вызовах математических функций порождает NaN (почти везде, смотрите замечание ниже). Откровенную чушь показать пользователю не получится.
NB Если в вычислениях значение одного аргумента не влияет на результат, то NaN может исчезнуть и это логично. Например: NaN0 → 1, Math.hypot(+∞, NaN) → +∞.Грамотно организуя сравнения, можно управлять, в какую ветку попадёт NaN без написания специального кода обработки ошибок.
В JavaScript результат сравнения NaN === NaN и NaN == NaN всегда false, потому что NaN (Not-a-Number) представляет неопределенное или некорректное число, и Как правильно заметили предыдущие авторы стандарт IEEE 754 гласит, что два NaN никогда не равны друг другу.
Чутка дополню что JS не одинок в этом. Примеры в других языках программирования:
Язык Код Результат
JavaScript console.log(NaN === NaN); false
Python print(float('nan') == float('nan')) False
Java System.out.println(Float.NaN == Float.NaN); false
C# Console.WriteLine(float.NaN == float.NaN); false
Go fmt.Println(math.NaN() == math.NaN()) false
Как правильно проверять NaN? Поскольку прямое сравнение NaN с NaN всегда дает false, используется специальная функция:
JavaScript: isNaN(value) или Number.isNaN(value)
Python: math.isnan(value)
Java: Float.isNaN(value)
C#: float.IsNaN(value)
Go: math.IsNaN(value)
Таким образом, если нужно проверить, является ли значение NaN, лучше использовать соответствующие встроенные функции.
Ну и в придачу NULL в SQL работает похоже на NaN в других языках, так как не равен самому себе.