Почему NaN не равно NaN? [Дубликат]

На этот вопрос уже есть ответ:

Каково обоснование для всех сравнений, возвращающих false для значений NaN IEEE75 13 ответов

Соответствующий стандарт IEEE определяет числовую константу NaN (не число) и предписывает, чтобы NaN сравнивалось как не равное себе. Почему это

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

тандарты @IEEE хорошо продуманы, поэтому я уверен, что есть веская причина, по которой сравнение NaN как равного себе было бы плохим. Я просто не могу понять, что это такое.

 Jim Balter08 апр. 2014 г., 09:20
Стандарты IEEE были разработаны инженерами, а не программистами, поставщиками компьютеров или авторами математических библиотек, для которых правило NaN является катастрофой.

Ответы на вопрос(6)

log(-1) даетNaN, а такжеacos(2) также даетNaN. Означает ли это, чтоlog(-1) == acos(2)? Очевидно, нет. Следовательно, вполне логично, чтоNaN не равен самому себе.

Возвращаясь к этому почти два года спустя, вот «NaN-безопасная» функция сравнения:

function compare(a,b) {
    return a == b || (isNaN(a) && isNaN(b));
}
 max05 апр. 2012 г., 22:04
Учитывая, что Inf == Inf, и учитывая, что можно так же легко утверждать, что объект должен быть равен самому себе, я подозреваю, что за выбором IEEE было какое-то другое, очень конкретное и очень сильное обоснование ...
 mmitchell15 мая 2014 г., 00:45
Ваша NaN-безопасная функция сравнения возвращает true, если вы указали два разных числа, которые не равны друг другу. Что-то вроде возврата a == b || (isNaN (a) && isNaN (b)) должно работать?
 Niet the Dark Absol05 апр. 2012 г., 21:05
Ну, если вы искали пересечение междуlog функция иacos функция, тогда все отрицательные значения после-1 будет рассматриваться как пересечение. Интересно,Infinity == Infinity верно, несмотря на то, что этого нельзя сказать в реальной математике.
 borisdiakur20 июл. 2012 г., 23:33
1 + 3 = 4 а также2 + 2 = 4. Означает ли это, что1 + 3 = 2 + 2? Ясно да. Следовательно, ваш ответ не имеет смысла.
 Tim Goodman28 июн. 2013 г., 18:39
Ноlog(-1) != log(-1) не имеет смысла. Так что ниNaN равноNaN ниNaN не равноNaN имеет смысл во всех случаях. Возможно, это будет иметь больше смысла, еслиNaN == NaN оценивается как нечто неизвестное, но затем== не вернет логическое значение.

Принятый ответ на 100% без вопросов НЕПРАВИЛЬНО. Не наполовину неправильно или даже слегка неправильно. Я боюсь, что эта проблема может запутать и ввести в заблуждение программистов на долгое время, когда этот вопрос всплывает в поисках.

NaN предназначен для распространения по всем вычислениям, заражая их, как вирус, поэтому, если где-то в ваших глубоких и сложных вычислениях вы натолкнетесь на NaN, вы не получите, казалось бы, разумного ответа. В противном случае по тождеству NaN / NaN должен равняться 1 вместе со всеми другими последствиями, такими как (NaN / NaN) == 1, (NaN * 1) == NaN и т. Д. Если вы предполагаете, что ваши вычисления где-то пошли не так (округление привело к нулевой знаменатель, приводящий к NaN) и т. д., тогда вы можете получить совершенно неверные (или, что еще хуже: слегка неверные) результаты ваших расчетов без очевидного указания, почему.

Существуют также веские причины для расчета NaN при вычислении значения математической функции; Одним из примеров, приведенных в связанном документе, является поиск нулей () функции f (). Вполне возможно, что в процессе исследования функции со значениями угадывания вы будете исследовать функцию, в которой функция f () не дает ощутимого результата. Это позволяет нулям () видеть NaN и продолжать свою работу.

Альтернативой NaN является инициирование исключения, как только встречается недопустимая операция (также называемая сигналом или ловушкой). Помимо огромных потерь производительности, с которыми вы могли столкнуться, в то время не было никакой гарантии, что процессоры будут поддерживать его аппаратно или ОС / язык будет поддерживать его программно; у каждого была своя уникальная снежинка при работе с плавающей точкой.IEEE решил явно обработать его в программном обеспечении как значения NaN, чтобы оно было переносимым на любую ОС или язык программирования. Правильные алгоритмы с плавающей запятой, как правило, корректны во всех реализациях с плавающей запято будь то node.js или COBOL (хах).

