您可以通过比较自己的值来测试NaN的值。如果x是NaN,则x == x
将返回false。因此,对于4×浮点值的SSE向量,VX:
vmask = _mm_cmpeq_ps(vx, vx);
会给你全0在VX NaN的元素和全1对于非NaN的元素面膜载体。您可以使用掩码来清零NaN。您还可以使用该掩码将有效数据点的数量视为32位整数和累加的向量来计数。
这里是一个经过测试的示例 - 注意它假定n是4的倍数,a,b不是16字节对齐的,并且还要注意它需要SSE4。
float rms(const float *a, const float *b , int n)
{
int count;
float sum;
__m128i vcount = _mm_set1_epi32(0);
__m128 vsum = _mm_set1_ps(0.0f);
assert((n & 3) == 0);
for (int i = 0; i < n; i += 4)
{
__m128 va = _mm_loadu_ps(&a[i]);
__m128 vb = _mm_loadu_ps(&b[i]);
__m128 vmaska = _mm_cmpeq_ps(va, va);
__m128 vmaskb = _mm_cmpeq_ps(vb, vb);
__m128 vmask = _mm_and_ps(vmaska, vmaskb);
__m128 vtmp = _mm_sub_ps(va, vb);
vtmp = _mm_and_ps(vtmp, vmask);
vtmp = _mm_mul_ps(vtmp, vtmp);
vsum = _mm_add_ps(vsum, vtmp);
vcount = _mm_sub_epi32(vcount, (__m128i)vmask);
}
vsum = _mm_hadd_ps(vsum, vsum);
vsum = _mm_hadd_ps(vsum, vsum);
_mm_store_ss(&sum, vsum);
vcount = _mm_hadd_epi32(vcount, vcount);
vcount = _mm_hadd_epi32(vcount, vcount);
count = _mm_extract_epi32(vcount, 0);
return count > 0 ? sum/(float)count : 0.0f;
}
_mm_cmpord_ps(a [i],b [i])也许?你会用n + = 4来计算n。请注意,编译器可以自己矢量化这个循环。还要注意的是,finitef并不完全检查NaN。 – 2013-04-09 21:24:58
请注意,此功能不计算RMS - 它计算均方差。 – 2013-04-10 08:55:56
你是对的,但SSE中的sqrt也是个问题,我想: -/ – Roby 2013-04-11 16:46:46