web-dev-qa-db-ja.com

IEEE754 NaN値に対してfalseを返すすべての比較の根拠は何ですか?

NaN値の比較が他のすべての値と異なる動作をするのはなぜですか?つまり、1つまたは両方の値がNaNである演算子==、<=、> =、<、>とのすべての比較は、他のすべての値の動作に反してfalseを返します。

私はこれが何らかの方法で数値計算を簡素化すると思いますが、他の設計決定を詳細に議論するKahanによる IEEE 754のステータスに関する講義ノート でさえ、明示的に述べられた理由を見つけることができませんでした。

この逸脱した動作は、単純なデータ処理を行うときに問題を引き起こしています。たとえば、レコードw.r.tのリストをソートする場合。 Cプログラムの一部の実数値フィールドでは、NaNを最大要素として処理する追加のコードを記述する必要があります。そうしないと、ソートアルゴリズムが混乱する可能性があります。

Edit:これまでの答えはすべて、NaNを比較することは無意味だと主張しています。

私は同意しますが、それは正しい答えが偽であることを意味するのではなく、幸いなことに存在しないブールではない(NaB)であることを意味します。

したがって、比較のためにtrueまたはfalseを返す選択は任意であり、一般的なデータ処理では、通常の法則(==の反射率、<、==、>の三分法)、データ構造を守れば有利ですこれらの法律に依存していると混乱します。

ですから、哲学的な推論だけでなく、これらの法律を破ることの具体的な利点を求めています。

編集2:NaNを最大にすることが悪い考えであり、上限の計算を台無しにするのはなぜか、今理解できたと思います。

NaN!= NaNは、次のようなループでの収束の検出を避けるために望ましい場合があります。

while (x != oldX) {
    oldX = x;
    x = better_approximation(x);
}

ただし、絶対差と小さな制限を比較することで、より適切に記述する必要があります。だから私見、これはNaNで反射性を破るための比較的弱い議論です。

234
starblue

私はIEEE-754委員会のメンバーでしたが、物事を少し明確にする手助けをしようと思います。

まず、浮動小数点数は実数ではなく、浮動小数点演算は実数演算の公理を満たしていません。三分法は、浮動小数点数を保持しない実際の算術演算の唯一のプロパティではなく、最も重要なプロパティでもありません。例えば:

  • 加算は結合的ではありません。
  • 分配法は適用されません。
  • 逆数のない浮動小数点数があります。

続けられた。私たちが知っていて愛している実際の算術の特性のallを満たす固定サイズの算術型を指定することはできません。 754委員会は、それらのいくつかを曲げるか破るかを決定しなければなりません。これは、いくつかの非常に単純な原則に基づいています。

  1. 可能な場合は、実際の算術の動作を一致させます。
  2. できない場合は、違反を可能な限り予測可能で簡単に診断できるようにします。

「正解が間違っているという意味ではありません」というコメントについては、これは間違っています。述語_(y < x)_は、yxより小さいかどうかを尋ねます。 yがNaNの場合、浮動小数点値xよりもnotより小さいため、答えは必ずfalseです。

三分法は浮動小数点値には当てはまらないと述べました。ただし、同様のプロパティがあります。 754-2008標準の5.11項、2項:

4つの相互に排他的な関係が可能です:より小さい、等しい、より大きい、および順序なし。最後のケースは、少なくとも1つのオペランドがNaNの場合に発生します。すべてのNaNは、順不同で、それ自体を含むすべてと比較します。

NaNを処理するための追加のコードを記述する限り、NaNが適切に処理されるようにコードを構造化することは(常に簡単ではありませんが)通常可能ですが、常にそうであるとは限りません。そうでない場合は、追加のコードが必要になる場合がありますが、代数的閉包が浮動小数点演算にもたらした利便性のために支払うには少額の費用がかかります。


補遺:多くのコメント者は、NaN!= NaNを採用することはおなじみの公理を保持しないようであるという理由で、平等と三分法の反射性を保持することがより有益であると主張しています。私はこの視点に同情を持っていることを認めたので、私はこの答えを再考し、もう少し文脈を提供すると思った。

Kahanと話すことからの私の理解は、NaN!= NaNは2つの実用的な考慮事項から生まれたということです。

  • _x == y_は、可能な場合はいつでも_x - y == 0_と同等である必要があります(実際の算術の定理である以外に、これにより比較のハードウェア実装がよりスペース効率になり、標準が開発された時点で最も重要でした)ただし、これはx = y =無限の場合に違反するため、それ自体は大きな理由ではなく、合理的に_(x - y == 0) or (x and y are both NaN)_)に曲げられている可能性があることに注意してください。

  • さらに重要なことは、NaNが8087算術で形式化された時点ではisnan( )述語がなかったことです。プログラマーにNaN値を検出する便利で効率的な手段を提供する必要がありました。NaN値はisnan( )のようなものを提供するプログラミング言語に依存していませんでした。このテーマに関するカハン自身の文章を引用します。

NaNを取り除く方法がなければ、CRAYのIndefinitesと同じくらい役に立たなくなります。遭遇するとすぐに、計算は不定の結論に至るまで無期限に継続されるのではなく、最適に停止されます。そのため、NaNに対する一部の操作では、NaN以外の結果を提供する必要があります。どの操作ですか? …例外はC述語“ x == x”および“ x!= x”です。これらはそれぞれ無限または有限の数xに対してそれぞれ1と0ですが、xが非数(NaN)の場合は逆になります。これらは、NaNの単語と述語IsNaN(x)を欠く言語で、NaNと数字の間の唯一の単純な例外のない区別を提供します。

