NaN

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

NaNNot a Number、非数、ナン)は、コンピュータにおいて、主に浮動小数点演算の結果として、不正なオペランドを与えられたために生じた結果を表す値またはシンボルである。NaNの体系的仕様は、無限大の表現などと共に1985年の IEEE 754 浮動小数点規格で導入された。

NaNには quiet NaN と signaling NaN の2種類がある。quiet NaN は不正な操作や不正な値で生じる誤りを伝播させるのに使用され、signaling NaN は数値計算と記号計算英語版の混合や基本的な浮動小数点演算への他の拡張といった高度な機能のサポートに使える。例えば結果が実数の範囲内でないゼロ除算において、ゼロ以外のゼロ除算は無限大だが、ゼロのゼロ除算は NaN である。負数の平方根虚数となるため、浮動小数点数としては表現できず、NaN で表現される。他に、正負の無限大の両方が絡んだために、どちらの無限大ともできないような計算の結果も NaN である。また、NaN は計算上必要な値が得られていない場合にも使われることがある[1][2]

数値計算の類似用語としてNAがあるが、まったく異なる概念なので注意を要する。(後述NA参照)

浮動小数点数の NaN[編集]

浮動小数点演算においては、NaNと無限大は別の概念であるが、どちらも浮動小数点数としての表現も特殊であり、それを使った演算も特殊である。不正な演算という概念と算術オーバーフロー(無限大を結果とする場合もある)と算術アンダーフロー(最小の正常な数値か、非正規化数か、ゼロとなる)は異なる。

IEEE 754 の NaN は、指数部は全て1で(無限大と同じ)、仮数部にゼロでない何らかの値を格納している(無限大の場合はゼロ)。仮数部のビット列が任意であるため NaN の値は一意ではないし、先頭の符号ビットで正負の区別がある(個々のNaNの値を常に区別して処理するとは限らない)。

IEEE 754 の単精度(32ビット)での NaN をビット列として表現すると s111 1111 1axx xxxx xxxx xxxx xxxx xxxx となり、ここで s は正負の符号(多くのアプリケーションでは無視する)、a は NaN の種類、x は特殊ペイロード(多くのアプリケーションでは無視する)である。a が 1 の場合は quiet NaN (qNaN) であり、a が 0 でペイロードがゼロでない場合は signaling NaN (sNaN) である[3]

大小比較以外の浮動小数点数操作は一般に quiet NaN をそのまま伝播する。signaling NaN に対する浮動小数点数操作は不正例外を発生し、デフォルトの例外処理ではqNaNをオペランドとしたときと同様に演算結果としてqNaNを生成するだけである。

NaNとの大小比較では、自分自身と比較した場合でも「大小不明な結果」を返す。比較には signaling と non-signaling があり、signaling 版では NaN との比較を行うと不正例外を発生する。等号および不等号で比較する場合は常に non-signaling であり、x が quiet NaN なら x = x は偽 (false) を返す。他の一般的な大小比較は全て signaling であり、オペランドとして NaN を渡されると不正例外を発生するが、規格ではそれらの non-signaling 版も提供することになっている。isNaN(x) は渡された値がNaNかどうかを判定する関数であり、x が signaling NaN であっても例外を発生しない。

quiet NaN が演算を通して伝播していくため、計算途中で何度もチェックを入れる必要はなく、最終的に得られた値を調べればよい。ただし、言語や関数によっては NaN を渡されてもそれが計算結果に影響しない場合に黙って普通の浮動小数点数値を返すことがある。例えばどんな数でも0乗すれば1になるので、NaN^0 は 1 と定義することもできる。そのため一般に最終的な値を得るまでの過程で NaN が入り込んでいたかを示す INVALID フラグを調べる必要がある[4](詳しくは後述の関数定義における NaN節を参照)。

最新の IEEE 754-2008 の6.2節では、2つの異例の関数 maxnumminnum が定義されており(2つの引数のうち大きい方または小さい方を返す)、引数の一方が NaN の場合は常にもう一方の引数を返すようになっている。

