`Vector <float> .Equals`は再帰的である必要がありますか、それともIEEE 754セマンティクスに従う必要がありますか?


9

浮動小数点値が等しいかどうかを比較する場合、2つの異なる方法があります。

  • NaN一致する、それ自体に等しくないIEEE 754仕様。
  • NaN等価関係の定義に不可欠な反射性の数学的特性を提供する、それ自体に等しい

C#(にIEEE浮動小数点型に内蔵floatし、doubleIEEEのためのセマンティクス従う)==及び!=(等リレーショナル演算子<)が、ための反射性を確保しobject.EqualsIEquatable<T>.Equals(およびCompareTo)。

ここで、float/の上にベクター構造体を提供するライブラリについて考えますdouble。このようなベクトル型は過負荷になり==/ !=およびオーバーライドobject.Equals/ IEquatable<T>.Equals

何皆に同意すると、そのある==/ !=IEEEセマンティクスに従ってください。問題は、そのようなライブラリーがEquals再帰的な方法で、またはIEEEセマンティクスに一致する方法で(等価演算子とは別の)メソッドを実装するかどうかです。

のIEEEセマンティクスを使用するための引数Equals

  • IEEE 754に準拠
  • SIMD命令を利用できるため、(おそらくはるかに)高速です。

    私は、スタックオーバーフローについて、SIMD命令を使用して再帰的等式をどのように表現するか、およびそれらのパフォーマンスへの影響について、別の質問をしました。浮動小数点の等値比較のためのSIMD命令

    更新: 3つのSIMD命令を使用して効率的に再帰的等式を実装できるようです。

  • のドキュメントでEqualsは、浮動小数点を使用する場合に再帰性は必要ありません。

    次のステートメントは、Equals(Object)メソッドのすべての実装に当てはまる必要があります。リストには、xy、およびznullではないオブジェクト参照を表します。

    x.Equals(x)true浮動小数点型を含む場合を除いて、を返します。ISO / IEC / IEEE 60559:2011、情報技術-マイクロプロセッサシステム-浮動小数点演算を参照してください。

  • floatを辞書のキーとして使用している場合は、罪の状態にあり、正常な動作を期待するべきではありません。

再帰的であるという主張:

  • それはを含む既存のタイプと一致だSingleDoubleTupleSystem.Numerics.Complex

    Equals再帰的ではなく、IEEEに従うBCLの前例は知りません。カウンターの例としてはSingleDoubleTupleSystem.Numerics.Complex

  • Equals主に、反射性に依存するコンテナと検索アルゴリズムで使用されます。これらのアルゴリズムでは、動作を妨げる場合、パフォーマンスの向上は重要ではありません。パフォーマンスの正確さを犠牲にしないでください。
  • これは、すべてのハッシュベースのセットや辞書、壊れるContainsFindIndexOfさまざまなコレクション/ LINQ、セットベースのLINQの操作(上UnionExceptデータが含まれている場合など)NaNの値を。
  • IEEEセマンティックが受け入れられる実際の計算を行うコードは、通常、具象型で機能し、==/ !=(またはより可能性の高いイプシロン比較)を使用します。

    ジェネリック演算が必要なため、現在ジェネリックを使用して高性能計算を作成することはできませんが、これらはインターフェース/仮想メソッドを介して利用できません。

    したがって、遅いEqualsメソッドはほとんどの高性能コードに影響を与えません。

  • IEEEセマンティクスが必要な場合、またはパフォーマンス上の利点が必要な場合に、IeeeEqualsメソッドまたはを提供するIeeeEqualityComparer<T>ことができます。

私の意見では、これらの議論は再帰的な実装を強く支持しています。

MicrosoftのCoreFXチームは、そのようなベクトル型を.NETに導入することを計画しています。私とは異なり、彼らは主にパフォーマンス上の利点のために、IEEEソリューションを好みます。このような決定は最終リリース後も変わらないので、大きな間違いだと私が信じていることについてコミュニティからフィードバックを得たいと思います。


1
優秀で考えさせられる質問。(少なくとも)私にとって、それはという意味がありません==し、Equals異なる結果を返すでしょうが。多くのプログラマーはそうであると想定、同じことをします。さらに-一般に、等価演算子の実装はEqualsメソッドを呼び出します。を含めることもできますIeeeEqualsが、逆の方法で- ReflexiveEqualsメソッドを含めることもできます。Vector<float>型はで使用することができる多くのパフォーマンス・クリティカルなアプリケーション、およびそれに応じて最適化する必要があります。
死ぬ

