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

时间:2011-12-24 22:59:50

标签: assembly x86 sse

关注SSE运营商

CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles

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

5 个答案:

答案 0 :(得分:27)

有序比较检查两个操作数是否均为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
  • NaN1.0的有序比较给出了false
  • NaN1.0的无序比较给出了true
  • 1.01.0的有序比较给出了true
  • 1.01.0的无序比较给出了false
  • NaNNan的有序比较给出了false
  • NaNNaN的无序比较给出了true

答案 1 :(得分: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
     
     

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

区别在于 AND (有序)vs OR (无序)。

答案 2 :(得分:3)

TL:DR :无序是两个FP值可以具有的关系。 FUCOM中的“无序”表示当比较结果无序时它不会引发FP异常,而FCOM则会引发FP异常。这与OQ和OS cmpps谓词

之间的区别相同

ORD和UNORD是cmppd / cmpps / cmpss / cmpsd insn (full tables in the cmppd entry which is alphabetically first)的两种谓词选择。那个html摘录具有可读的表格格式,但英特尔的官方PDF原始版本要好一些。 (有关链接,请参阅标记wiki。)

如果两个浮点操作数都不是NaN ,则它们相互排序。如果是NaN,它们是无序的。即ordered = (x>y) | (x==y) | (x<y);。没错,浮动点可能没有一个是真的。有关浮点数的更多信息,请参阅Bruce Dawson's excellent series of articles.

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

标量等价物是comiss / ucomiss,用于从FP比较结果设置ZF / PF / CF(其效果类似于x87比较指令(参见本答案的最后一部分),但是XMM的低元素注册。)

要检查无序,请查看PF。如果比较是有序的,您可以查看其他标志以查看操作数是大于,等于还是更小(using the same conditions as for unsigned integers, like jae for Above or Equal)。

  

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

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

这与cmpps / vcmpps的O / UQ与O / US谓词相同。 cmp[ps][sd]指令的AVX版本具有扩展的谓词选择,因此它们需要一个命名约定来跟踪它们。

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

Q vs. S告诉你,如果任一操作数是一个安静的NaN,是否会引发#I。如果任一操作数是信令NaN,则#I将始终被引发,但这些不是“自然发生的”。您不会将它们作为其他操作的输出,只能通过自己创建位模式(例如,作为函数的错误返回值,以确保以后检测到问题)。

x87等效版使用fcomfucom来设置FPU状态字 - &gt; fstsw ax - &gt; sahf,或者最好fucomi直接设置EFLAGS,如comiss

U /非U区别与x87指令相同,与comiss / ucomiss

相同

答案 3 :(得分:1)

你可以通过llvm CC的定义理解“有序CC”和“无序CC”的含义,其中“CC”是指CondCode。 在'llvm/include/llvm/CodeGen/ISDOpcodes.h'(我的源代码版本是llvm-10.0.1)中,可以看到CondCode的枚举如下:

enum CondCode {
// Opcode          N U L G E       Intuitive operation
SETFALSE,      //    0 0 0 0       Always false (always folded)
SETOEQ,        //    0 0 0 1       True if ordered and equal
SETOGT,        //    0 0 1 0       True if ordered and greater than
SETOGE,        //    0 0 1 1       True if ordered and greater than or equal
SETOLT,        //    0 1 0 0       True if ordered and less than
SETOLE,        //    0 1 0 1       True if ordered and less than or equal
SETONE,        //    0 1 1 0       True if ordered and operands are unequal
SETO,          //    0 1 1 1       True if ordered (no nans)
SETUO,         //    1 0 0 0       True if unordered: isnan(X) | isnan(Y)
SETUEQ,        //    1 0 0 1       True if unordered or equal
SETUGT,        //    1 0 1 0       True if unordered or greater than
SETUGE,        //    1 0 1 1       True if unordered, greater than, or equal
SETULT,        //    1 1 0 0       True if unordered or less than
SETULE,        //    1 1 0 1       True if unordered, less than, or equal
SETUNE,        //    1 1 1 0       True if unordered or not equal
SETTRUE,       //    1 1 1 1       Always true (always folded)
// Don't care operations: undefined if the input is a nan.
SETFALSE2,     //  1 X 0 0 0       Always false (always folded)
SETEQ,         //  1 X 0 0 1       True if equal
SETGT,         //  1 X 0 1 0       True if greater than
SETGE,         //  1 X 0 1 1       True if greater than or equal
SETLT,         //  1 X 1 0 0       True if less than
SETLE,         //  1 X 1 0 1       True if less than or equal
SETNE,         //  1 X 1 1 0       True if not equal
SETTRUE2,      //  1 X 1 1 1       Always true (always folded)
SETCC_INVALID       // Marker value.
};

这意味着:对于浮点条件比较,“ordered CC”表示“ordered & CC”,而“unordered CC”表示“unordered |抄送。

换句话说,在浮点比较中,NaN 是“非数字”,

  • 'ordered CC' 在以下情况下返回 true:'两个操作数都不是 NaN' AND 'CC is true'
  • 'unordered CC' 在以下情况下返回 true:'一个或多个操作数为 NaN' OR 'CC is true'

你也可以看到,'ordered CC'绝对是'unordered !CC'的反义词。

答案 4 :(得分:-3)

对于Visual C ++内在函数来说,this page可能有帮助吗? :)

CMPORDPS

r0 := (a0 ord? b0) ? 0xffffffff : 0x0
r1 := (a1 ord? b1) ? 0xffffffff : 0x0
r2 := (a2 ord? b2) ? 0xffffffff : 0x0
r3 := (a3 ord? b3) ? 0xffffffff : 0x0

CMPUNORDPS

r0 := (a0 unord? b0) ? 0xffffffff : 0x0
r1 := a1 ; r2 := a2 ; r3 := a3