Чому typeof NaN повертає "число"?


166

Тільки з цікавості.

Це не дуже логічно, що typeof NaNце число. Так само , до речі, NaN === NaNабо NaN == NaNповернення помилкових. Це одна з особливостей javascript чи це буде причина для цього?

Редагувати: дякую за відповіді. Але нелегка річ, щоб змусити їх голову, хоча. Читаючи відповіді та вікі, я зрозумів більше, але все-таки таке речення, як

Порівняння з NaN завжди повертає невпорядкований результат навіть при порівнянні з самим собою. Предикати порівняння є або сигналізацією, або несигналізацією; версії сигналізації сигналізують про недійсне виключення для таких порівнянь. Ідентифікатори рівності та нерівності не сигналізують, тому х = х, що повертаються помилковими, можна використовувати для перевірки, чи є х тихим NaN.

просто тримає мою голову крутиться. Якщо хтось може перекласти це людською (на відміну, скажімо, математиком) читаною мовою, я був би вдячний.


17
+1: "NaN - це число, але це не число. Гум ... що ?!"
ereOn

11
Для додаткової забави; (NaN! == NaN) == вірно
Алекс К.

1
Ще веселіше (але зрозуміло, думаючи про це, isNaN повертає булевий): isNaN (parseInt ('nodice')) === isNaN (parseInt ('someOtherNaN')) === вірно;
KooiInc

1
Якщо ви використовуєте jQuery, я віддаю перевагу isNumericперевірці типу: $.isNumeric(NaN); повертає false, де як $.type(NaN);, повертає число. api.jquery.com/jQuery.isNumeric
Джастін

3
Як професійний математик, я повинен сказати, що речення має мало спільного з точною мовою математики.
Дмитро Зайцев

Відповіді:


53

Це означає Не число. Це не особливість JavaScript, а загальний принцип інформатики.

З http://en.wikipedia.org/wiki/NaN :

Існує три види операцій, які повертають NaN:

Операції з NaN як мінімум одним операндом

Неозначені форми

  • Підрозділи 0/0, ∞ / ∞, ∞ / −∞, −∞ / ∞ і −∞ / −∞
  • Множення 0 × ∞ і 0 × −∞
  • Потужність 1 ^ ∞
  • Додавання ∞ + (−∞), (−∞) + ∞ та еквівалентні віднімання.

Реальні операції зі складними результатами:

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

Усі ці значення можуть бути не однаковими. Простий тест для NaN - перевірити value == valueпомилково.


46
Ще простіший тестisNaN(value)
Альссенде

4
@Alsciende це не рівнозначно. isNaN(undefined)повертає true, але undefined == undefinedтеж правда. Те саме стосується всіх інших типів, крім числа null.
Енді

7
Іншими словами, value !== valueце, мабуть, найкоротший спосіб перевірити, чи valueсправді це NaN.
Енді

1
Схоже, ти маєш рацію, @Andy. Тепер це особливість.
Альсьенде

2
Фраза "ці значення можуть бути не однаковими" не має значення, оскільки ці значення не існують.
Дмитро Зайцев

103

Ну, NaNце все ще числовий тип , незважаючи на те, що він насправді означає Not-A-Number :-)

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

Конкретний NaNне вважається рівним іншому, NaNоскільки вони можуть бути різними значеннями. Тим не менш, NaNце все ще число типу, як і 2718 або 31415.


Що стосується Вашого оновленого запитання, яке слід пояснити в умовах непростої людини:

Порівняння з NaN завжди повертає невпорядкований результат навіть при порівнянні з самим собою. Предикати порівняння є або сигналізацією, або несигналізацією; версії сигналізації сигналізують про недійсне виключення для таких порівнянь. Ідентифікатори рівності та нерівності не сигналізують, тому х = х, що повертаються помилковими, можна використовувати для перевірки, чи є х тихим NaN.

Все це означає (розбитий на частини):

Порівняння з NaN завжди повертає невпорядкований результат навіть при порівнянні з самим собою.

В основному, а NaNне дорівнює жодному іншому числу, включаючи інше NaN, і навіть включає себе .

Предикати порівняння є або сигналізацією, або несигналізацією; версії сигналізації сигналізують про недійсне виключення для таких порівнянь.

Спроба зробити порівняння (менше, більше і т. Д.) Операцій між NaNіншим і іншим числом може призвести до того, що викид буде викинуто (сигналізація), або просто отримати помилковий результат (несигналізація або спокійне).

