SSE: обратный, если не нулевой

Как я могу взять обратное (обратное) число с плавающей запятой с инструкциями SSE, но только для ненулевых значений?

Фон ниже:

Я хочу нормализовать массив векторов, чтобы каждое измерение имело одинаковое среднее значение. В C это можно закодировать как:

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

Теперь из соображений производительности я хочу сделать это с помощью SSE intinsics. Setp 1 и шаг 3 просты, но я застрял на шаге 2. Кажется, я не нашел ни одного примера кода или очевидной инструкции SSE, чтобы получить обратное значение if оно не равно нулю . Для деления _mm_rcp_ps делает свое дело и, возможно, комбинирует его с условным перемещением, но как получить маску, указывающую, какой компонент равен нулю?

Мне не нужен код к алгоритму, описанному выше, просто функция "обратная, если не нулевая":

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

Спасибо!


person Antoine    schedule 15.05.2012    source источник


Ответы (1)


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

Каждая дорожка mask устанавливается либо на b111...11, если вход равен нулю, либо на b000...00 в противном случае. И-нет с той маской заменяет элементы обратной величины, соответствующие нулевому входу, на нуль.

person Stephen Canon    schedule 15.05.2012
comment
Черт, это было быстро. Я работал один, а ты меня опередил. +1 - person Mysticial; 15.05.2012
comment
Спасибо. Есть ли способ проверить вместо сравнения и избежать использования регистра, установленного на ноль? Просто интересуюсь... - person Antoine; 16.05.2012
comment
Кроме того, в последней строке опечатка: ввод должен быть recip. - person Antoine; 16.05.2012
comment
@Antoine: Регистр, установленный на ноль, обычно ничего вам не стоит. Любой приличный компилятор будет просто выдавать xorps, который распознается процессором как идиома обнуления и чрезвычайно эффективен (на самых процессорах его даже не нужно выполнять). - person Stephen Canon; 16.05.2012
comment
В отличие от того, что следует из названия, andnot(a,b) не (a & ~b), а (~a & b). - person Antoine; 19.07.2012