Почему typeof NaN возвращает "номер"?

Просто из любопытства.

Не похоже, чтобы typeof NaN был числом. Точно так же, как NaN === NaN или NaN == NaN возврат false. Является ли это одной из особенностей javascript или будет причина для этого?

Изменить: спасибо за ваши ответы. Но нелегко заставить их обойти. Чтение ответов и вики я понял больше, но все же предложение вроде

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

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

Ответ 1

Это означает не номер. Это не особенность javascript, а общий принцип компьютерной науки.

Из http://en.wikipedia.org/wiki/NaN:

Существует три вида операций которые возвращают NaN:

Операции с NaN как по крайней мере одним операндом

Неопределенные формы

  • Разделы 0/0, ∞/∞, ∞/-∞, -∞/∞ и -∞/-∞
  • Умножения 0 × ∞ и 0 × -∞
  • Мощность 1 ^ ∞
  • Добавления ∞ + (-∞), (-∞) + ∞ и эквивалентные вычитания.

Реальные операции со сложными результатами:

  • Квадратный корень отрицательного числа
  • Логарифм отрицательного числа
  • Тангенс нечетного кратного 90 градусов (или π/2 радиан)
  • Обратный синус или косинус числа, которое меньше -1 или больше +1.

Все эти значения могут быть не одинаковыми. Простой тест для NaN заключается в проверке value == value является ложным.

Ответ 2

Ну, NaN по-прежнему является числовым типом, несмотря на то, что он фактически означает Not-A-Number: -)

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

Конкретный NaN не считается равным другому NaN, потому что они могут быть разными значениями. Однако NaN по-прежнему является типом числа, как 2718 или 31415.


Что касается вашего обновленного вопроса для объяснения в неспециалистских терминах:

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

Все это означает (разбивается на части):

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

В принципе, NaN не равно никакому другому номеру, включая другой NaN, и даже включая его.

Предикаты сравнения либо сигнализируют, либо не сигнализируют, версии сигнализации сигнализируют недопустимое исключение для таких сравнений.

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

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

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

Ответ 3

Стандарт ECMAScript (JavaScript) указывает, что Numbers являются Numbers с плавающей точкой IEEE 754, которые включают в себя NaN в качестве возможного значения.

ECMA 262 5e Раздел 4.3.19: Числовое значение

значение примитива, соответствующее 64-битному двоичному формату IEEE 754 с двойной точностью.

ECMA 262 5e Раздел 4.3.23: NaN

Числовое значение, которое является значением IEEE 754 "Not-a-Number".

IEEE 754 в Википедии

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

Стандарт определяет

  • арифметические форматы: наборы двоичных и десятичных данных с плавающей точкой, которые состоят из конечных чисел (в том числе нулей со знаком и субнормальных чисел), бесконечностей и специальных значений "не число" (NaN)

[...]

Ответ 4

typeof NaN возвращает 'number', потому что:

  • Спецификация ECMAScript говорит, что тип номера включает NaN:

    4.3.20 Тип номера

    набор всех возможных значений числа, включая специальный "Not-a-Number" (NaN), положительной бесконечности и отрицательной бесконечности

  • Итак, typeof возвращает соответственно:

    11.4.3 Оператор типа

    Произведение UnaryExpression: typeof UnaryExpression оценивается следующим образом:

    • Пусть val является результатом вычисления UnaryExpression.
    • Если Тип (val) - Ссылка, то
    • Возвращает строку, определенную Тип (val) в соответствии с Таблицей 20.

                    Table 20 — typeof Operator Results
    ==================================================================
    |        Type of val         |              Result               |
    ==================================================================
    | Undefined                  | "undefined"                       |
    |----------------------------------------------------------------|
    | Null                       | "object"                          |
    |----------------------------------------------------------------|
    | Boolean                    | "boolean"                         |
    |----------------------------------------------------------------|
    | Number                     | "number"                          |
    |----------------------------------------------------------------|
    | String                     | "string"                          |
    |----------------------------------------------------------------|
    | Object (native and does    | "object"                          |
    | not implement [[Call]])    |                                   |
    |----------------------------------------------------------------|
    | Object (native or host and | "function"                        |
    | does implement [[Call]])   |                                   |
    |----------------------------------------------------------------|
    | Object (host and does not  | Implementation-defined except may |
    | implement [[Call]])        | not be "undefined", "boolean",    |
    |                            | "number", or "string".            |
    ------------------------------------------------------------------
    

