assembly - procesador - ¿Qué significa comparación ordenada/desordenada?
sse wikipedia (4)
¿Quizás esta página sobre intrínsecos de Visual C ++ puede ser de ayuda? :)
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
Mirando los operadores SSE
CMPORDPS - ordered compare packed singles
CMPUNORDPS - unordered compare packed singles
¿Qué significa ordenado y desordenado? Busqué instrucciones equivalentes en el conjunto de instrucciones x86, y solo parece haber desordenado (FUCOM).
Esta guía de Intel: http://intel80386.com/simd/mmx2-doc.html contiene ejemplos de los dos que son bastante sencillos:
CMPORDPS compara los paralelos ordenados paralelos
Instrucción de ciclos de códigos de operación 0F C2 .. 07 2 (3) CMPORDPS xmm reg, xmm reg / mem128
CMPORDPS op1, op2
op1 contiene 4 valores de coma flotante de 32 bits de precisión simple op2 contiene 4 valores de coma flotante de 32 bits de precisión simple
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 compara los escalares paralelos desordenados
Instrucción de ciclos de código de operación 0F C2 .. 03 2 (3) CMPUNORDPS xmm reg, xmm reg / mem128
CMPUNORDPS op1, op2
op1 contiene 4 valores de coma flotante de 32 bits de precisión simple op2 contiene 4 valores de coma flotante de 32 bits de precisión simple
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
La diferencia es AND (ordenada) frente a OR (desordenada).
Una comparación ordenada comprueba si ninguno de los operandos es NaN
. Por el contrario, una comparación desordenada comprueba si alguno de los operandos es un NaN
.
Esta página ofrece más información sobre esto:
La idea aquí es que las comparaciones con NaN
son indeterminadas. (no puede decidir el resultado) Entonces una comparación ordenada / desordenada verifica si este es (o no) el caso.
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;
Resultado:
0
-1
-1
0
0
-1
- La comparación ordenada de
NaN
y1.0
dafalse
. - La comparación desordenada de
NaN
y1.0
datrue
. - La comparación pedida de
1.0
y1.0
datrue
. - La comparación desordenada de
1.0
y1.0
dafalse
. - La comparación ordenada de
NaN
yNan
dafalse
. - La comparación desordenada de
NaN
yNaN
datrue
.
TL: DR : Desordenado es una relación que pueden tener dos valores FP. El "Desordenado" en FUCOM
significa que no FUCOM
una excepción FP cuando el resultado de la comparación no está ordenado, mientras que FCOM
sí FCOM
hace. Esto es lo mismo que la distinción entre predicados cmpps
OQ y OS
ORD y UNORD son dos elecciones de predicado para las cmppd
/ cmpps
/ cmpss
/ cmpsd (tablas completas en la entrada cmppd
que es alfabéticamente primero) . Ese extracto html tiene formato de tabla legible, pero el original PDF original de Intel es algo mejor. (Consulte la wiki de la etiqueta x86 para ver los enlaces).
Dos operandos de coma flotante se ordenan entre sí si ninguno es NaN . No están ordenados si alguno de ellos es NaN. es decir, ordered = (x>y) | (x==y) | (x<y);
ordered = (x>y) | (x==y) | (x<y);
. Así es, con punto flotante es posible que ninguna de esas cosas sea verdad. Para más locura de punto flotante, vea la excelente serie de artículos de Bruce Dawson.
cmpps
toma un predicado y produce un vector de resultados, en lugar de hacer una comparación entre dos escalares y banderas de configuración para que pueda verificar cualquier predicado que desee después del hecho. Por lo tanto, necesita predicados específicos para todo lo que pueda verificar.
El equivalente escalar es comiss
/ ucomiss
para configurar ZF / PF / CF a partir del resultado de la comparación FP (que funciona como las instrucciones de comparación x87 (ver la última sección de esta respuesta), pero en el elemento bajo de las reglas XMM).
Para verificar si no está ordenado, mira PF
. Si la comparación está ordenada, puede mirar las otras banderas para ver si los operandos fueron mayores, iguales o menores ( usando las mismas condiciones que para los enteros sin signo, como jae
para Above o Equal ).
La instrucción COMISS difiere de la instrucción UCOMISS en que señala una excepción de operación inválida de coma flotante SIMD (#I) cuando un operando fuente es QNaN o SNaN. La instrucción UCOMISS señala una excepción numérica inválida solo si un operando fuente es un SNaN.
Normalmente, las excepciones de FP están enmascaradas, por lo que esto no interrumpe realmente su programa; simplemente establece el bit en el MXCSR que puedes verificar más tarde.
Esto es lo mismo que los sabores de predicado O / UQ frente a O / US para cmpps
/ vcmpps
. La versión AVX de las instrucciones cmp[ps][sd]
tiene una opción expandida de predicado, por lo que necesitaban una convención de nomenclatura para realizar un seguimiento de ellos.
La O vs. U le dice si el predicado es verdadero cuando los operandos están desordenados.
La Q vs. S le dice si # I se generará si cualquiera de los dos operandos es un NaN silencioso. # Siempre me plantearé si alguno de los operandos es un NaN de señalización, pero esos no son "naturales". No los obtiene como salidas de otras operaciones, solo creando el patrón de bits usted mismo (por ejemplo, como un valor de retorno de error de una función, para asegurar la detección de problemas más adelante).
El equivalente x87 está usando fucom
o fucom
para configurar la palabra de estado FPU -> fstsw ax
-> sahf
, o preferiblemente fucomi
para establecer EFLAGS directamente como comiss
.
La distinción U / no U es la misma con las instrucciones x87 que con comiss
/ ucomiss