В теории вам не нужно устанавливать конкретные директивы #pragma, устанавливать сумасшедшие флаги компилятора, перехватывать правильные исключения или устанавливать специальные обработчики сигналов, чтобы заставить то, что кажется идентичным алгоритму, действительно работать правильно. К сожалению, некоторые разработчики языка и авторы компиляторов были действительно заняты тем, чтобы максимально использовать эту функцию.

Пожалуйста, ознакомьтесь с информацией об истории IEEE 754 с плавающей запятой. Также этот ответ на аналогичный вопрос, где член комитета ответил: Каково обоснование для всех сравнений, возвращающих false для значений NaN IEEE75

"Интервью со стариком с плавающей точкой"

"История формата с плавающей точкой IEEE"

Что каждый ученый должен знать об арифметике с плавающей точкой

 Sven Marnach10 февр. 2016 г., 17:12
@ xenadu Я вижу, что log (-1) == acos (2) предоставляет некоторые аргументы в пользу текущего поведения. Тем не менее, вы заметили, что вам не следует сравнивать числа с плавающей точкой на равенство, так что это довольно слабый аргумент (и есть много причин для выбора другого пути). Однако это не было темой моего предыдущего комментария. Моя точка зрения состояла в том, что приведенный выше ответ, хотя и является правильным, не дает никаких причин, по которым NaN не должен сравниваться с самим собой. Все, о чем вы говорите, никак не связано с этим вопросом.
 max17 мая 2014 г., 13:03
Мне также нравится, когда NaN распространяется "как вирус". К сожалению, это не так. В тот момент, когда вы сравниваете, например,NaN + 1 != 0, илиNaN * 1 > 0, возвращаетTrue илиFalse как будто все было хорошо. Поэтому нельзя полагаться наNaN защитить вас от проблем, если вы планируете использовать операторы сравнения. Учитывая, что сравнения не помогут вам «распространять» NaN, почему бы не сделать их хотя бы чувственными? При сложившейся ситуации они путают случаи использования NaN в словарях, делают сортировку нестабильной и т. Д. Кроме того, незначительная ошибка в вашем ответе.NaN/NaN == 1 не оценил быTrue если бы у меня был свой путь.
 max17 мая 2014 г., 13:16
Кроме того, вы утверждаете, что мой ответ на 100% абсолютно неверен. Однако человек в комитете IEEE, которого вы цитировали, фактически заявил в том самом посте, который вы цитировали: «Многие комментаторы утверждают, что было бы более полезно сохранить рефлексивность равенства и трихотомии на том основании, что принятие NaN! = NaN не делает кажется, сохранить любую знакомую аксиому. Я признаюсь в том, что сочувствую этой точке зрения, поэтому я подумал, что вернусь к этому ответу и предоставлю немного больше контекста. Поэтому, возможно, дорогой сэр, вы могли бы подумать, что в своих высказываниях вы будете менее настойчивы.
 max28 мая 2014 г., 13:07
Я никогда не говорил, что дизайн не был преднамеренным. Преднамеренный дизайн, основанный на плохой логике или плохом понимании проблемы, все еще является ошибкой. Но это обсуждение бессмысленно. Вы ясно обладаете знанием абсолютной истины, и ваша задача - проповедовать его необразованным массам, таким как я. Наслаждайтесь священством.
 Sven Marnach08 окт. 2015 г., 13:22
Распространение NaN посредством вычислений совершенно не связано с сравнением равенства с NaN. Переносимость и реализация NaN в качестве битовой комбинации также несущественны для вопроса о том, должен ли NaN сравниваться равным самому себе или нет. На самом деле, я не могу найти никакого обоснования для NaN! = NaN в этом ответе, за исключением первого связанного ответа внизу, который объясняет, что причиной была недоступностьisnan() в то время, которое является веской причиной, по которой было принято решение. Однако я не вижу никакой причины, которая все еще действует сегодня, за исключением того, что было бы очень плохой идеей изменить семантику.

Попробуй это

var a = 'asdf';
var b = null;

var intA = parseInt(a);
var intB = parseInt(b);

console.log(intA); //logs NaN
console.log(intB); //logs NaN
console.log(intA==intB);// logs false

