signos signo regla positivos operaciones numeros negativos multiplicacion los ley ejemplos divisiones con c x86 sse simd sign

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; }