SSE演算子を見る
CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles
順序付きおよび順序なしとはどういう意味ですか? x86命令セットで同等の命令を探しましたが、順序付けされていないようです(FUCOM)。
順序付き比較は、どちらのオペランドもNaN
でないかどうかをチェックします。逆に、順序なし比較は、いずれかのオペランドがNaN
であるかどうかをチェックします。
このページには、これに関する詳細情報が記載されています。
ここでの考え方は、NaN
との比較は不確定であるということです。 (結果を決定できません)したがって、順序付き/順序なしの比較では、これが当てはまる(または当てはまらない)かどうかがチェックされます。
double a = 0.;
double b = 0.;
__m128d x = _mm_set1_pd(a / b); // NaN
__m128d y = _mm_set1_pd(1.0); // 1.0
__m128d z = _mm_set1_pd(1.0); // 1.0
__m128d c0 = _mm_cmpord_pd(x,y); // NaN vs. 1.0
__m128d c1 = _mm_cmpunord_pd(x,y); // NaN vs. 1.0
__m128d c2 = _mm_cmpord_pd(y,z); // 1.0 vs. 1.0
__m128d c3 = _mm_cmpunord_pd(y,z); // 1.0 vs. 1.0
__m128d c4 = _mm_cmpord_pd(x,x); // NaN vs. NaN
__m128d c5 = _mm_cmpunord_pd(x,x); // NaN vs. NaN
cout << _mm_castpd_si128(c0).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c1).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c2).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c3).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c4).m128i_i64[0] << endl;
cout << _mm_castpd_si128(c5).m128i_i64[0] << endl;
結果:
0
-1
-1
0
0
-1
NaN
と1.0
の順序付き比較はfalse
を与えます。NaN
と1.0
の順序付けられていない比較はtrue
を与えます。1.0
と1.0
の順序付き比較はtrue
を与えます。1.0
と1.0
の順序なしの比較はfalse
を与えます。NaN
とNan
の順序付き比較はfalse
を与えます。NaN
とNaN
の順序付けられていない比較はtrue
を与えます。このIntelガイド: http://intel80386.com/simd/mmx2-doc.html には、かなり単純な2つの例が含まれています。
CMPORDPSは順序付けられた並列スカラーを比較します
オペコードサイクル命令0FC2 .. 07 2(3)CMPORDPS xmm reg、xmm reg/mem128
CMPORDPS op1、op2
op1には4つの単精度32ビット浮動小数点値が含まれていますop2には4つの単精度32ビット浮動小数点値が含まれています
op1[0] = (op1[0] != NaN) && (op2[0] != NaN) op1[1] = (op1[1] != NaN) && (op2[1] != NaN) op1[2] = (op1[2] != NaN) && (op2[2] != NaN) op1[3] = (op1[3] != NaN) && (op2[3] != NaN) TRUE = 0xFFFFFFFF FALSE = 0x00000000
CMPUNORDPSは順序付けられていない並列スカラーを比較します
オペコードサイクル命令0FC2 .. 03 2(3)CMPUNORDPS xmm reg、xmm reg/mem128
CMPUNORDPS op1、op2
op1には4つの単精度32ビット浮動小数点値が含まれていますop2には4つの単精度32ビット浮動小数点値が含まれています
op1[0] = (op1[0] == NaN) || (op2[0] == NaN) op1[1] = (op1[1] == NaN) || (op2[1] == NaN) op1[2] = (op1[2] == NaN) || (op2[2] == NaN) op1[3] = (op1[3] == NaN) || (op2[3] == NaN) TRUE = 0xFFFFFFFF FALSE = 0x00000000
違いは、[〜#〜]と[〜#〜](順序付き)と[〜#〜]です。または[〜#〜](順序なし)。
TL:DR:順序なしは、2つのFP値が持つことができる関係です。 FUCOM
の「順序なし」は、比較結果が順序付けされていない場合にFP例外が発生しないことを意味しますが、FCOM
は発生します。これは、OQとOSのcmpps
述語の違いと同じです。
ORDとUNORDは、cmppd
/cmpps
/cmpss
/cmpsd
insns (の完全なテーブルの述語の2つの選択肢です。アルファベット順で最初のcmppd
エントリ) 。そのhtml抽出には読み取り可能なテーブル形式がありますが、Intelの公式のPDFオリジナルの方がやや優れています。 (リンクについては、 x86 タグwikiを参照してください)。
2つの浮動小数点どちらもNaNでない場合、オペランドは相互に順序付けられます。どちらかがNaNの場合、順序付けされていません。つまり、ordered = (x>y) | (x==y) | (x<y);
。そうです、浮動小数点では、これらのことのどれも真実ではない可能性があります。浮動小数点の狂気の詳細については、 ブルース・ドーソンの優れた一連の記事を参照してください。
cmpps
は、2つのスカラーを比較してフラグを設定する代わりに、述語を受け取り、結果のベクトルを生成します。これにより、事後に必要な述語を確認できます。したがって、チェックできるすべてのものに対して特定の述語が必要です。
同等のスカラーはcomiss
/ucomiss
であり、FP比較結果(x87比較命令のように機能します(この最後のセクションを参照)からZF/PF/CFを設定します。答え)、しかしXMM regsの低い要素について)。
順序付けされていないことを確認するには、PF
を確認してください。比較が順序付けられている場合は、他のフラグを調べて、オペランドが大きい、等しい、または小さい( )かどうかを確認できます。たとえば、jae
上記または等しい )。
COMISS命令 は、ソースオペランドがQNaNまたはSNaNのいずれかである場合に、SIMD浮動小数点無効操作例外(#I)を通知するという点でUCOMISS命令とは異なります。 UCOMISS命令は、ソースオペランドがSNaNの場合にのみ、無効な数値例外を通知します。
通常、FP例外はマスクされるため、実際にプログラムが中断されることはありません。後で確認できるMXCSRのビットを設定するだけです。
これは述語のO/UQ対O/USフレーバーと同じですcmpps
/vcmpps
の場合。 cmp[ps][sd]
命令のAVXバージョンでは、述語の選択肢が拡張されているため、それらを追跡するための命名規則が必要でした。
O対Uは、オペランドが順序付けられていないときに述語が真であるかどうかを示します。
Q vs. Sは、いずれかのオペランドがQuietNaNの場合に#Iが発生するかどうかを示します。 #どちらかのオペランドがSignaling NaNの場合、常に発生しますが、それらは「自然に発生する」ものではありません。自分でビットパターンを作成するだけで、他の操作からの出力としてそれらを取得することはありません(たとえば、後で問題を確実に検出するために、関数からのエラー戻り値として)。
X87に相当するものは、fcom
またはfucom
を使用してFPUステータスを設定しますWord-> fstsw ax
-> sahf
、またはできれば fucomi
は、EFLAGSをcomiss
のように直接設定します。
U /非Uの区別は、x87命令でもcomiss
/ucomiss
の場合と同じです。