2013-04-09 3 views
4

인텔 sse 내장 함수로 rms를 계산하고 싶습니다. 유사 항목 :SSE rms 계산

float rms(float *a, float *b , int l) 
{ 
    int n=0; 
    float r=0.0; 
    for(int i=0;i<l;i++) 
    { 
     if(finitef(a[i]) && finitef(b[i])) 
     { 
      n++; 
      tmp = a[i] - b[i]; 
      r += tmp*tmp; 
     } 
    } 
    r /= n; 
    return r; 
} 

하지만 NaN 요소를 확인하는 방법은 무엇입니까? 그리고 어떻게 계산합니까?

+1

_mm_cmpord_ps (a [i], b [i])? 그리고 n + = 4로 n을 계산할 것입니다. 컴파일러는이 루프를 직접 벡터화 할 수 있습니다. finitef는 NaN을 정확히 검사하지 않는다는 점에 유의하십시오. –

+0

이 함수는 RMS를 계산하지 않습니다. 평균 제곱의 차이를 계산합니다. –

+0

당신은 맞지만 SSE의 sqrt도 문제입니다. -/ – Roby

답변

5

NaN 값은 자체 값과 비교하여 테스트 할 수 있습니다. x == x은 x가 NaN 인 경우 false를 반환합니다. 4 × 플로트 값의 SSE 벡터, VX에 대한 그래서 :

vmask = _mm_cmpeq_ps(vx, vx); 

당신에게 VX에서 NaN의 요소 모두 0이 아닌 NaN의 요소 모두 1로 마스크 벡터를 제공한다. 마스크를 사용하여 NaN을 제로로 만들 수 있습니다. 또한 마스크를 사용하여 유효한 데이터 포인트 수를 32 비트 int의 벡터로 처리하고 누적하여 카운트 할 수 있습니다.

작동되는 테스트 된 예제입니다. 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; 
} 
+0

고마워,하지만 만약 내가 "vmask = _mm_cmpeq_ps (vx, vx);" enxt 단계는 _mm_hadd_ps가 두 번 호출 된 것으로 생각하는이 네 가지 요소를 추가하는 것입니다. 하지만 난 내 값에 나노 값을 가지고. 그래서 나는 처음에이 벡터들을 벡터에서 지워 버렸습니까? : -/ – Roby

+2

아니요 - 마스크를 사용하여 NaN을 제로화합니다. 또한 루프가 끝날 때까지 수평으로 추가하지 마십시오. 마스크를 사용하여 유효한 데이터 포인트 수를 계산할 수도 있습니다. –

+0

@Roby : 위 참조 - 이제 전체 구현을 추가했습니다. –