Что означает упорядоченное/неупорядоченное сравнение?

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

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

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

Ответ 1

упорядоченное сравнение проверяет, не находится ли ни один из операндов 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.

Ответ 2

В этом руководстве Intel: http://intel80386.com/simd/mmx2-doc.html содержатся примеры двух, которые довольно прямолинейны:

CMPORDPS Сравнение упорядоченных параллельных скаляров

Циклы команд Opcode 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 Сравнение неупорядоченных параллельных скаляров

Циклы команд Opcode Инструкция 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

Разница И (упорядоченная) vs ИЛИ (неупорядоченная).

Ответ 3

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


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

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

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


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

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


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

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

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

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

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


Эквивалент x87 использует FCOM или FUCOM для установки слова состояния FPU → fstsw axsahf или предпочтительно fucomi, чтобы установить EFLAGS прямо как comiss.

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

Ответ 4

Возможно, эта страница в Visual С++ может помочь?:)

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