Если intA == intB было правдой, это может привести к выводу, что a == b, а это явно не так.

Другой способ взглянуть на это состоит в том, что NaN просто дает вам информацию о том, что что-то НЕ, а не о том, что это такое. Например, если я скажу «яблоко не горилла» и «апельсин не горилла», вы бы пришли к выводу, что «яблоко» == «апельсин»?

 supercat30 апр. 2014 г., 01:25
Я не следую твоей логике. Данныйa=16777216f, b=0.25, а такжеc=0.125, если тот факт, чтоa+b == a+c следует понимать, чтоb==c? Или просто, что два вычисления дают Неотличимы полученные результаты? Почему не следует считать, что sqrt (-1) и (0.0 / 0.0) неразличимы, если нет средств их различения?
 Ody23 окт. 2014 г., 03:05
@ MikeC в значительной степени прибил причину без особой грамматики
 Kushal25 февр. 2015 г., 10:26
Так много ответов, и я мог понять только то, что ты объяснил, слава!
 Jim Balter08 апр. 2014 г., 09:42
"это может привести вас к выводу, что a == b" - но это просто неверный вывод - например, strtol ("010") == strtol ("8").
 Mike C30 апр. 2014 г., 14:15
Если ты намекаешь на то, что неотличимые вещи следует считать равными, я с этим не согласен. Равенство подразумевает, что у вас действительно есть возможность различать два объекта сравнения, а не просто идентичный недостаток знаний о них. Если у вас нет средств для их различения, то они могут быть равны или не могут быть. Я мог видеть, что NaN == NaN возвращает 'undefined', но это не так.

известное как «единство». Эти значения являются расширениями, которые тщательно сконструированы для устранения внешних проблем в системе. Например, вы можете думать о кольце на бесконечности в сложной плоскости как о точке или наборе точек, и некоторые ранее претенциозные проблемы исчезают. Есть и другие примеры этого в отношении количества множеств, где вы можете продемонстрировать, что вы можете выбрать структуру континуума бесконечностей, пока | P (A) | > | A | и ничего не ломается.

ОТКРЫТИЕ: Я работаю только со смутным воспоминанием о некоторых интересных предостережениях во время обучения математике. Я приношу свои извинения, если сделал ужасную работу по представлению концепций, на которые я ссылался выше.

Если вы хотите верить, что NaN является единственным значением, то вы, вероятно, будете недовольны некоторыми результатами, такими как оператор равенства не работает так, как вы ожидаете / хотите. Однако, если вы решите верить, что NaN - это скорее континуум «плохости», представленный одиночным заполнителем, то вы совершенно довольны поведением оператора равенства. Другими словами, вы теряете из виду рыбу, которую вы поймали в море, но вы ловите другую, которая выглядит так же, но такая же вонючая.

 max19 мар. 2013 г., 21:42
Да, в математике вы можете добавить Бесконечности и похожие значения. Однако они никогда не нарушат отношения эквивалентности. Равенство программистов представляет отношение эквивалентности в математике, что по определению рефлексивно. Плохой программист может определить== это не рефлексивно, симметрично и транзитивно; К сожалению, Python не остановит его. Но когда сам Python делает== нерефлексивный, и вы даже не можете его переопределить, это полная катастрофа как с практической точки зрения (членство в контейнере), так и с точки зрения элегантности / ясности ума
Решение Вопроса

й точки зрения, не понимая контекст, в котором было принято решение. Таким образом, он не отвечает на вопрос.

Правильный ответ данВо:

NaNнак равNaN возникла из двух прагматических соображений:

[...] Там не былоisnan( ) предикат в то время, когда NaN был формализован в арифметике 8087; было необходимо предоставить программистам удобные и эффективные средства обнаружения значений NaN, которые не зависели от языков программирования, обеспечивающих что-то вродеisnan( ) что может занять много лет

У этого подхода был один недостаток: он сделал NaN менее полезным во многих ситуациях, не связанных с численными вычислениями. Например, гораздо позже, когда люди захотели использоватьNaN чтобы представить пропущенные значения и поместить их в хеш-контейнеры, они не могли этого сделать.

Если бы комитет предвидел будущие варианты использования и посчитал их достаточно важными, они могли бы пойти на более подробные!(x<x & x>x) вместо того,x!=x как тест дляNaN. Однако их фокус был более прагматичным и узким: они обеспечивали лучшее решение для числовых вычислений, и поэтому они не видели проблем с их подходом.

