Что означает упорядоченное / неупорядоченное сравнение? - PullRequest
29 голосов
/ 25 декабря 2011

Глядя на операторов SSE

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

Что означают упорядоченные и неупорядоченные? Я искал эквивалентные инструкции в наборе команд x86, и он только кажется неупорядоченным (FUCOM).

Ответы [ 4 ]

27 голосов
/ 25 декабря 2011

Упорядоченное сравнение проверяет, является ли ни один из операндов 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.
5 голосов
/ 25 декабря 2011

Это руководство Intel: 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

Разница составляет И (заказано) против ИЛИ (неупорядочено).

3 голосов
/ 22 июля 2016

TL: DR : Неупорядоченное - это отношение, которое могут иметь два значения FP. «Неупорядоченный» в FUCOM означает, что он не вызывает исключение FP, когда результат сравнения неупорядочен, в то время как FCOM делает. Это то же самое, что и различие между предикатами OQ и OS cmpps


ORD и UNORD - два варианта предиката для cmppd / cmpps / cmpss / cmpsd insns (полные таблицы в записи cmppd, которая начинается в алфавитном порядке) . Этот HTML-фрагмент имеет удобочитаемое форматирование таблицы, но официальный оригинал Intel в формате PDF несколько лучше. (См. Вики-тег для ссылок).

Два операнда с плавающей точкой упорядочены относительно друг друга, если ни один из них не равен NaN . Они неупорядочены, если любой из них является NaN. т.е. ordered = (x>y) | (x==y) | (x<y);. Правильно, с плавающей точкой ни одна из этих вещей не может быть правдой. Для получения дополнительной информации о безумии с плавающей точкой см. превосходную серию статей Брюса Доусона.

cmpps берет предикат и выдает вектор результатов вместо сравнения двух скаляров и установки флагов, чтобы вы могли проверить любой предикат, который вам нужен, после факта. Поэтому для всего, что вы можете проверить, нужны конкретные предикаты.


Скалярный эквивалент равен comiss / ucomiss для установки ZF / PF / CF из результата сравнения FP (который работает как инструкции сравнения x87 (см. Последний раздел этого ответа), но для младшего элемента XMM regs).

Чтобы проверить неупорядоченное, посмотрите на PF. Если сравнение упорядочено, вы можете посмотреть другие флаги, чтобы увидеть, были ли операнды больше, равны или меньше (, используя те же условия, что и для целых чисел без знака, например, jae для Above или Equal ) .


Инструкция COMISS отличается от инструкции UCOMISS тем, что она сигнализирует об исключении недопустимой операции SIMD с плавающей запятой (#I), когда исходным операндом является QNaN или SNaN. Инструкция UCOMISS сообщает о недопустимом числовом исключении, только если исходным операндом является SNaN.

Обычно исключения FP маскируются, так что это фактически не прерывает вашу программу; он просто устанавливает бит в MXCSR, который вы можете проверить позже.

Это то же самое, что O / UQ против разновидностей O / US предиката для cmpps / vcmpps. AVX-версия инструкций cmp[ps][sd] имеет расширенный выбор предикатов, поэтому для их отслеживания требовалось соглашение об именах.

O против U говорит вам, является ли предикат истинным, когда операнды неупорядочены.

Q vs. S говорит вам, будет ли поднято #I, если любой из операндов является тихим NaN. # Я всегда буду вызываться, если любой из операндов является сигнальным NaN, но они не «встречаются естественным образом». Вы не получаете их в качестве выходных данных от других операций, только создавая битовую комбинацию самостоятельно (например, как возвращаемое значение ошибки из функции, чтобы гарантировать обнаружение проблем позже).


Эквивалент x87 использует fcom или fucom для установки слова состояния FPU -> fstsw ax -> sahf, или предпочтительно fucomi для прямой установки EFLAGS, например comiss.

Различие U / non-U с инструкциями x87 такое же, как для comiss / ucomiss

0 голосов
/ 25 декабря 2011

Может быть, эта страница о встроенных функциях Visual C ++ может помочь? :)

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
...