8

如何使用 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 指令来取值的倒数(如果它不为零)。对于除法,_mm_rcp_ps 可以解决问题,并且可能将其与条件移动相结合,但是如何获得指示哪个分量为零的掩码?

我不需要上述算法的代码,只需要“如果不为零则取反”函数:

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

谢谢!

4

1 回答 1

13
__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设置为,否则设置为。And-not 使用该掩码将对应于零输入的倒数元素替换为零。b111...11b000...00

于 2012-05-15T18:18:37.043 回答