===

Оригинальный ответ:

Мне очень жаль, но я ценю мысль, которая пришла к ответу, получившему наибольшее количество голосов, я с ним не согласен. NaN не означает «неопределенный» - см.http: //www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PD, стр. 7 (поиск по слову «неопределенный»). Как подтверждает этот документ, NaN является четко определенной концепцией.

Кроме того, подход IEEE состоял в том, чтобы как можно больше следовать обычным правилам математики, а когда они не могли, следовать правилу «наименьшего удивления» - см.https: //stackoverflow.com/a/1573715/33652. Любой математический объект равен самому себе, поэтому правила математики подразумевают, что NaN == NaN должно быть True. Я не вижу никакой веской и веской причины отклоняться от такого важного математического принципа (не говоря уже о менее важных правилах трихотомии сравнения и т. Д.).

В результате мой вывод следующий.

лены комитета @IEEE не очень четко продумали это и допустили ошибку. Поскольку очень немногие люди понимали подход комитета IEEE или интересовались тем, что именно стандарт говорит о NaN (то есть: обработка NaN большинством компиляторов в любом случае нарушает стандарт IEEE), никто не поднял тревогу. Следовательно, эта ошибка теперь включена в стандарт. Это вряд ли будет исправлено, так как такое исправление разрушит большую часть существующего кода.

Редактировать: Вот один пост из очень информативного обсуждения. Примечание: чтобы получить беспристрастное представление, вы должны прочитать всю ветку, поскольку Guido придерживается мнения, отличного от представления некоторых других разработчиков ядра. Тем не менее, Гвидо лично не заинтересован в этой теме и во многом следует рекомендациям Тима Питерса. Если у кого-то есть аргументы Тима Питерса в пользуNaN != NaN, пожалуйста, добавьте их в комментарии; у них есть хороший шанс изменить мое мнение.

 russbishop15 мая 2014 г., 00:47
Этот ответ НЕПРАВИЛЬНО НЕПРАВИЛЬНО! Смотрите мой ответ ниже.
 supercat30 апр. 2014 г., 01:28
@ EamonNerbonne: имеяNaN==NaN вернуть что-либо, кроме true или false, было бы проблематично, но учитывая, что(a<b) не обязательно равен!(a>=b), Я не вижу причин, по которым(a==b) обязательно должно быть равно!(a!=b). ИмеяNaN==NaN а такжеNan!=NaN оба возвращают false, чтобы код, которому нужно любое определение равенства, использовал тот, который ему нужен.
 tmyklebu13 февр. 2014 г., 20:59
Ты можешь читать дальше; Кахан говорит в другом месте этого документа: «NaN должны соответствовать математически непротиворечивым правилам, которые были выведены, а не изобретены произвольно [.]» Я согласен, что он не упоминаетка NaN != NaN выводится за пределами высказывания, что необходимо различатьNaN от неNaNs отсутствует поддержка библиотеки какisnan().
 Transcendence15 мая 2014 г., 01:25
Даже если вы основываетесь на функции тождества f на множестве S, где f (x) = x, я бы сказал, что NaN не является частью набора чисел, в конце концов, это буквально не число. Поэтому я не вижу аргумента от функции тождества, что NaN должен равняться самому себе.
 supercat18 сент. 2013 г., 21:40
IMHO, имеяNaN нарушать трихотомию имеет смысл, но, как и вы, я не вижу разумного семантического обоснования отсутствия== определить отношение эквивалентности, когда оба его операнда имеют один и тот же тип (я думаю, что языки должны явно запретить сравнения между вещами разных типов - даже если существуют неявные преобразования - если такие сравнения не могут реализовать отношение эквивалентности) , Концепция отношений эквивалентности настолько фундаментальна как в программировании, так и в математике, что кажется безумным ее нарушать.

x == x возвращает false, затемx являетсяNaN.

(можно использовать это свойство, чтобы проверить, еслиx являетсяNaN или не.

 Statham19 дек. 2016 г., 03:57
Это отличная замена np.isnan () и pd.isnull ()!
 supercat11 февр. 2014 г., 01:38
У одного может быть это свойство, но оно все еще есть (Нэн! = Нэн)такж вернуть ложь. Если бы IEEE сделал это, код, который хотел проверить отношение эквивалентности междуa а такжеb мог бы использовать!(a != b).

Ваш ответ на вопрос