Почему IEEE-754 решил, что NaN!= NaN, несмотря на свою нелогичность?

Это дополнительный вопрос к тому, что является обоснованием для всех сравнений, возвращающих false для значений NaN IEEE754? (Я думаю, что это лучше, как другой вопрос, чем комментарий). У него очень хороший ответ, в котором упущена ровно одна важная вещь: почему NaN != NaN?

Я понимаю, что NaN неупорядочен по сравнению с числами и, таким образом, NaN < x а также NaN > x оба всегда ложны. Но это не объясняет, почему равенство задом наперед. Чтобы процитировать ответ на вопрос, который я связал с:

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

Хорошо, тогда:

if((0/0) == x) print "I found NaN!";
//using 0/0 is more readable than using 0x7fc00000 or 0x7ff8000000000000

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

Одна дополнительная операция, безусловно, не является неэффективной, тем более что FPU имеет жестко запрограммированный ответ (не требуется никаких расчетов). Использование 0/0 также более удобно для программиста, чем нелогично x!=x,

Программа редко нуждается в проверке на NaN, и наличие одной дополнительной операции на проверку не будет причиной неэффективности программы. Аналогично, нет такой программы, настолько ограниченной, чтобы она не могла обрабатывать ни одну дополнительную переменную, особенно временную.

Для меня аргумент "мне нужно NaN!=NaN так что я могу обнаружить это "не имеет смысла: это точно такой же аргумент, как" мне нужно Infinity!=Infinity так что я могу это обнаружить ". Нет, не надо, просто сравните это с 1/0, как и все остальные.

Поэтому мой вопрос гораздо более узкий, чем первоначальный вопрос: почему NaN != NaN?

Я не могу сказать, задавался ли этот вопрос раньше, так как есть много дубликатов исходного вопроса.

Примечание:

NaN == NaN не собирается меняться сейчас

хотя FPU теперь не изменится, некоторые языки программирования уже изменились, так что NaN == NaN правда.

Редактировать:

Позвольте мне попытаться объяснить, почему я до сих пор не принял никакого ответа. Я до сих пор читал комментарии, и мне жаль, что я бросил мяч: вместо того, чтобы объяснять, почему я не согласен, я просто спросил "почему", надеясь, что вы дадите другую причину. Итак, позвольте мне попытаться объяснить мою точку зрения лучше.

Бесконечность и NaN во многом похожи.

  1. И бесконечность, и NaN - понятия. Бесконечность - это не число, это понятие бесконечного конца. Если x бесконечность, то это означает, что x бесконечен. NaN не является числом (duh) и представляет недопустимое состояние или что-то не математически допустимое. Для математической полноты: бесконечность является спорным "числом", однако числа с плавающей точкой приближают действительные числа (хотя они ближе к рациональным числам), а бесконечность определенно не в действительных числах. Следовательно, что касается FPU и строки действительных чисел, бесконечность (все типы) не является числом (согласно определению домена "число").
  2. Равенство не всегда числовое равенство. Общее равенство - это только числовое равенство, если оба операнда являются числами (а не понятиями), даже если FPU предлагается выполнить сравнение. Общее равенство используется, когда одним операндом является бесконечность или NaN, чтобы увидеть, представляет ли другой ту же концепцию. Например x == Infinity не использует числовое равенство (поскольку Infinity не является числом), вместо этого он проверяет, представляет ли x понятие положительной бесконечности. Я также ожидал бы того же самого от x == NaN возвращать истину, если x является понятием "не число", но это не так (относительно причины этого вопроса).
  3. Оба могут быть получены путем деления на 0: 0/0 возвращает NaN, а 1/0 возвращает бесконечность. Если ваш язык не имеет константы для бесконечности, то x == (1/0) это способ сравнить х с бесконечностью.
  4. Несколько вкусов. Существует бесконечно много типов Бесконечности (из-за кардинальности). Однако FPU не делает никаких различий: Infinity является универсальной и единственной доступной. С этими конструкциями невозможно спросить, является ли x, например, счетной бесконечностью. Концептуально NaN имеет только 1 тип ("не число"), однако имеет 2 способа обработки: тихий и сигнальный. Я ничего не знаю о передаче сигналов, но, насколько я понимаю, если бы вы попытались сравнить равенство сигнального NaN, он бы выбросил, поэтому, поскольку у него нет равенства, это не совсем по теме.
  5. Битовое представление. NaN имеет много разных битовых представлений, но Infinity имеет только 1 (и 1 для -Infinity). Однако все представления NaN логически точно совпадают, потому что все они представляют одно и то же понятие "не число". Не следует делать различий между 0x7FF8000000000000 и 0x7FF8000000000001: они означают одно и то же, и одна и та же математика может возвращать любой результат. Вы не можете спросить, является ли x квадратом (-1) или x является логарифмом (-1), потому что оба из них будут возвращать одно и то же: NaN. Подобно тому, как существует только 1 вид Бесконечности, существует только 1 тип (тихий) NaN. Да, существует несколько битовых представлений, но одно не превосходит другие: FPU использует специальную логику, чтобы обрабатывать их все одинаково. Это также верно для -0, бит которого отличается от +0, но обрабатывается точно так же. Следовательно, биты - это детали реализации, не связанные с логическим равенством.
  6. (Не по теме, но у них обоих есть особая математика: x-1 не меняет значение бесконечности или NaN).