Ідентифікатори рівності та нерівності не сигналізують, тому х = х, що повертаються помилковими, можна використовувати для перевірки, чи є х тихим NaN.

Тести на рівність (рівне, не рівне) ніколи не сигналізують, тому їх використання не спричинить винятку. Якщо у вас є звичайний номер x, то x == xце завжди буде правдою. Якщо xце a NaN, то x == xзавжди буде помилковим. Це дає вам можливість NaNлегко (тихо) виявити .


1
гарне пояснення, хоча я не погоджуюсь в останніх двох реченнях: кращий спосіб перевірити, чи х NaN використовує функцію isNaN ()
Карлос Барселона

@DominicRodger ось як я думаю про це: typeof a === 'number'означає "a зберігається внутрішньо як IEEE 754 float"
Енді

Чому Infinity === Infinityповертається, trueякщо Infinityможна отримати різні значення: 1,0 / 0,0 або 2,0 / 0,0?
Hashem Qolami

1
@Hashem, цілком ймовірно, тому що вони вважаються однаковою нескінченністю. Трактуючи поділ як повторне віднімання, це не має ніякої різниці, починаєте ви з двох або одного, це однакова кількість кроків, необхідних для досягнення (або, точніше, не досягнення) нуля. Я розумію, що у гуру математики є різні класи нескінченності, але (1) я підозрюю 1/0і 2/0лежу в одному класі, і (2) в IEEE754 є один клас нескінченності (крім +/-звичайно).
paxdiablo

1
Я не знаю жодного способу визначити ці виняткові "фактичні числа" будь-яким змістовним чином. У математиці журнал та корінь негативів можна отримати лише за допомогою розширення дійсних даних до складних чисел, де вони оцінюються на декілька значень, і 0/0не визначаються жодним змістовно, крім того, щоб сказати, що його "значення" є цілим набором чисел. І навіть якщо вони були визначені, Math.log(-1) == Math.log(-1)все одно оцінює false. Тож не тільки немає "фактичних чисел", окрім, NaNале навіть якщо вони були, вони не використовувалися для порівняння.
Дмитро Зайцев

20

Стандарт ECMAScript (JavaScript) визначає, що Numbersце поплавці IEEE 754 , які включають NaNяк можливе значення.

ECMA 262 5e Розділ 4.3.19 : Значення числа

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

ECMA 262 5e Розділ 4.3.23 : NaN

Значення числа, яке є значенням IEEE 754 "Не число"

IEEE 754 у Вікіпедії

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

Стандарт визначає

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

[...]


8

typeof NaNповертається, 'number'тому що:

  • Специфікація ECMAScript говорить, що Тип Числа включає NaN:

    4.3.20 Тип номера

    набір усіх можливих значень числа, включаючи спеціальні значення "Не-число" (NaN), позитивну нескінченність та негативну нескінченність

  • Отже, typeofповертається відповідно:

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

    Виробництво UnaryExpression : typeof UnaryExpression оцінюється наступним чином:

    1. Нехай val є результатом оцінки UnaryExpression .
    2. Якщо Type ( val ) є посиланням , то
      1. Якщо IsUnresolvableReference ( val ) вірно , поверніться "undefined".
      2. Нехай val буде GetValue ( val ).
    3. Повертає рядок визначається типом ( вали ) в відповідності з таблицею 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 "Не число"

8.5 Тип номера

Тип Числа має точно 18437736874454810627 (тобто 2 53 −2 64 +3) значення, що представляє значення подвійної точності 64-бітового формату IEEE 754, як визначено в стандарті IEEE для двійкової арифметики з плаваючою точкою, за винятком 9007199254740990 ( тобто 2 53 −2) відмінні значення “Не-число” стандарту IEEE представлені в ECMAScript як єдине спеціальне значення NaN . (Зверніть увагу, що значення NaN виробляється програмним виразом NaN.)


5

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

а NaN === NaN помилковий, оскільки вони не обов'язково однакові не числа


1
Вибачте, але я мушу сказати, що це не гарний спосіб подумати про це. "необов'язково однакове число" не означає, що вони завжди різні, і порівнюючи їх, слід отримати помилкове значення. Найкраще не оцінювати NaN і просто вважати це диваком у нашій базі знань.
Дейв

1
То чому всі Infinitys якось однакові? Будь-які думки?
Hashem Qolami

5