Это соответствует стандарту IEEE для арифметики с плавающей точкой (IEEE 754):

4.3.19 Числовое значение

примитивное значение, соответствующее 64-битовому двоичному двоичному представлению с двойной точностью формат IEEE 754

4.3.23 NaN

числовое значение, которое является значением IEEE 754 "Not-a-Number"

8.5 Тип номера

Тип номера имеет точно 18437736874454810627 (то есть 2 53 -2 64 +3) значения, представляющие 64-битный формат с двойной точностью IEEE 754 значения, указанные в стандарте IEEE для двоичной плавающей точки Арифметика, за исключением того, что 9007199254740990 (то есть 2 53 -2) Значения "Not-a-Number" стандарта IEEE представлены в ECMAScript как одно специальное значение NaN. (Обратите внимание, что значение NaN создается программным выражением NaN.)

Ответ 5

NaN != NaN, потому что они не являются необходимыми НЕ-число. Таким образом, это имеет большой смысл... Кроме того, у float есть и +0.00 и -0.00, которые не совпадают. Округление может сделать, что они фактически не равны нулю.

Что касается typeof, это зависит от языка. И большинство языков скажут, что NaN - это float, double или number в зависимости от того, как они классифицируют его... Я не знаю языков, которые скажут, что это неизвестный тип или null.

Ответ 6

