NaN
NaN(Not a Number、非数、ナン)は、コンピュータにおいて、主に浮動小数点演算の結果として、不正なオペランドを与えられたために生じた結果を表す値またはシンボルである。 たとえば、多くのFPUは負の数値の平方根を求めることができないため、演算結果が不正であることを示す値としてNaNが生成される。 数値計算の類似用語としてNAがあるが、まったく異なる概念なので注意を要する。(後述NA参照)
目次 |
[編集] 浮動小数点数の NaN
浮動小数点演算においては、NaNと無限大は別の概念であるが、どちらも浮動小数点数としての表現も特殊であり、それを使った演算も特殊である。不正な演算という概念と算術オーバーフロー(無限大を結果とする場合もある)と算術アンダーフロー(最小の正常な数値か、非正規化数か、ゼロとなる)は異なる。
NaNは、NaNを含むどんな浮動小数点数と比較しても等しくない。NaNの内部表現が一種類だとしてもである。そこで、変数の値がNaNかどうかは、それ自身と比較してみればすぐにわかる。
IEEE 754 浮動小数点規格では、NaNを使った演算は常に結果がNaNとなり、計算の途中でNaNが発生するとそれが伝播していく。現在策定中のIEEE 754r規格では、この規則にふたつの例外が設けられる予定である。 maxnum と minnum というふたつのオペランドの大きい数か小さい数を返す操作に関して、数をなるべく返す(つまり、オペランドの一方がNaNである場合にもう一方の数を返す)。 これはまばらなデータを統計処理する場合に便利である。
同様のコンセプトはGNU OctaveとMATLABのNaNツールボックスに実装されている([1])。 NaNツールボックスに含まれる統計関数群はNaNを発生させないようになっている。 NaNツールボックスの多くのアルゴリズムはSUMSKIPNANの機能に基づいている([2])。 SUMSKIPNANは全ての数値を加算する際に全てのNaNをスキップする。 NaNツールボックスも数のみに基づいて統計処理をするため、値が抜けているようなデータを統計処理する際に便利である。
[編集] NaN が返される演算
以下の処理で NaN が生成される可能性がある。
- 唯一の引数に NaN を指定された数学関数
- 次のような除算: 0/0、∞/∞、∞/-∞、-∞/∞、-∞/-∞
- 次のような乗算: 0×∞、0×-∞
- 負の数の平方根、ゼロや負数の対数、-1未満の値や+1より大きい値の逆三角関数といった値が未定義となる演算
なお、これらの場合に常に NaN が生成されるわけではない。一つ目の処理の場合、ほぼ間違いなく NaN が生成されるが、他はそうとは限らない。例えば x86アーキテクチャのFPUは最初の項目以外では NaN を生成せず、例外を発生させる。もちろん、ソフトウェアによる例外処理で NaN を返すようにして計算を続行させる可能性もある。
[編集] quiet NaN
quiet NaN あるいは qNaN は演算過程で伝播していく以外に何も例外などを発生させない。 ただし、NaNを出力できない処理の場合は別である。たとえば、フォーマットの変換やある種の比較操作である(NaNが入力されることを想定していない操作)。
[編集] signaling NaN
signaling NaN あるいは sNaN は特殊なNaNであり、多くの操作に入力として用いられたときに不正例外を発生する(訳注:通常、オペレーティングシステムの例外処理が呼び出される)。その後、sNaN は qNaN に変化し、伝播していく。 この機能の使い方はいくつかある。
- 未使用メモリに signaling NaN の値を入れておくと、初期化前にそのデータが使われたときに不正例外が発生するようにできる。
- sNaN をもっと複雑なオブジェクトのプレースホルダーとして使うこともできる。
- 算術アンダーフローとなった数を表現する。
- 算術オーバーフローとなった数を表現する。
- より高い精度フォーマットの数
- 複素数
これらに遭遇するとトラップハンドラは sNaN をデコードして計算結果へのインデックスを返す。 実際にはこの手法は非常に複雑である。 NaN の正負の符号ビットの単純な操作(たとえば絶対値を返す操作)における扱いは通常の算術操作とは異なる。 トラップ処理は規格上は要求されていないので、移植性が問題となる。 このような問題を扱う他の移植性の高い方法がいくつか存在する。
signaling NaN を将来の標準規格でも採用すべきかどうか疑問の声も出ている。
[編集] 関数定義における NaN
数値関数が入力として NaN を受け取ったとき、どう処理すべきかについては様々な意見がある。1つの見方は、NaN はエラーを示すものとして常に出力に伝播させなければならないというものである。別の見方として、その関数に複数の引数があり、NaN でない引数だけで出力値が決定される場合、その値を返すべきだという考え方もある。
例えば、pow(x,y) = x ** y という関数定義があった場合、pow(1, NaN) の値はどうすべきだろうか? 1は何乗しても1だが、NaN乗しても1と言えるのかという問題である。多くの数値計算ライブラリでは、なるべく NaN でない普通の数を返すような方針となっているものが多い。
同様の問題として、無限大との大小比較がある。通常の数は常に無限大より小さい。しかし IEEE 754 では、(NaN <= infinity) は偽となる。
[編集] 整数の NaN
固定ビット幅の整数フォーマットは明確に不正データを示す方法がない。
Perlの BigInt パッケージは正常な整数でないものを表す文字列として "NaN" を使用する。
>perl -mMath::BigInt -e "print Math::BigInt->new('foo')"
NaN
[編集] NaN の表示
各種ライブラリやプログラミング言語は NaN を文字列表記する場合、それぞれ独自の表示となっている。以下にその例を列挙する。
nan NaN NaN% NAN NaNQ NaNS qNaN sNaN 1.#SNAN 1.#QNAN +nan.0 -nan.0 -1.#IND
実際、NaN には符号と診断用の情報(ペイロード)が含まれており、NaN の文字列表記で以下のように表示されることがある。
-NaN NaN12345 -sNaN12300
[編集] NaN の符号化
quiet NaN と signaling NaN の符号上の識別方法は IEEE 754 では規定されていないため、少なくとも2種類の符号化が存在する。IEEE 754rでは仮数部の最上位ビットが 1 なら qNaN、0なら sNaN とされる。こうすると、sNaN のそのビットを反転させて qNaN にしても、その値は NaN のままとなることが保証される。これは、インテルやAMDのプロセッサの符号化方式と同じである。他のプロセッサはこれとは違った符号化方式となっている。
[編集] NA
紛らわしい言葉として、NA(Not availableの意味)がある。「数表のコラムにデータが存在しない場合」に使われ『欠損値』と訳される。 殊に統計計算の分野、R言語など統計解析ソフトウェアで用いられる。NaN==NaNの結果が偽なのに対し、NA==NAの結果はNAである。