NaN != NaNтому що вони не потрібні ІНШЕМУ номеру. Таким чином, це має багато сенсу ... Крім того, чому у плавців є і +0.00, і -0.00, які не є однаковими. Округлення може призвести до того, що вони насправді не дорівнюють нулю.

Що стосується типуof, це залежить від мови. І більшість мов скажуть, що NaN - це плаваючий, подвійний чи числовий, залежно від того, як вони його класифікують ... Я не знаю жодної мови, яка б сказала, що це невідомий тип чи нуль.


1
ех, врахуйте: var x = parseInt ('без кісток'), y = x; Тепер я б сказав, що обидва NaN абсолютно однакові? Але ні, x === y також повертає помилку.
KooiInc

так, але ти не можеш бути впевненим, і, таким чином, вони не однакові. Це та сама логіка, що і логіка NULLable в базі даних. Хоча багато людей вважають їх такими ж, як нульові вказівники з інших мов програмування, вони мають іншу семантику. Вони "невідомі", і тому одне значення NULL порівняно з іншим завжди є помилковим. Виконання обчислень за значенням NULL закінчується результатом NULL. Спробуйте розглянути його з точки зору значення, яке називається НЕВІДОМЛЕНО
Cine

Будучи типовим number, NaNє примітивним, а значить, однозначно визначається його значенням.
Дмитро Зайцев

4

NaNозначає Не число . Це значення числових типів даних (зазвичай типи з плаваючою точкою, але не завжди), що представляє результат недійсної операції, наприклад, ділення на нуль.

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


Власне ділення на нуль оцінюється як InfinityнеNaN
Дмитро Зайцев

2

Javascript використовує NaN для представлення будь-якого зіткнення, яке не може бути представлене іншим способом за своїми характеристиками. Це не означає, що це не число. Це просто найпростіший спосіб описати зустріч. NaN означає, що він чи об'єкт, що посилається на нього, не могли бути представлені іншим способом через JavaScript. Для всіх практичних цілей це "невідомо". Будучи «невідомим», він не може сказати вам, що це таке, навіть навіть якщо він є сам. Це навіть не той об’єкт, якому він призначений. Він може сказати вам лише те, що це не так, і ні-ність чи небуття можна описати лише математично мовою програмування. Оскільки математика стосується чисел, javascript представляє небуття як NaN. Це не означає, що це не число. Це означає, що ми не можемо читати його будь-яким іншим способом, який має сенс. Ось чому це може ' t навіть дорівнює собі. Тому що це не так.


2

Краще назва NaN, яке б точніше і менш заплутано описувало його значення, було б числовим винятком . Це справді інший вид об’єкта винятку, замаскований як примітивний тип (за мовною конструкцією), де при цьому він не трактується як примітивний у своєму помилковому самопорівнянні. Звідси плутанина. І поки мова "не подумає" вибирати між правильним об'єктом виключення та примітивним числом , плутанина залишатиметься.

Сумнівна нерівність самого NaNсебе і того, ==і іншого, ===є проявом заплутаного дизайну, що змушує цей об'єкт винятку бути примітивним. Це порушує основний принцип того, що примітив однозначно визначається його цінністю . Якщо NaNперевагу слід розглядати як виняток (серед яких можуть бути різні види), то це не повинно «продаватися» як примітивне. І якщо він хоче бути примітивним, цей принцип повинен дотримуватися. Поки він порушений, як у нас в JavaScript, і ми не можемо реально вирішити між ними, збережеться плутанина, що призводить до зайвого когнітивного навантаження для всіх учасників. Що, однак, реально легко виправити, просто зробивши вибір між двома:

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

Єдиною можливою перевагою примушування NaNдо numberтипу є можливість повернути його в будь-який числовий вираз. Це, однак, робить її крихким вибором, оскільки результат будь-якого числового вираження, що містить, NaNбуде або матиме NaN, або призводить до непередбачуваних результатів, таких як NaN < 0оцінювання false, тобто повернення booleanзамість збереження виключення.

І навіть якщо "речі є такими, якими вони є", ніщо не заважає нам зробити це чітке розмежування для себе, щоб зробити наш код більш передбачуваним і простішим налагодження. На практиці це означає ідентифікацію цих винятків та поводження з ними як винятки. Це, на жаль, означає більше коду, але, сподіваємось, буде пом'якшено такими інструментами, як TypeScript Flowtype.

І тоді ми маємо безладний тихий і шумний ака, що сигналізує про NaNвідмінність . Що насправді стосується того, як обробляються винятки, а не самі винятки, і нічим не відрізняються від інших винятків.

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


