有序/无序比较是什么意思?

Dan*_*Dan 33 x86 assembly sse

看着SSE运营商

CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles
Run Code Online (Sandbox Code Playgroud)

有序和无序是什么意思?我在x86指令集中寻找等效指令,它似乎只有无序(FUCOM).

Mys*_*ial 33

一个有序的比较检查,如果没有操作数NaN.相反,无序比较检查两个操作数是否为a 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;
Run Code Online (Sandbox Code Playgroud)

结果:

0
-1
-1
0
0
-1
Run Code Online (Sandbox Code Playgroud)
  • 比较有序NaN,并1.0给出了false.
  • 无序的比较NaN,并1.0给出了true.
  • 比较有序1.0,并1.0给出了true.
  • 无序的比较1.0,并1.0给出了false.
  • 比较有序NaN,并Nan给出了false.
  • 无序的比较NaN,并NaN给出了true.


Aus*_*oke 5

本英特尔指南:http://intel80386.com/simd/mmx2-doc.html包含两个相当简单的示例:

CMPORDPS比较有序并行标量

操作码循环指令0F C2 .. 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
Run Code Online (Sandbox Code Playgroud)

CMPUNORDPS比较无序并行标量

操作码循环指令0F C2 .. 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
Run Code Online (Sandbox Code Playgroud)

差异是AND(有序)对OR(无序).


Pet*_*des 5

TL:DR:无序是两个FP值可以具有的关系。“无序” FUCOM表示在比较结果无序的情况下不会引发FP异常,而在比较结果无序的FCOM情况下。这与OQ和OS cmpps谓词之间的区别相同


ORD和UNORD是断言对于两种选择cmppd/ cmpps/ cmpss/ cmpsd的insn (在完整的表cmppd其是按字母顺序第一个条目)。该html摘录具有可读的表格格式,但Intel的官方PDF原版要好一些。(有关链接,请参见标签wiki)。

如果NaN都不是,则两个浮点操作数彼此相对排序。如果它们都是NaN,则它们是无序的。即ordered = (x>y) | (x==y) | (x<y);。没错,以浮点数表示,这些都不是真的。有关浮点疯狂的更多信息,请参阅Bruce Dawson的精彩文章系列。

cmpps接受一个谓词并产生一个结果向量,而不是在两个标量和设置标志之间进行比较,以便您可以在事后检查想要的任何谓词。因此,对于需要检查的所有内容,它都需要特定的谓词。


标量等效项是comiss/,ucomiss用于从FP比较结果中设置ZF / PF / CF(其工作方式类似于x87比较指令(请参见此答案的最后部分),但位于XMM regs的低位)。

要检查是否有序,请查看PF。如果比较是有序的,则可以查看其他标志以查看操作数是大于,等于还是小于(使用与无符号整数相同的条件,例如jaeAbove或Equal)。


COMISS指令与UCOMISS 指令的不同之处在于,当源操作数是QNaN或SNaN时,它会发信号通知SIMD浮点无效操作异常(#I)。仅当源操作数为SNaN时,UCOMISS指令才会发出无效的数字异常信号。

通常,FP异常会被屏蔽,因此这实际上不会中断您的程序。它只是设置了MXCSR中的位,您可以稍后检查。

这是一样的谓语的O / UQ与O /美国口味cmpps/ vcmpps。该cmp[ps][sd]指令的AVX版本具有更多的谓词选择,因此它们需要一个命名约定来跟踪它们。

O与U会告诉您操作数无序时谓词是否为真。

Q与S告诉您,如果任一操作数为Quiet NaN,是否会提高#I。如果任何一个操作数是一个信号NaN,但不会“自然发生”,则始终会引发#I。您不能仅通过自己创建位模式(例如,将其作为函数的错误返回值,以确保以后发现问题)而将其作为其他操作的输出。


x87等效项是使用fcomfucom设置FPU状态字-> fstsw ax-> sahf,或者最fucomi好像一样直接设置EFLAGS comiss

x87指令的U / non-U区别与comiss/ucomiss