152

関連する IEEE 標準では、数値定数 NaN (数値ではない) が定義されており、NaN はそれ自体と等しくないと比較する必要があると規定されています。何故ですか?

私がよく知っているすべての言語は、このルールを実装しています。しかし、NaN がコンテナに格納されているとき、NaN がソートされているデータ内にあるときなどの予期しない動作など、重大な問題を引き起こすことがよくあります。彼らが NaN について学ぶ前に)、彼らを驚かせることはバグと混乱を助長します。

IEEE 標準はよく考えられているので、NaN がそれ自体と等しいと比較するのが良くないのには十分な理由があると確信しています。私はそれが何であるかを理解することはできません。

編集: IEEE754 NaN 値に対して false を返すすべての比較の根拠は何ですか?を参照してください。正式な回答として。

4

6 に答える 6

183

受け入れられた答えは、間違いなく 100%です。中途半端でも、少しでも間違っているわけではありません。この問題は、検索でこの質問が表示されたときに、長い間プログラマーを混乱させ、誤解を招くことになるのではないかと心配しています。

NaN はすべての計算に伝播し、ウイルスのように感染するように設計されているため、深層部の複雑な計算のどこかで NaN に遭遇したとしても、一見まともな答えを出すことはできません。それ以外の場合、恒等式 NaN/NaN は、(NaN/NaN)==1、(NaN*1)==NaN などの他のすべての結果とともに 1 に等しくなる必要があります。分母がゼロ、NaN が生成される) などの場合、計算から非常に不正確な (またはさらに悪いことに、微妙に不正確な) 結果が得られる可能性がありますが、その理由についての明確な指標はありません。

また、数学関数の値をプローブする際の計算で NaN が使用されるのには、十分な理由があります。リンクされたドキュメントに示されている例の 1 つは、関数 f() の zeros() を見つけることです。推測値を使用して関数を調べる過程で、関数 f() が適切な結果をもたらさない場所を調べる可能性は十分にあります。これにより、zeros() は NaN を認識して作業を続行できます。

NaN に代わる方法は、不正な操作 (シグナルまたはトラップとも呼ばれる) が発生するとすぐに例外をトリガーすることです。発生する可能性のある大幅なパフォーマンスの低下に加えて、当時、CPU がハードウェアでそれをサポートするか、OS/言語がソフトウェアでそれをサポートするかという保証はありませんでした。誰もが浮動小数点を処理する独自のスノーフレークでした。IEEE は、ソフトウェアで NaN 値として明示的に処理することを決定したため、任意の OS またはプログラミング言語に移植できます。node.js であろうと COBOL であろうと、正しい浮動小数点アルゴリズムは通常、すべての浮動小数点実装で正しいものです (笑)。

理論的には、特定の #pragma ディレクティブを設定したり、クレイジーなコンパイラ フラグを設定したり、正しい例外をキャッチしたり、特別なシグナル ハンドラーをインストールしたりして、同一のアルゴリズムのように見えるものを実際に正しく動作させる必要はありません。残念ながら、一部の言語設計者とコンパイラ作成者は、この機能を最大限に元に戻すのに非常に忙しくしています。

IEEE 754 浮動小数点の歴史に関する情報の一部をお読みください。また、委員会のメンバーが回答した同様の質問に対するこの回答: IEEE754 NaN 値に対して false を返すすべての比較の根拠は何ですか?

「浮動小数点オヤジインタビュー」

「IEEE浮動小数点形式の歴史」

すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと

于 2014-05-14T23:06:12.737 に答える
116

さて、log(-1)を与えるNaN、そしてacos(2)また与えるNaN。それはそれを意味しlog(-1) == acos(2)ますか?明らかにそうではありません。NaNしたがって、それ自体と等しくないことは完全に理にかなっています。

ほぼ2年後にこれを再検討すると、「NaNセーフ」比較関数があります。

function compare(a,b) {
    return a == b || (isNaN(a) && isNaN(b));
}
于 2012-04-05T18:45:18.907 に答える
34

私の最初の答え(4年前から)は、決定がなされた文脈を理解することなく、現代の観点から決定を批判しています。このように、それは質問に答えません。

正解はここにあります

NaN!= NaN2つの実用的な考慮事項から生じました:

[...] isnan( )NaNが8087算術で形式化された時点では、述語はありませんでした。プログラミング言語に依存せず、isnan( )何年もかかる可能性のあるようなものを提供するNaN値を検出する便利で効率的な手段をプログラマーに提供する必要がありました。

