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


267

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

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

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

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

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

したがって、比較に対してtrueまたはfalseを返すかどうかの選択は、私の見解では任意であり、一般的なデータ処理では、データ構造を考慮せずに、通常の法則(==の再帰性、<、==、>のトリコトミー)に従うと有利です。これらの法律に依存するものは混乱します。

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

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

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

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

ただし、絶対的な違いを小さな制限と比較することで記述します。だから私見これはNaNで反射性を壊すための比較的弱い議論です。


2
NaNが計算に入ると、通常、NaNが終了することはないため、収束テストは無限ループになります。通常は、NaNを返すことにより、呼び出しルーチンに収束できないことを報告することをお勧めします。したがって、ループ構造は通常、のようになりwhile (fabs(x - oldX) > threshold)、収束が発生するかNaNが計算に入るとループを終了します。NaNの検出と適切な対策は、ループの外側で行われます。
スティーブンキャノン

1
NaNが、whileループが機能する順序の最小要素である場合。
starblue 2013年

回答:


535

私はIEEE-754委員会のメンバーだったので、少しわかりやすくするように努めます。

まず、浮動小数点数は実数ではなく、浮動小数点演算は実数演算の公理を満たしていません。トリコトミーは、浮動小数点数に当てはまらない実際の算術の唯一の特性ではなく、最も重要なものですらありません。例えば:

  • 加算は関連付けされていません。
  • 分配法は成立しません。
  • 逆のない浮動小数点数があります。

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

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

「正解が間違っているわけではない」というコメントについては、これは誤りです。述語(y < x)は、yがより小さいかどうかを尋ねxます。場合はyNaNである、それはありません以下の任意の浮動小数点値よりもx、その答えは必然的に偽です。

トリコトミーは浮動小数点値には当てはまらないと述べました。ただし、同様のプロパティが保持されます。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( )、当時、NaNが8087の算術演算で公式化されたという述語はありませんでした。isnan( )何年もかかるようなプログラミング言語に依存しないNaN値を検出する便利で効率的な手段をプログラマーに提供する必要がありました。この件に関するKahan自身の文章を引用します。

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


16
私はあなたのポイント1と2を読みました。次に、実際の算術(最初にNaNを許可するように拡張された)でNaNはそれ自体に等しいことを観察しました。ここで私は混乱しています。なぜIEEEは「実際の算術の動作に一致しない」のですか。NaN== NaNになりますか?何が欠けていますか?
最大

12
同意した NaNの非反射性により、Pythonのような言語に平等性に基づいた包含のセマンティクスにより、痛みの終わりはありません。その上にコンテナーを構築しようとしているときに、等価性が等価関係にならないことを本当に望んでいません。そして、平等の2つの別々の概念を持っていることも、学習しやすいはずの言語にとって、あまり友好的な選択肢ではありません。結果(Pythonの場合)は、IEEE 754の尊重とあまりにも壊れていない封じ込めセマンティクスとの間の不愉快な脆弱性の妥協です。幸い、NaNをコンテナーに入れることはまれです。
Mark Dickinson

5
ここにいくつかの素晴らしい観察があります:bertrandmeyer.com/2010/02/06/…–
Mark Dickinson

6
@StephenCanon:(0/0)==(+ INF)+(-INF)はどういう意味で無意味1f/3f == 10000001f/30000002fですか?浮動小数点値が等価クラスであると見なされる場合、a=b「生成された計算ab、無限の精度で実行された場合、同じ結果が生成される」という意味ではなく、「既知のaものと既知のものとが一致する」b」「Nan!= NaN」を使用すると、そうでない場合よりも物事が簡単になるコードの例を知っているかどうか知りたいのですが。
スーパーキャット2013

5
理論的には、NaN == NaNがあり、isNaNがない場合でも、でNaNをテストできます!(x < 0 || x == 0 || x > 0)が、それよりも遅くて不格好でしたx != x
user2357112は、

50

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

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

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


5
sqrt(1.00000000000000022)== sqrt(1.0)の結果はどうなりますか?(1E308 + 1E308-1E308-1E308-1E308)==(1E308 + 1E308)はどうですか?また、6つの比較のうち5つだけがfalseを返します。!=オペレータはtrueを返します。たNaN==NaNNaN!=NaNの両方のリターン偽しても、xを比較したコードとyが両方のオペランドがどちらかを選択することにより、NaNであるときにどうするかを選択できるようになります==!=
スーパーキャット2013年

