コンピュータサイエンスの文脈で言う"NaN"は、"Not a Number"の略である。

しかし、これを素直に「数値以外のデータ」として受け取ると、混乱する羽目になる。

例えばJavaScriptには、isNaN()というメソッドがある。一見すると、何かしらの値を受け取り、それが数値ではない場合にtrue、そうではない場合にfalseを返してくれそうだ。

この解釈は必ずしも間違いではないが、正しくもない。

NaNの意味

"NaN"は、コンピュータが計算した結果、それが数値ではなかった場合に使われる記号である。

例えば0で割ったりとか、Infinityを掛けたりとか、虚数を求めたりとかするとNaNが返される。

js
console.log(0 / 0);
console.log(0 * Infinity);
console.log(Math.sqrt(-1));

NaNは、浮動小数点数の演算の標準規格であるIEEE 754によって定められた。現在の仕様は改訂版のIEEE 754-2008に則っている。

JavaScriptのNaN

JavaScriptのNaNは、グローバルプロパティである。書き換えはできず、オブジェクトのようにプロパティを追加することもできない。

01と同じく、実質的にはNumber型のプリミティブ値として扱われる。

また、JavaScriptでNaNが表れるのは、以下の5パターンのいずれかである。

  • Number型以外の値の、Number型への無理な変換
  • 実数以外の結果が表れる数値演算
  • 無限大が含まれる演算
  • NaNの含まれる演算
  • その他、無効な値を数値型として表現しようとする演算

ほか、JavaScriptに限らず、NaNは以下の特徴を持つ。

  • NaNが含まれる演算の結果は、常にNaNとなる
  • NaNが含まれる関係演算は、常にfalseを返す
  • NaNNaNも不等となる
  • NaNfalsyな値である

isNaN()とNumber.isNaN()

JavaScriptには、渡された値がNaNかどうかを判断する方法が2つある。

isNaN()Number.isNaN()である。

かつてはisNaN()のみで賄われていたが、この関数には問題があった。数値以外の値が渡された際に、その値を数値型に変換する、というものだ。

この変換が場合によって予測不明であるために、より厳密にNaNを判断する方法としてNumber.isNaN()が追加された。

ちなみにisNaN()に渡された値は以下のように変換される。

  • 数値はそのまま。
  • undefinedNaNに変換。
  • null0に変換。
  • true1に、false0に変換。
  • 文字列は、以下のルールに基づいてパースされ、パースに失敗するとNaNとなる。
    • 先頭と末尾の空白・改行は無視される。
    • 先頭に0があっても、8進数としては解釈されない。
    • 先頭の+-は、符号として許可される。
    • Inifity-Infinityは、数値として解釈される。
    • 空文字やスペースだけの文字列は0に変換する。
    • 読みやすさのための区切り文字(_)は許可されない。
  • BigIntsSymbolTypeErrorを投げる
  • オブジェクトの場合は、そのオブジェクトの[@@toPrimitive]()メソッド、valueOf()メソッド、toString()メソッドを順に呼び出し、プリミティブ値に変換できた段階で数値に変換される。

参考資料