同様のコンセプトは GNU OctaveMATLAB のNaNツールボックスに実装されている[5]。NaNツールボックスに含まれる統計関数群(平均、標準偏差などの関数)は、NaNを統計データがないことを示すものとみなし、単に NaN を無視して伝播させない。

NaN を返す演算[編集]

以下の処理で NaN が生成される可能性がある[6]

  • 唯一の引数に NaN を指定された数学関数
  • 不定形英語版
    • 次のような除算: 0/0、±∞/±∞
    • 次のような乗算: 0×±∞、±∞×0
    • 次のような加算(および等価な減算): ∞ + (−∞)、(−∞) + ∞
    • 標準には冪乗が2種類定義されている。
      • pow 関数と冪指数が整数である pown 関数は、00、1、∞0 を 1 と定義している。
      • powr 関数は上記3つの不定形を不正演算と定義しており、NaN を返す。
  • 結果が複素数となるような演算(以下は一部)
    • 負数の平方根
    • 負数の対数
    • -1未満の値や+1より大きい値の逆三角関数

必要な値がないとき、明示的に変数に NaN を代入しておくことがある。IEEE 754 制定以前、未定義値を表すのに特別な値(例えば −99999999)を使うことが多かったが、そういった値が常に想定通りに扱われるとは限らなかった[1]

上記の全ケースで常に NaN が生成されるとは限らない。マスクされていない例外やトラップを発生できる場合、NaNを生成する代わりにトラップを発生させることもある[7]。引数が quiet NaN で signaling NaN ではない場合、例外の発生する条件が成立しておらず quiet NaN を結果として返す。明示的に代入する場合は signaling NaN であっても例外は発生しない。

quiet NaN[編集]

quiet NaN あるいは qNaN は演算過程で伝播していく以外に何も例外などを発生させない。ただし、NaNを出力できない処理の場合は別である。たとえば、フォーマットの変換やある種の比較操作である(NaNが入力されることを想定していない操作)。

signaling NaN[編集]

signaling NaN あるいは sNaN は特殊なNaNであり、多くの操作に入力として用いられたときに不正例外を発生する(通常、オペレーティングシステム例外処理が呼び出される)。その後、sNaN は qNaN に変化し、伝播していく。これは IEEE 754 で導入された。この機能の使い方はいくつかある。

  • 未使用メモリに signaling NaN の値を入れておくと、初期化前にそのデータが使われたときに不正例外が発生するようにできる。
  • sNaN をもっと複雑なオブジェクトのプレースホルダーとして使うこともできる。

これらに遭遇するとトラップハンドラは sNaN をデコードして計算結果へのインデックスを返すこともできる。実際にはこの手法は非常に複雑である。NaN の正負の符号ビットの単純な操作(たとえば絶対値を返す操作)における扱いは通常の算術操作とは異なる。トラップ処理は規格上は要求されていない。このような問題を扱う他の移植性の高い方法がいくつか存在する。

関数定義における NaN[編集]

数値関数が入力として NaN を受け取ったとき、どう処理すべきかについては様々な意見がある。1つの見方は、NaN はエラーを示すものとして常に出力に伝播させなければならないというものである。別の見方として、その関数に複数の引数があり、NaN でない引数だけで出力値が決定される場合、その値を返すべきだという考え方もある。IEEE 754 は主に後者の立場で策定されている。例えば、hypot(±∞, qNaN) と hypot(qNaN, ±∞) は +∞ を返す。

例えば冪乗関数 pow(x,y) = x ** y という関数を考えてみよう。00、∞0、1 といった式は極限を考えると(∞ × 0 などと同様)不定形英語版だが、0の0乗は1と定義すべきだという意見もある。

引数が未定義なら結果も未定義とする場合、pow(1,qNaN) は qNaN を出力すべきである。しかし、一般的な数学ライブラリでは pow(1,y) は任意の実数 y について常に 1 を返す。これは y が無限大であっても同様である。同様に pow(x,0) は x が 0 や無限大であっても 1 を返す。本来不定形であるはずなのに 1 を返す論理的根拠は、ロピタルの定理である。IEEE 754-2008 では、pow(1,qNaN)pow(qNaN,0) はどちらも 1 を返すべきだとされている。

