c - positivos - regla de los signos division
SSE intrÃnseca sobre int16[8] para extraer el signo de cada elemento (3)
Estoy trabajando con las funciones intrínsecas de SSE. Tengo un __m128i que representa una matriz de 8 valores cortos firmados (16 bits).
¿Hay una función para obtener el signo de cada elemento?
EDIT1: algo que se puede usar así:
short tmpVec[8];
__m128i tmp, sgn;
for (i-0;i<8;i++)
tmp.m128i_i16[i] = tmpVec[i]
sgn = _mm_sign_epi16(tmp);
por supuesto, "_mm_sign_epi16" no existe, así que eso es lo que estoy buscando.
¿Qué tan lento es hacerlo elemento por elemento?
EDIT2: comportamiento deseado: 1 para valores positivos, 0 para cero y -1 para valores negativos.
Gracias
Llene un registro de ceros, y compárelo con su registro, primero con "mayor que", que con "menor que" (o invierta el orden de los operandos en la instrucción "mayor que").
http://msdn.microsoft.com/en-us/library/xd43yfsa%28v=vs.90%29.aspx
http://msdn.microsoft.com/en-us/library/t863edb2%28v=vs.90%29.aspx
El problema en este punto es que el verdadero valor se representa como 0xffff, que resulta ser -1, resultado correcto para el número negativo pero no para el positivo. Sin embargo, como señaló Raymond Chen en los comentarios, 0x0000 - 0xffff = 0x0001, entonces es suficiente restar el resultado de "mayor que" del resultado de "menor que". http://msdn.microsoft.com/en-us/library/y25yya27%28v=vs.90%29.aspx
Por supuesto, la respuesta de Paul R es preferible, ya que solo usa 2 instrucciones.
Puede cambiar los 8 cortos a la vez usando _mm_srai_epi16(tmp, 15)
que devolverá ocho enteros de 16 bits, siendo cada uno todos (es decir -1) si la entrada fue negativa, o todos ceros (es decir 0) si es positivo.
Puede usar operaciones min / max para obtener el resultado deseado, por ejemplo
inline __m128i _mm_sgn_epi16(__m128i v)
{
v = _mm_min_epi16(v, _mm_set1_epi16(1));
v = _mm_max_epi16(v, _mm_set1_epi16(-1));
return v;
}
Esto es probablemente un poco más eficiente que comparar explícitamente con cero + cambio + combinar resultados.
Tenga en cuenta que ya existe un _mm_sign_epi16
intrínseco en SSSE3 ( PSIGNW
- ver tmmintrin.h
), que se comporta de forma algo diferente, así que cambié el nombre de la función requerida a _mm_sgn_epi16
. Sin embargo, el uso de _mm_sign_epi16
podría ser más eficiente cuando SSSE3 está disponible, por lo que podría hacer algo como esto:
inline __m128i _mm_sgn_epi16(__m128i v)
{
#ifdef __SSSE3__
v = _mm_sign_epi16(_mm_set1_epi16(1), v); // use PSIGNW on SSSE3 and later
#else
v = _mm_min_epi16(v, _mm_set1_epi16(1)); // use PMINSW/PMAXSW on SSE2/SSE3.
v = _mm_max_epi16(v, _mm_set1_epi16(-1));
#endif
return v;
}