要点
- NaNを自分自身と比較すると、Python・Goの
==、JavaScriptの===はいずれも偽だった(出典: 自社の実測・2026-10-25)。 - NaNを渡した専用関数は、測定した3言語すべてで真を返した(出典: 自社の実測・2026-10-25)。
- JavaScriptでは、文字列
"abc"に対するisNaNとNumber.isNaNの結果が異なった(出典: 自社の実測・2026-10-25)。 - JavaScriptの配列では、
includesはNaNを見つけ、indexOfは見つけなかった(出典: 自社の実測・2026-10-25)。
NaNの比較では何が困るのか
NaNとは、「数値ではない」ことを表すNot a Numberのことだ。
NaNかどうかを調べたいとき、NaNとの等値比較を書けば判定できるように見える。しかし、今回の記録では、PythonとGoの==、JavaScriptの===でNaNを自分自身と比較しても、結果はすべて偽だった。同じ変数を左右に置く書き方でも、NaNであることを真として取り出せない。
ここで分けたいのは、「値が等しいか」という問いと、「値がNaNか」という問いだ。今回の実測では、比較演算子とNaN判定用の関数に同じNaNを渡して、異なる結果が得られている。NaNの検出を目的にするなら、その目的に合う判定方法を選ぶ必要がある。
測定日は2026-10-25(JST)。記録にある環境情報は次のとおりだ。Goの版情報にはdarwin/arm64が含まれる。PythonとNode.jsについては、下記の版情報が記録されている。
| 道具 | 確認コマンド | 記録された版情報 |
|---|---|---|
| Python | python3 --version |
Python 3.9.0 |
| Node.js | node --version |
v22.23.4 |
| Go | go version |
go version go1.26.2 darwin/arm64 |
出典: 自社の実測(2026-10-25)
公式資料は自分自身との比較をどう説明しているか
MDNのNaNについて、参照記録には次の公式文の抜粋がある。
"NaN… is the only value in JavaScript that is not equal to itself"
出典: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN (取得日 2026-10-25)
この記述は、JavaScriptのNaNが自分自身と等しくない値であることを示している。今回のJavaScriptの実測で、NaN === NaNがfalseだったこととも一致する。
また、Pythonの公式mathモジュールの参照記録では、NaNの判定に専用関数を使うことが案内されている。Pythonではmath.isnanによる判定が、今回の確認対象になっている。
参照: https://docs.python.org/3/library/math.html
ただし、公式文の引用が直接説明している範囲と、手元で実行した範囲は区別したい。ここで引用したMDNの文はJavaScriptについてのものだ。PythonとGoの具体的な比較結果は、以下に示す実測記録を根拠にしている。また、JavaScriptで今回実行した比較演算子は===であり、==の実測結果として読み替えることはできない。
3言語の比較演算子と専用関数を比べる
NaNを用意して比較し、続いてNaN判定用の関数に渡した結果を並べると、比較と判定の違いが見える。
| 言語 | 実行した比較式 | 比較結果 | NaNを渡した専用関数 | 判定結果 |
|---|---|---|---|---|
| Python | x == x |
False |
math.isnan(x) |
True |
| JavaScript | x === x |
false |
Number.isNaN(x) |
true |
| Go | n == n |
false |
math.IsNaN(n) |
true |
Pythonではx = float('nan')、JavaScriptではconst x = NaN;、Goではn := math.NaN()として測定した。Pythonの記録をそのまま示す。
import math
x = float('nan')
print(x == x) # False(== では判定できない)
print(math.isnan(x)) # True(専用関数で判定)
同じxを使っていても、等値比較の結果はFalse、専用関数の結果はTrueになっている。したがって、「NaNなら処理を分けたい」という用途では、表の比較式をそのまま条件にしても、今回のNaNは真として判定されない。
3言語で関数名の表記は異なるが、今回渡したNaNに対して専用関数が真を返した点は共通する。ただし、この表はNaNを入力した結果の比較であり、各関数にあらゆる型の値を渡した結果を示すものではない。
出典: 自社の実測(2026-10-25)
どちらを使うかは文字列と配列の検索でも変わる
JavaScriptでは、名前の似たisNaNとNumber.isNaNにも差があった。NaNを渡した場合は、どちらもtrueだった。一方、文字列"abc"では結果が分かれている。
| 入力 | isNaNの結果 |
Number.isNaNの結果 |
|---|---|---|
NaN |
true |
true |
"abc" |
true |
false |
記録では、グローバル関数のisNaNは文字列にも数値変換を試みるため、"abc"に対してtrueになったと説明されている。Number.isNaNは型も見るため、この文字列に対してはfalseだった。今回のように、文字列"abc"をNaNとして扱わずに判定したい場合は、Number.isNaNを選ぶ根拠になる。
配列内でNaNを探す場合も、方法をそろえずに結果だけを期待すると食い違いが出る。
| 対象 | 実行した検索・判定 | 結果 |
|---|---|---|
Pythonのa = [1, float('nan'), 3] |
float('nan') in a |
False |
| 同じPythonのリスト | any(math.isnan(x) for x in a) |
True |
JavaScriptのconst a = [1, NaN, 3]; |
a.includes(NaN) |
true |
| 同じJavaScriptの配列 | a.indexOf(NaN) |
-1 |
Pythonで測定したinの式は、検索時にもfloat('nan')を呼んでいる。この結果を、NaNを扱うすべてのinの書き方に広げることはできない。確認できたのは、表にある式では見つからず、各要素をmath.isnanで調べる式では真になったことだ。
JavaScriptでは、同じ配列に対するincludesとindexOfで結果が異なった。今回の配列でNaNの有無を調べる用途には、includesの実測が判断材料になる。Goのスライス内検索と、NaNを含む構造体・辞書のキー比較は測定されていないため、この表から結果を補うことはできない。
出典: 自社の実測(2026-10-25)
自分の環境で確かめる手順
PythonとNode.jsを使える環境では、次のコマンドで版情報を確認したうえで、比較演算子と専用関数の違いを確かめられる。以下は読者が実行するための手順であり、新たな実行結果は掲載していない。
python3 --version
python3 -c "import math; x = float('nan'); print(x == x); print(math.isnan(x))"
node --version
node -e 'console.log(NaN === NaN); console.log(Number.isNaN(NaN)); console.log(isNaN("abc")); console.log(Number.isNaN("abc"));'
Pythonのコマンドは、同じ変数に対する等値比較と専用関数の順に表示する。Node.jsのコマンドは、NaNの自己比較、専用関数による判定、文字列に対する2種類の関数の判定を順に表示する。
確認するときは、結果と式を対応させて読むことが大切だ。とくにJavaScriptの文字列に対する判定は、NaNそのものを渡した場合とは比較の条件が違う。自分のコードが必要としているのがNaNの検出なのか、配列内での存在確認なのかを分け、今回記録された関数やメソッドと照らし合わせたい。

コメント