1

Це просто тому, що NaNє властивістю об'єкта Number в JS, він не має нічого спільного з тим, що це число.


Як і будь-який інший об'єкт, номер може мати будь-який тип властивості. Number.fu = "bar"; alert(typeof Number.fu);
Альссенде

NaN- це не значення, яке зберігається в Number.NaN, яким би воно не було. NaNє примітивним значенням типу Number. І крім того, значення Number.NaNє NaN, але це не пов'язано.
Оріол

1

Найкращий спосіб подумати про NAN - це невідоме число. Ось чому NAN! = NAN, оскільки кожне значення NAN являє собою якесь унікальне невідоме число. NAN необхідні, оскільки числа з плаваючою комою мають обмежений діапазон значень. У деяких випадках округлення відбувається там, де втрачаються нижчі біти, що призводить до того, що здається нісенітницею, як 1.0 / 11 * 11! Дійсно великі значення, які є більшими, - це NAN, безмежність є ідеальним прикладом.

Зважаючи на те, що у нас є лише десять пальців, будь-яка спроба показати значення, що перевищують 10, неможлива, це означає, що такі значення повинні бути NAN, оскільки ми втратили справжнє значення, що перевищує 10. Те саме стосується значень з плаваючою комою, де значення перевищує межі того, що може утримуватися в поплавці.


Нескінченність не представлена ​​NaN. Спроба представити число поза діапазоном буде округлена вниз (до max / -inf) або вгору (до min / + inf).
OrangeDog


1

NaN- це число з точки зору типу, але це не нормальне число, як 1, 2 або 329131. Назва "Не число" означає те, що представлене значення є спеціальним і стосується специфікації домену формату IEEE, а не Мовний домен JavaScript.


1

Якщо ви використовуєте jQuery, я віддаю перевагу isNumericперевірці типу:

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

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


Спасибі людина. У мене були проблеми з isNumberз utilпакета машинопису. Добре, що ми все ще використовуємо jQueryв нашому проекті, тому натомість використовували вашу пропозицію.
Ашок М.А.

Для запису, isNumberз utiltypecript також повертається trueдля NaN.
Ашок М.А.

0

У Javascript є лише один числовий тип даних, який є стандартним 64-бітовим поплавком подвійної точності. Все подвійне. NaN - це особливе значення подвійного, але все-таки подвійне.

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


0

NaN все ще є числовим типом, але він представляє значення, яке не могло представляти дійсне число.


0

Ми можемо стверджувати, що NaN є об'єктом особливого випадку. У цьому випадку об'єкт NaN представляє число, яке не має математичного сенсу. У математиці є деякі інші спеціальні об'єкти, такі як INFINITE тощо.

Ви все ще можете зробити деякі розрахунки з цим, але це призведе до дивної поведінки.

Більше інформації тут: http://www.concentric.net/~ttwang/tech/javafloat.htm (на базі Java, а не на JavaScript)


0

Ви повинні полюбити Javascript. У ньому є кілька цікавих примх.

http://wtfjs.com/page/13

Більшість цих химерностей можна пояснити, якщо ви перестаєте їх логічно розробляти, або якщо ви трохи знаєте теорію чисел, але все-таки вони все одно можуть вас наздогнати, якщо ви не знаєте про них.

До речі, рекомендую прочитати решту http://wtfjs.com/ - є набагато цікавіші примхи, ніж ця, яку можна знайти!


0

Значення NaN - це дійсно Число. Отже, коли ви запитаєте, чи є це число, воно скаже «так». Ви зробили правильно, використовуючи дзвінок isNaN ().

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


У якому сенсі це "цінність"? NaN == Number.NaNоцінює до false!
Дмитро Зайцев

@DmitriZaitsev Ви читали нитку? А чи пробували ви if (parseInt ("nan") == Number.NaN)? Спробуйте також! = І подивіться, що це вам каже.
Роб

Вибачте, забула дурну NaN==NaNістоту false, мабуть, це придумав садист, щоб всі страждали.
Дмитро Зайцев

0

Приклад

Уявіть, що ми перетворюємо рядок у число:

Number("string"); // returns NaN

Ми змінили тип даних на число, але його значення не є числом!


Ви, здається, пропустили суть питання. NaNє числовим типом. Питання - це чому.
Квентін

@Quentin Я пояснив, нарешті, рядок.
Амір Фо

-1

Це особливе значення типу Number як POSITIVE_INFINITY

Чому? За дизайном

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.