nan 比較でPython・JavaScript・Goはどう違う?

要点

  • 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の検出なのか、配列内での存在確認なのかを分け、今回記録された関数やメソッドと照らし合わせたい。

コメント

タイトルとURLをコピーしました