これは、「Not-A-Boolean」のようなものを返すことを除外するロジックでもあることに注意してください。たぶん、このプラグマティズムは見当違いであり、標準はisnan( )を必要とするはずでしたが、それはプログラミング言語の採用を待っている間、NaNを数年間効率的かつ便利に使用することをほぼ不可能にしました。私はそれが合理的なトレードオフだとは確信していません。

率直に言って、NaN == NaNの結果は今は変わりません。インターネットで文句を言うよりも、一緒に暮らすことを学ぶ方が良い。コンテナに適した順序関係がalsoであると主張したい場合、お気に入りのプログラミング言語がtotalOrderを実装することを提言することをお勧めします。 IEEE-754(2008)で標準化された述語。それが、現在の情勢を動機付けたカハンの懸念の妥当性をまだ語っていないという事実。

471
Stephen Canon

NaNは、未定義の状態/番号と考えることができます。 0/0が未定義またはsqrt(-3)(浮動小数点が存在する実数系)の概念に似ています。

NaNは、この未定義の状態のプレースホルダーの一種として使用されます。数学的に言えば、undefinedはundefinedと等しくありません。また、未定義の値が別の未定義の値より大きい、または小さいと言うこともできません。したがって、すべての比較はfalseを返します。

この動作は、sqrt(-3)とsqrt(-2)を比較する場合にも有利です。どちらもNaNを返しますが、同じ値を返しても同等ではありません。したがって、NaNを扱うときに常に等値がfalseを返すことが望ましい動作です。

49
Chris

さらに別の例えを投げかけます。 2つの箱を渡して、どちらにもAppleが入っていないことを伝えたら、箱には同じものが入っていると教えてくれますか?

NaNには、何かとは何かという情報は含まれていません。したがって、これらの要素が絶対に等しいとは決して言えません。

33
Jack Ryan

NaN に関するウィキペディアの記事から、次のプラクティスがNaNを引き起こす可能性があります。

  • すべての数学演算>少なくとも1つのオペランドとしてNaNを使用
  • 除算0/0、∞/∞、∞/-∞、-∞/∞、および-∞/-∞
  • 乗算0×∞および0×-∞
  • 加算∞+(-∞)、(-∞)+∞および同等の減算。
  • ドメイン外の引数に関数を適用します。負数の平方根の取得、負数の対数の取得、90度の奇数倍(またはπ/ 2ラジアン)の正接の取得、逆正弦の取得などがあります。または、-1未満または+1より大きい数値のコサイン。

これらの操作のどれがNaNを作成したかを知る方法はないため、それらを比較して意味のある方法はありません。

12
Stefan Rusek

設計の根拠はわかりませんが、IEEE 754-1985標準からの抜粋です。

「オペランドの形式が異なっていても、サポートされているすべての形式の浮動小数点数を比較できます。比較は正確であり、オーバーフローやアンダーフローはありません。4つの相互排他的な関係が可能です。最後のケースは、少なくとも1つのオペランドがNaNの場合に発生します。すべてのNaNは、順序付けられていないものとそれ自体を含むすべてのものを比較します。」

4
Rick Regan

NaNを許可するほとんどのプログラミング環境では3値のロジックも許可しないため、奇妙に見えるだけです。 3値のロジックをミックスに投入すると、一貫したものになります。

  • (2.7 == 2.7)= true
  • (2.7 == 2.6)= false
  • (2.7 == NaN)=不明
  • (NaN == NaN)=不明

.NETでさえbool? operator==(double v1, double v2)演算子を提供していないため、愚かな(NaN == NaN) = false結果。

2

NaN(Not A Number)は正確に次のことを意味すると推測しています:これは数値ではないため、比較することは実際には意味がありません。

nullオペランドを使用したSQLの算術演算に少し似ています。これらはすべてnullになります。

浮動小数点数の比較では、数値が比較されます。したがって、数値以外には使用できません。したがって、NaNは数値的に比較することはできません。

1
Daren Thomas

単純化した答えは、NaNには数値がないため、他の何かと比較するものは何もないということです。

NaNを+ INFのように動作させたい場合は、NaNをテストし、+ INFに置き換えることを検討してください。

1
David R Tribble

NaNと任意の実数の比較は順序付けられていないことに同意しますが、NaNをそれ自体と比較するだけの理由があると思います。たとえば、シグナルNaNとクワイエットNaNの違いをどのように発見しますか?信号をブール値(ビットベクトル)のセットと考えると、ビットベクトルが同じか異なるかを尋ね、それに応じてセットを並べることができます。たとえば、最大バイアス指数のデコード時に、仮数の最上位ビットをバイナリ形式の最上位ビットに合わせるように仮数を左にシフトすると、負の値は静かなNaNになり、正の値はシグナルNaNである。もちろん、ゼロは無限大のために予約されており、比較は順序付けられません。 MSBアライメントにより、異なるバイナリ形式からの信号を直接比較できます。したがって、同じ信号セットを持つ2つのNaNは同等であり、同等であることを意味します。

0

NaNは、(特別な種類のランタイムエラーの)暗黙的な新しいインスタンスです。つまり、NaN !== NaN_と同じ理由で_new Error !== new Error_;

また、このような暗黙性はエラーの外でも見られます。たとえば、正規表現のコンテキストでは、new RegExp('a') !== new RegExp('a')の単なる構文糖である_/a/ !== /a/_を意味します

0