2012-05-15 13 views
6

¿Cómo puedo tomar el recíproco (inverso) de flotadores con instrucciones SSE, pero solo para valores distintos de cero?SSE: recíproco si no es cero

Antecedentes abajo:

Quiero normalizar un conjunto de vectores de manera que cada dimensión tiene la misma media. En C esto puede ser codificada como:

float vectors[num * dim]; // input data 

// step 1. compute the sum on each dimension 
float norm[dim]; 
memset(norm, 0, dim * sizeof(float)); 
for(int i = 0; i < num; i++) for(int j = 0; j < dims; j++) 
    norm[j] += vectors[i * dims + j]; 
// step 2. convert sums to reciprocal of average 
for(int j = 0; j < dims; j++) if(norm[j]) norm[j] = float(num)/norm[j]; 
// step 3. normalize the data 
for(int i = 0; i < num; i++) for(int j = 0; j < dims; j++) 
    vectors[i * dims + j] *= norm[j]; 

ahora por razones de rendimiento, yo quiero hacer esto utilizando intinsics SSE. Setp 1 et paso 3 son fáciles, pero estoy atascado en el paso 2. No parece encontrar ningún ejemplo de código o instrucción SSE obvia para tomar la recirculación de un valor si no es cero. Para la división, _mm_rcp_ps hace el truco, y tal vez combinarlo con un movimiento condicional, pero ¿cómo obtener una máscara que indique qué componente es cero?

No necesito el código para el algoritmo descrito anteriormente, sólo la "inversa si no es cero" función:

__m128 rcp_nz_ps(__m128 input) { 
    // ???? 
} 

Gracias!

Respuesta

11
__m128 rcp_nz_ps(__m128 input) { 
    __m128 mask = _mm_cmpeq_ps(_mm_set1_ps(0.0), input); 
    __m128 recip = _mm_rcp_ps(input); 
    return _mm_andnot_ps(mask, recip); 
} 

Cada carril de mask se establece en b111...11 si la entrada es cero, y b000...00 lo contrario. Y, no con esa máscara, reemplaza los elementos de la reciproca correspondiente a una entrada cero con cero.

+1

Maldición, eso fue rápido. Estaba trabajando solo y tú me ganaste. +1 – Mysticial

+0

Gracias. ¿Hay alguna forma de "probar" en lugar de "comparar" y evitar el uso de un conjunto de registros como nulo? Sólo me preguntaba ... – Antoine

+0

Además, en la última línea, hay un error tipográfico: la entrada debe ser recip. – Antoine