Так что да, я слышал вас, когда вы сказали, что "равенство не имеет смысла, потому что это не число", но я не согласен с этим утверждением, потому что если бы оно было верным, то, согласно пункту 1, также не имеет смысла сравнивать бесконечность (что тоже не число). Хотя согласно #2 имеет смысл сравнивать не числа.

На самом деле я прочитал каждый ответ на первоначальный вопрос (и на Почему равны бесконечности с плавающей запятой, в отличие от NaNs?, Который имеет некоторые связанные ответы). Все аргументы почему NaN != NaN истинно сводится либо к "потому что это не число" (уже адресовано), либо к "потому что есть много разных битовых представлений", которым противостоит #5.

Я не могу придумать какой-либо логической основы того, почему NaN должно иметь различное равенство. Я не говорю, что я все учел: так что я пропустил? Один из моих аргументов неверен или есть какая-то другая причина, о которой я не думал? Вот почему я использовал слово "почему". Если вы не согласны, то опровергайте меня или защищайте свою точку зрения. Я предполагаю, что будет хотя бы один контрапункт моей вышеупомянутой логике, и я с нетерпением жду, чтобы услышать это.

Я снова прошу прощения за то, что не включил их в первоначальный вопрос, так как я думал об этом все время. Я также сожалею, что это может вызвать большие изменения в существующем ответе.

2 ответа

Есть несколько способов производства NaN,

Вообразите это:

double expr1 = 0.0 / 0.0;
double expr2 = Math.log(-1.0);
if (expr1 == expr2) {
  // They are the same
}

Эти двое NaNs, если бы они были представлены в виде чисел, имели бы высокую вероятность быть разными значениями.

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

Предположим, что A, B и C — числа. ? означает неопределенный A/B = C; потому что С * В = А

в случае B = 0 A/0 = ?, так как ? * 0 =
Нет номера для ? что делает это верным, если только A не равно 0 (см. Ниже). Предел A/B при стремлении B к нулю равен бесконечности; A/0 не определено, а не бесконечно.

в случае как A = 0, так и B = 0 0/0 = ?, потому что ? * 0 = 0 (все числа для ? делают это верным)

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

Если используемый вами компилятор или FPU имеет определенное поведение для неопределенного результата, соответствующим образом скорректируйте свой код.

выходит за рамки моего ответа: не все бесконечности равны

Другие вопросы по тегам