38

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

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


6
すべての空のセットは、定義により等しいです。
MSalters 2009年

28
あなたが与えられたボックスが空であることは知られていません。
John Smith、

7
箱に同じものが入っていないことを教えていただけますか?の根拠を理解できます(NaN==Nan)==false。私が理解していないのは、の根拠です(Nan!=Nan)==true
スーパーキャット2014

3
x!= yは!(x == y)と定義されているため、NaN!= NaNはtrueであると思います。確かに、IEEE仕様でそのように定義されているかどうかはわかりません。
Kef Schecter 2014年

6
しかし、この例えで、あなたが私に箱を与えた場合、それがリンゴを含んでいないと言って、それがそれ自体と等しいかどうか尋ねた場合、あなたは私がノーと言うと期待しますか?それはIEEEによると私が言わなければならないことだからです。
セミコロン

12

NaNに関するウィキペディアの記事から、以下の慣行がNaNを引き起こす可能性があります。

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

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


3
また、どの操作を知っていても役に立たないでしょう。ある時点で0/0に到達する数式をいくつでも作成できます。その数式は、(連続性を想定している場合)明確に定義され、その時点で異なる値になります。
David Thornley、

4

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

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


2

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結果に悩まされています。


1

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

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

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


3
「これは数ではないので、それを比較しても意味がありません。」文字列は数値ではありませんが、それらを比較することには意味があります。
ジェイソン、

2
はい、文字列を文字列と比較することには意味があります。しかし、文字列をたとえばりんごと比較しても、あまり意味がありません。リンゴとナシは数字ではないので、それらを比較することは理にかなっていますか?どちらが大きいですか?
ダレントーマス

@DarenThomas:SQLでは、「IF NULL = NULL THEN FOO;」のどちらもありません。また、「IF Null <> Null THEN CALL FOO;」でもありません。[または構文が何であれ]が実行されFOOます。NaNが同等でif (NaN != NaN) foo();あるためにはfoo、実行すべきではありませんが、実行されます。
スーパーキャット2013年

1

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

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


0

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


-1

私にとって、それを説明する最も簡単な方法は:

私は何かを持っています、そしてそれがリンゴでなければ、それはオレンジですか?

NaNには値がないため、NaNを他のもの(それ自体であっても)と比較することはできません。また、任意の値にすることができます(数値を除く)。

私は何かを持っていて、それが数字と等しくない場合、それは文字列ですか?


「数値以外の任意の値にすることができます」とはどういう意味ですか?
プーシキン

-2

数学は数字が「ただ存在する」分野だからです。コンピューティングでは、これらの数値を初期化し、必要に応じてその状態を維持する必要があります。昔は、メモリの初期化は、信頼できない方法で機能していました。「ああ、それは常に0xCDで初期化されるので、私のアルゴは壊れないでしょう」と考えることは決してできません

したがって、アルゴリズムが吸い込まれて壊れないように十分粘着性がある適切な非混合溶媒が必要です。数値を含む優れたアルゴリズムは、主にリレーションで機能し、それらのif()リレーションは省略されます。

これは、コンピュータメモリからランダムな地獄をプログラミングする代わりに、作成時に新しい変数に入れることができるグリースです。そして、それが何であれ、あなたのアルゴリズムは壊れません。

次に、アルゴリズムがNaNを生成していることを突然突然見つけた場合、一度に1つずつすべてのブランチを調べて、それをクリーンアップすることが可能です。繰り返しますが、「常に偽」のルールは、これに大きく貢献しています。


-4

非常に短い答え:

次の理由により、 nan / nan = 1 保持してはなりません。それ以外の場合inf/infは1になります。

(したがってnanに等しくすることができないnan。として>または<、場合nanアルキメデスの性質を満たす組における任意の順序関係を尊重することになる、我々は再びなければならないnan / nan = 1限界で)。


2
いいえ、それは意味がありません。我々は持っているinf = infinf / inf = nan、そうnan = nan防ぐことはできませんnan / nan = nanどちらか。
starblue

@starblueという意味nan / nan = 1ですか?とにかく... infとnanが他の数値と同じである場合、あなたの推論は理にかなっています。そうではありません。でinf/infなければならないnan(または数学では不定形)理由は1、単純な代数操作(De L'Hospitalの定理を参照)よりも微妙です。
SeF 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.