IEEE754 NaN 値に対してすべての比較が false を返す理由は何ですか? 質問する

IEEE754 NaN 値に対してすべての比較が false を返す理由は何ですか? 質問する

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

これはある意味で数値計算を簡素化するのだろうと思うが、IEEE 754 の現状に関する講義ノートKahan による、その他の設計上の決定について詳しく説明した論文。

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

編集:これまでの回答はすべて、NaN を比較するのは無意味であると主張しています。

私も同意しますが、これは正解が偽であることを意味するのではなく、むしろ Not-a-Boolean (NaB) になることを意味しますが、幸いなことにそれは存在しません。

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

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

編集 2: NaN を最大にすることがなぜ悪い考えなのかがわかったと思います。上限の計算が混乱するからです。

NaN != NaNは、次のようなループでの収束の検出を避けるために望ましいかもしれません。

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

しかし、絶対差を小さな極限と比較することで記述する方が適切です。したがって、私見では、これは NaN で反射性を破ることに対する比較的弱い議論です。

ベストアンサー1

私は IEEE-754 委員会のメンバーだったので、少しだけ説明してみたいと思います。

まず、浮動小数点数は実数ではなく、浮動小数点演算は実数演算の公理を満たしません。三分法は、浮動小数点数には当てはまらない実数演算の唯一の特性ではなく、最も重要な特性でもありません。たとえば、

  • 加算は結合的ではありません。
  • 分配法則は成り立ちません。
  • 逆数のない浮動小数点数もあります。

まだまだ話は続きます。私たちがよく知っている実数演算のすべての特性を満たす固定サイズの演算型を指定することは不可能です。754 委員会は、それらの特性のいくつかを曲げるか、または破棄するかを決定する必要があります。これは、いくつかの非常に単純な原則によって導かれます。

  1. 可能であれば、実際の算術の動作と一致します。
  2. それができない場合は、違反をできるだけ予測可能にし、診断しやすくするよう努めます。

「正解が偽であることを意味するわけではない」というあなたのコメントは間違っています。述語はが より小さい(y < x)かどうかを尋ねます。 がNaN の場合、どの浮動小数点値 より小さくはないため、答えは必然的に偽になります。yxyx

浮動小数点値には三分法は当てはまらないと述べました。しかし、同様の特性は当てはまります。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))。

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

NaN を取り除く方法がなければ、NaN は CRAY の Indefinites と同じくらい役に立たなくなります。NaN に遭遇したら、計算を無期限に継続して不定の結論に至るよりも、すぐに停止する方がよいでしょう。そのため、NaN に対する一部の操作では、NaN 以外の結果を返さなければなりません。どの操作でしょうか。… 例外は C 述語「 x == x 」および「 x != x 」で、これらはそれぞれ無限数または有限数 x に対して 1 と 0 になりますが、 x が数値でない ( NaN ) 場合は逆になります。これらは、 NaN を表す単語や述語 IsNaN(x) がない言語で、NaN と数値を唯一簡単に区別する手段です。

これは、「Not-A-Boolean」のようなものを返すことを排除するロジックでもあることに注意してください。おそらくこの実用主義は見当違いで、標準では を必須にすべきだったのでしょうisnan( )が、そうすると、プログラミング言語の採用を待つ数年間、NaN を効率的かつ便利に使用することはほぼ不可能になっていたでしょう。それが合理的なトレードオフだったとは思えません。

率直に言うと、NaN == NaN の結果は今のところ変わりません。インターネットで文句を言うよりも、それに慣れる方がよいでしょう。コンテナに適した順序関係も存在すべきだと主張するならお気に入りのプログラミング言語で IEEE-754 (2008) で標準化された述語を実装するよう提唱することをお勧めしますtotalOrder。それがまだ実装されていないという事実は、現在の状況を引き起こした Kahan の懸念の正当性を物語っています。

おすすめ記事