NaN - допустимое значение с плавающей запятой (http://en.wikipedia.org/wiki/NaN)

и NaN === NaN ложно, потому что они не обязательно являются одинаковыми не-числоми

Ответ 7

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

Хотя его имена говорят, что это не число, тип данных, используемый для его хранения, является числовым. Поэтому в JavaScript запрос типа данных NaN вернется number (как ясно показывает alert(typeof(NaN))).

Ответ 8

Javascript использует NaN для представления всего, с чем он сталкивается, который не может быть представлен каким-либо другим способом по его спецификациям. Это не значит, что это не число. Это просто самый простой способ описать встречу. NaN означает, что он или объект, который ссылается на него, не может быть представлен каким-либо другим способом javascript. Для всех практических целей это "неизвестно". Будучи "неизвестным", он не может сказать вам, что это такое, и даже если он сам. Это даже не объект, которому он назначен. Он может только сказать вам, что это не так, а незнание или ничто не может быть описано математически только на языке программирования. Поскольку математика о числах, javascript представляет ничто как NaN. Это не значит, что это не число. Это означает, что мы не можем читать его каким-либо другим способом, который имеет смысл. Вот почему он не может даже равняться себе. Потому что это не так.

Ответ 9

Лучшее имя для NaN, более точно и менее смутно описывающее его значение, будет числовым исключением. Это действительно другой вид объекта исключения, замаскированный как имеющий примитивный тип (по языковому дизайну), где в то же время он не рассматривается как примитивный в своем ложном самосогласовании. Откуда путаница. И пока язык "не заставит себя думать" выбирать между правильным объектом исключения и примитивной цифрой, путаница останется.

Позорное неравномерность NaN для себя, как ==, так и === является проявлением запутанной конструкции, заставляющей этот объект исключения быть примитивным типом. Это нарушает фундаментальный принцип, согласно которому примитив однозначно определяется его значением. Если NaN предпочтительнее рассматривать как исключение (из которого могут быть разные типы), то он не должен быть "продан" как примитивный. И если он хочет быть примитивным, этот принцип должен выполняться. Пока он сломан, как и в JavaScript, и мы не можем решить между ними, путаница, приводящая к ненужной когнитивной нагрузке для всех участников, останется. Который, однако, очень легко исправить, просто сделав выбор между ними:

  • либо сделать NaN особый объект исключения, содержащий полезную информацию о том, как возникло исключение, а не выбрасывать эту информацию как то, что в настоящее время реализовано, что приводит к сложному отладке кода;
  • или сделать NaN объект примитивного типа number (который может быть менее смутно назван "числовым" ), и в этом случае он должен быть равен самому себе и не может содержать никакой другой информации; последний, безусловно, имеет более низкий выбор.

Единственное возможное преимущество форсирования NaN в тип number - это возможность вернуть его в любое числовое выражение. Это, однако, делает его хрупким выбором, потому что результат любого численного выражения, содержащего NaN, будет либо NaN, либо приведет к непредсказуемым результатам, таким как NaN < 0, оценивающим до false, т.е. возвращая boolean вместо сохраняя исключение.

И даже если "все так, как есть", ничто не мешает нам сделать это четкое различие для себя, чтобы сделать наш код более предсказуемым и легко отлаживаемым. На практике это означает выявление этих исключений и рассмотрение их как исключений. Который, к сожалению, означает больше кода, но, надеюсь, будет смягчен такими инструментами, как TypeScript Flowtype.

И тогда у нас есть беспорядочный тихий vs шумный сигнал сигнализации NaN. Речь идет о том, как обрабатываются исключения, а не о самих исключениях и ничего не отличается от других исключений.

Аналогично, Infinity и +Infinity являются элементами числового типа, возникающими в расширении реальной строки, но они не являются действительными числами, Математически они могут быть представлены последовательностями действительных чисел, сходящихся либо к +, либо к -Infinity.

Ответ 10

Это просто потому, что NaN является свойством объекта Number в JS, он не имеет ничего общего с тем, что он является числом.

Ответ 11

Лучший способ думать о NAN заключается в том, что это не известный номер. Вот почему NAN!= NAN, потому что каждое значение NAN представляет собой некоторое уникальное неизвестное число. NAN необходимы, поскольку числа с плавающей запятой имеют ограниченный диапазон значений. В некоторых случаях округление происходит там, где теряются младшие биты, что приводит к тому, что кажется бессмысленным, как 1.0/11 * 11!= 1.0. Действительно большие значения, которые больше, - это идеальные примеры NAN с бесконечностью.

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

Ответ 12

Поскольку NaN является числовым типом данных.

Ответ 13

NaN - это номер с точки зрения типа, но не является нормальным числом, например 1, 2 или 329131. Имя "Не номер" относится к тому, что значение представленный специально и относится к области спецификации формата IEEE, а не к языковому языку javascript.

Ответ 14

Если вы используете jQuery, я предпочитаю isNumeric проверять тип:

console.log($.isNumeric(NaN));  // returns false
console.log($.type(NaN));       // returns number

http://api.jquery.com/jQuery.isNumeric/

Ответ 15

Javascript имеет только один числовой тип данных, который является стандартным 64-битным плавающей точкой с двойной точностью. Все двойное. NaN - особое значение double, но тем не менее оно двойное.

Все, что делает parseInt, - это "приведение" вашей строки в числовой тип данных, поэтому результат всегда "число"; только если исходная строка не была проанализирована, ее значение будет NaN.

Ответ 16

NaN по-прежнему является числовым типом, но представляет собой значение, которое не может представлять действительное число.

Ответ 17

Мы можем утверждать, что NaN является объектом специального случая. В этом случае объект NaN представляет собой число, которое не имеет математического смысла. В математике, например, INFINITE и т.д. Существуют некоторые другие объекты специального случая.

Вы можете выполнять некоторые вычисления с ним, но это приведет к странным поведением.

Дополнительная информация здесь: http://www.concentric.net/~ttwang/tech/javafloat.htm (java based, а не javascript)

Ответ 18

Вы должны любить Javascript. У него есть несколько интересных причуд.

http://wtfjs.com/page/13

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

Кстати, я рекомендую прочитать остальную часть http://wtfjs.com/ - там будет много более интересных причуд, чем этот!

Ответ 19

Значение NaN действительно является Number.NaN, поэтому, когда вы спрашиваете, является ли это числом, он скажет "да". Вы сделали правильную вещь, используя вызов isNaN().

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

Ответ 20

Пример

Представьте, что мы преобразовываем строку в число:

Number("string"); // returns NaN

Мы изменили тип данных на число, но его значение не является числом!

Ответ 21

Это специальное значение типа Number как POSITIVE_INFINITY

Почему? По дизайну