@diemaus説得力がないと思ういくつかの理由:1)float/ doubleと他のいくつかの型のために、==そしてEqualsすでに異なっています。既存のタイプとの不整合は==、それらの間の不整合よりもさらに混乱Equalsし、他のタイプについては引き続き対処する必要があると思います。2)ほとんどすべての一般的なアルゴリズム/コレクションはEquals、その機能の柔軟性(LINQおよび辞書)を使用および依存しますが、具体的な浮動小数点アルゴリズムは通常==、IEEEセマンティクスを取得する場所で使用します。
CodesInChaos 2016年

私はVector<float>単純なfloatやとは別の「ビースト」を考えdoubleます。その方法では、私はそれらの基準を遵守する理由Equals==オペレーターを理解できません。「フロートを辞書のキーとして使用している場合、あなたは罪の状態にあり、正気な行動を期待してはいけません」NaN辞書に保存するとしたら、それはひどい慣習を使うことに対する彼ら自身のくだらない責任です。CoreFXチームがこれを完全に考えていなかったとは、私にはほとんど思えません。ReflexiveEqualsパフォーマンス向上のために、私はと同様のものを使用します。
死ぬ

回答:


5

IEEEの動作は正しいと私は主張します。NaNsはいかなる意味でも互いに同等ではありません。これらは、数値の答えが適切でない不適切に定義された条件に対応します。

ほとんどのプロセッサがネイティブでサポートしているIEEE演算を使用することによるパフォーマンス上の利点以外に、if if isnan(x) && isnan(y)、then と言うことには意味上の問題があると思いますx == y。例えば:

// C++
double inf = std::numeric_limits<double>::infinity();
double x = 0.0 / 0.0;
double y = inf - inf;

x等しいと見なす意味のある理由はないと私は主張しyます。それらが同等の数であるとはほとんど結論できません。それらはまったく数字ではないので、それは完全に無効な概念のように思えます。

さらに、API設計の観点からすると、多くのプログラマーが使用することを目的とした汎用ライブラリーで作業している場合、最も一般的な業界標準の浮動小数点セマンティクスを使用することは理にかなっています。優れたライブラリの目的は、ライブラリを使用する人の時間を節約することです。そのため、非標準の動作を組み込むことは混乱を招きやすいのです。


3
それNaN == NaNを返す必要があるfalseが争われていません。問題は、.Equalsメソッドが何をすべきかです。たとえばNaN、辞書のキーとして使用する場合、NaN.Equals(NaN)falseを返すと、関連付けられた値が取得できなくなります。
CodesInChaos

1
一般的なケースに最適化する必要があると思います。数値のベクトルの一般的なケースは、高スループットの数値計算です(多くの場合、SIMD命令で最適化されます)。辞書キーとしてベクトルを使用することは非常にまれなユースケースであり、セマンティクスを設計する価値はほとんどないと私は主張します。既存以来、私にとって最も合理的と思われる反論は、一貫性あるSingleDoubleなどのクラスがすでに反射的行動を持っています。私見、それはそもそも間違った決断でした。しかし、私は優雅さが実用性/スピードの邪魔をしないようにします。
Jason R

しかし、数値計算は通常==、常にIEEEに準拠しているものを使用するため、どのようEqualsに実装されていても高速なコードが得られます。IMOは、EqualsLINQのDistinct()関数など、具体的なタイプを気にしないアルゴリズムで別のメソッドを使用することの重要なポイントです。
CodesInChaos

1
わかった。しかし==Equals()セマンティクスが異なる演算子と関数を持つAPIに対しては反対の意見を述べます。開発者の観点からは混乱の代償を払っていると思いますが、実際のメリットはありません(数値のベクトルを辞書のキーとして使用できるように値を割り当てていません)。それは私の意見です。目の前の質問に対する客観的な答えはないと思います。
Jason R

0

問題があります。IEEE754は、数値演算のアプリケーションに適した方法で関係演算と等価性を定義しています。ソートやハッシュにはあまり適していません。したがって、数値に基づいて配列をソートする場合、または数値をセットに追加する場合、またはディクショナリのキーとして使用する場合は、NaN値が許可されていないか、IEEE754を使用しないことを宣言します組み込み操作。ハッシュテーブルは、すべてのNaNが同じ値に一致していることを確認し、互いに等しく比較する必要があります。

Vectorを定義する場合、数値のみの目的でそれを使用するか、それともソートおよびハッシュと互換性があるべきかどうか、設計上の決定を行う必要があります。個人的には数値的な目的がもっと重要だと思います。並べ替え/ハッシュが必要な場合は、Vectorをメンバーとしてクラスを記述し、そのクラスのハッシュと等価性を好きなように定義できます。


1
数値的な目的がより重要であることに同意します。しかし、すでにそれらのための==and !=演算子があります。私の経験では、このEquals方法はほとんど非数値アルゴリズムでのみ使用されています。
CodesInChaos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.