このアプローチには1つの欠点がありました。それは、数値計算とは関係のない多くの状況でNaNの有用性が低下したことです。たとえば、ずっと後になって、人々がNaN欠落している値を表現し、それらをハッシュベースのコンテナに入れたいと思ったとき、彼らはそれを行うことができませんでした。

委員会が将来のユースケースを予見し、それらが十分に重要であると考えた場合、それらはのテストとしてでは!(x<x & x>x)なく、より冗長なものに移行することができたはずです。しかし、彼らの焦点はより実用的で狭いものでした。数値計算に最適なソリューションを提供するため、アプローチに問題はありませんでした。x!=xNaN

===

元の答え:

申し訳ありませんが、トップ投票の回答に寄せられた考えに感謝しますが、私はそれに同意しません。NaNは「未定義」を意味するものではありません。7ページのhttp://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDFを参照してください(「未定義」という単語を検索してください)。そのドキュメントが確認しているように、NaNは明確に定義された概念です。

さらに、IEEEのアプローチは、可能な限り通常の数学の規則に従うことでした。それができなかった場合は、「驚き最小の原則」の規則に従います。https://stackoverflow.com/a/1573715/336527を参照してください。すべての数学的対象はそれ自体と等しいので、数学の規則は、NaN==NaNが真でなければならないことを意味します。そのような主要な数学的原理から逸脱する正当で強力な理由はわかりません(比較の三分法などのそれほど重要ではない規則は言うまでもありません)。

その結果、私の結論は次のようになります。

IEEE委員会のメンバーは、これを明確に考えていなかったため、間違いを犯しました。IEEE委員会のアプローチを理解したり、NaNについて標準が正確に何を言っているかを気にかけている人はほとんどいなかったので(つまり、ほとんどのコンパイラによるNaNの扱いはIEEE標準に違反しています)、誰も警告を発しませんでした。したがって、この間違いは現在、標準に組み込まれています。このような修正は既存のコードの多くを壊してしまうため、修正される可能性は低いです。

編集:これは非常に有益な議論からの1つの投稿です。注:Guidoは他のコア開発者とは異なる見方をしているため、偏りのない見方を得るには、スレッド全体を読む必要があります。ただし、Guidoはこのトピックに個人的に興味を持っておらず、TimPetersの推奨事項にほぼ従っています。ティム・ピーターズの主張に賛成する人がいる場合はNaN != NaN、コメントに追加してください。彼らは私の意見を変える良いチャンスがあります。

于 2012-04-08T01:50:42.900 に答える
13

優れたプロパティは次のとおりです。falsex == xを返す場合、xNaN.

(このプロパティを使用して、そうxであるNaNかどうかを確認できます。)

于 2012-04-05T18:47:27.867 に答える
9

これを試して:

var a = 'asdf';
var b = null;

var intA = parseInt(a);
var intB = parseInt(b);

console.log(intA); //logs NaN
console.log(intB); //logs NaN
console.log(intA==intB);// logs false

intA == intB が true の場合、a==b と結論付ける可能性がありますが、明らかにそうではありません。

別の見方をすれば、NaN は、それが何かではなく、何が ISN'T でないかについての情報を提供するだけだということです。たとえば、「リンゴはゴリラではない」「オレンジはゴリラではない」と言ったら、「リンゴ」==「オレンジ」という結論になりますか?

于 2013-04-02T12:43:06.867 に答える
2

実際、数学には「統一」値として知られる概念があります。これらの値は、システム内の範囲外の問題を調整するために慎重に構築された拡張機能です。たとえば、複素平面の無限大のリングは、点または点のセットであると考えることができ、以前は大げさだった問題がいくつかなくなります。| P(A)|である限り、無限の連続体の構造を選択できることを示すことができる集合のカーディナリティに関して、これの他の例があります。> | A | そして何も壊れません。

免責事項:私は数学の勉強中にいくつかの興味深い警告の漠然とした記憶を使って作業しているだけです。私が上でほのめかした概念を表現するというひどい仕事をしたならば、私は謝罪します。

NaNが単独の値であると信じたい場合は、等式演算子が期待どおりに機能しないなど、結果の一部に不満を感じる可能性があります。ただし、NaNが孤立したプレースホルダーによって表される「悪さ」の連続体であると信じることを選択した場合は、等式演算子の動作に完全に満足しています。言い換えれば、あなたは海で捕まえた魚を見失いますが、同じように見えるが同じように臭い別の魚を捕まえます。

于 2013-03-19T18:54:26.340 に答える