320

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

これにより数値計算が何らかの形で単純化されると思いますが、他の設計上の決定について詳細に説明しているKahanによるIEEE 754のステータスに関する講義ノートでも、明確に述べられた理由を見つけることができませんでした。

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

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

私は同意しますが、それは正解が間違っていることを意味するのではなく、幸いにも存在しないNot-a-Boolean(NaB)になります。

したがって、比較のためにtrueまたはfalseを返すという選択は、私の見解では恣意的であり、一般的なデータ処理では、データ構造を避けるために、通常の法則(==の再帰性、<、==、>の三分法)に従った場合に有利です。これらの法律に依存しているものは混乱します。

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

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

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

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

ただし、これは絶対差を小さな制限と比較することによって記述したほうがよいでしょう。したがって、私見では、これはNaNでの再帰性を破るための比較的弱い議論です。

4

11 に答える 11

656

私は IEEE-754 委員会のメンバーでした。少し説明を手伝おうと思います。

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

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

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

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

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

三分法は浮動小数点値には当てはまらないと述べました。ただし、保持される同様のプロパティがあります。754-2008 規格の第 5.11 項、パラグラフ 2:

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

NaN を処理するための追加コードを作成する限り、NaN が適切に通過するようにコードを構成することは通常 (常に簡単ではありませんが) 可能ですが、常にそうであるとは限りません。そうでない場合は、追加のコードが必要になる場合がありますが、代数的閉包が浮動小数点演算にもたらした利便性を考えると、それはわずかな代償です。


補遺: 多くのコメンテーターは、NaN != NaN を採用してもおなじみの公理が維持されないように見えるという理由で、平等と三分法の再帰性を維持する方がより有用であると主張しています。私はこの観点に共感を持っていることを告白するので、この回答を再検討して、もう少し背景を説明したいと思いました.

NaN != NaN は、次の 2 つの実用的な考慮事項から生じたものであるということを、Kahan との会話から理解しました。

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

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

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

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

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

于 2009-10-15T17:00:03.807 に答える
58

NaNは、未定義の状態/数と考えることができます。0/0が未定義またはsqrt(-3)であるという概念に似ています(浮動小数点が存在する実数システムの場合)。

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

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

于 2009-10-14T09:38:00.980 に答える
47

さらに別のアナロジーを投入します。2 つの箱を渡して、どちらにもリンゴが入っていないと言ったら、箱には同じものが入っていると教えてくれますか?

NaN には、何かについての情報は含まれず、そうでないものだけが含まれます。したがって、これらの要素は決して等しいとは言えません。

于 2009-10-14T09:41:39.890 に答える
14

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

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

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

于 2009-10-14T09:41:51.857 に答える
5

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

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

于 2009-10-14T13:57:38.517 に答える
2

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

  • (2.7 == 2.7) = 真
  • (2.7 == 2.6) = 偽
  • (2.7 == NaN) = 不明
  • (NaN == NaN) = 不明

.NET でさえ演算子を提供していないため、bool? operator==(double v1, double v2)依然としてばかげた(NaN == NaN) = false結果が得られます。

于 2009-10-14T10:59:21.943 に答える
2

NaN (Not A Number) はまさにそれを意味していると思います。これは数値ではないため、比較してもあまり意味がありません。

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

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

于 2009-10-14T09:26:04.257 に答える
1

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

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

于 2009-10-15T17:54:27.237 に答える
0

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

于 2014-05-18T19:22:17.333 に答える