冪乗関数がより厳密な解釈に従うべきだという立場を考慮し、IEEE 754-2008 では他に2つの冪乗関数を定義している。pown(x, n) は冪指数として整数しか指定できない。powr(x, y) は引数のいずれかが NaN の場合や計算結果が不定形になる場合、常に NaN を返す。

整数の NaN[編集]

固定ビット幅の整数フォーマットは明確に不正データを示す方法がない。

Perl の BigInt パッケージは正常な整数でないものを表す文字列として "NaN" を使用する。

 >perl -mMath::BigInt -e "print Math::BigInt->new('foo')" 
 NaN 

JavaScript の parseInt() メソッドは、文字列から整数値への変換に失敗した場合、"NaN" が返却される。

alert(parseInt("10"));
alert(parseInt("abc"));


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(s1234)

これら以外の表示もある。

NaN の符号化[編集]

IEEE 754 の浮動小数点数フォーマットでは、NaN のビットパターンが定義されている。符号ビットはどちらでもよい。指数部は全て1であり(無限大と同じ)、仮数部はゼロでない値(無限大ではゼロ)である。IEEE 754-1985 では signaling NaN と quiet NaN を区別する方法が定義されていなかった。一般に仮数部の最上位ビットで signaling か quiet かを判定していたが、具体的な 1 と 0 の意味付けによって2種類の実装が存在した。

  • 多くのプロセッサ(インテル/AMDx86-32/x86-64ファミリ、モトローラMC68000ファミリ、AIM PowerPCファミリ、Sun SPARCファミリ)では、問題のビットが0でないとき quiet NaN、0のとき signaling NaN と解釈する。したがって、そのビットは 'is_quiet' フラグとして機能する。
  • PA-RISCMIPSの場合、問題のビットが0のときを quiet、0でないときを signaling と解釈する。したがって、そのビットは 'is_signaling' フラグとして機能する。

IEEE 754-2008 では問題のビットの解釈について正式な勧告を追加している。

  • 二進フォーマットの場合、'is_quiet' フラグとして解釈することを標準とする。すなわち、当該ビットが0でない場合は quiet NaN、0の場合は signaling NaN とする。'is-quiet' ビットは仮数部の最上位ビットである。
  • 十進フォーマットの場合、符号ビットに続く5ビットのフィールドを全て1にセットすることでNaNを表す。そして、その直後に 'is_signaling' フラグとなるビットがある。すなわち、当該ビットが0であれば quiet NaN、1であれば signaling NaN と解釈される。

qNaN/sNaNであることを示すために値が定義されているビットを除くと、標準では特に何も定義されていない(ただし、仮数部が全て0の場合は無限大と解釈される)。これをNaNの「ペイロード」と呼び、デバッグのために、出力がqNaNとなった操作で1つ目のqNaNの引数のペイロードをそのまま伝播させることを推奨している。

NA[編集]

紛らわしい言葉として、NA(Not availableの意味、N/Aとも表記される)がある。「数表のコラムにデータが存在しない場合」に使われ『欠損値』と訳される。 殊に統計計算の分野、R言語など統計解析ソフトウェアで用いられる。NaN==NaNの結果が偽なのに対し、NA==NAの結果はNAである。

脚注[編集]

  1. ^ a b Bowman, Kenneth (2006) An introduction to programming with IDL: Interactive Data Language. Academic Press. p. 26 ISBN 0-12-088559-X
  2. ^ William H. Press, Saul A. Teukolsky, William T. Vetterling (2007) Numerical recipes: the art of scientific computing.p. 34 Cambridge University Press, ISBN 0-521-88068-8
  3. ^ a もペイロードもゼロなら「無限大」である。
  4. ^ William Kahan (1997年10月1日). “Lecture Notes on the Status of IEEE Standard 754 for Binary Floating-Point Arithmetic”. 2012年3月31日閲覧。
  5. ^ NaN 'toolbox'
  6. ^ David Goldberg. “What Every Computer Scientist Should Know About Floating-Point”. 2012年3月31日閲覧。
  7. ^ Intel 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture”. pp. 118–125, 266–267, 334–335 (2008年4月). 2012年3月31日閲覧。

外部リンク[編集]