2013-03-12 27 views
6

Tôi muốn đạt được điều này:Nếu báo cáo với so sánh SSE trong C

for (int i=0;i<n,i++){ 
    if (x[i] > 2.0f || x[i] < -2.0f) 
    a[i] += x[i]; 
} 

Tôi đã đi xa nhưng không biết phải làm gì tiếp theo:

__m128 P2f = _mm_set1_ps(2.0f); 
__m128 M2f = _mm_set1_ps(-2.0f); 
for(int i=0;i<n,i+=4){ 
__m128 xv = _mm_load_ps(x+i); 
__m128 av = _mm_load_ps(a+i); 

__m128 c1 = _mm_cmpgt_ps(xv, P2f); 
__m128 c2 = _mm_cmplt_ps(xv, M2f); 

__m128 or = _mm_or_ps(c1,c2); 
    =???== 
av = _mm_add_ps(av, xv); 
_mm_store_ps(a+i, av); 
} 

Trả lời

4

Bạn đang gần:

const __m128 P2f = _mm_set1_ps(2.0f); 
const __m128 M2f = _mm_set1_ps(-2.0f); 
for (int i = 0; i < n; i += 4) 
{ 
    __m128 xv = _mm_load_ps(x + i); 
    __m128 av = _mm_load_ps(a + i); 

    __m128 c1v = _mm_cmpgt_ps(xv, P2f); 
    __m128 c2v = _mm_cmplt_ps(xv, M2f); 

    __m128 cv = _mm_or_ps(c1v, c2v); 

    xv = _mm_and_ps(xv, cv); 

    av = _mm_add_ps(av, xv); 

    _mm_store_ps(a + i, av); 
} 

Bí quyết là OR hai kết quả so sánh và sau đó sử dụng kết quả này làm mặt nạ để loại trừ giá trị X không vượt qua bài kiểm tra bằng cách sử dụng thao tác bitwise AND. Sau đó bạn thêm vectơ X có mặt nạ, sẽ thêm 0 hoặc giá trị X ban đầu cho mỗi phần tử của A theo mặt nạ.


Đối với phiên bản thay thế như đã đề cập trong nhận xét của bạn bên dưới, bạn muốn làm điều này:

const __m128 P2f = _mm_set1_ps(2.0f); 
const __m128 M2f = _mm_set1_ps(-2.0f); 
for (int i = 0; i < n; i += 4) 
{ 
    __m128 xv = _mm_load_ps(x + i); 
    __m128 av = _mm_load_ps(a + i); 

    __m128 c1v = _mm_cmpgt_ps(xv, P2f); 
    __m128 c2v = _mm_cmplt_ps(xv, M2f); 

    __m128 cv = _mm_or_ps(c1v, c2v); 

    xv = _mm_and_ps(P2f, cv); // <<< change this line to get a[i] += 2.0f 
           //  instead of a[i] += x[i] 

    av = _mm_add_ps(av, xv); 

    _mm_store_ps(a + i, av); 
} 

Đối với phiên bản thứ ba bạn đề cập đến trong ý kiến ​​sau đây (a[i] *= 2.0) nó hơi phức tạp hơn, nhưng bạn có thể làm điều đó bằng cách suy nghĩ về biểu thức dưới dạng a[i] += a[i]:

const __m128 P2f = _mm_set1_ps(2.0f); 
const __m128 M2f = _mm_set1_ps(-2.0f); 
for (int i = 0; i < n; i += 4) 
{ 
    __m128 xv = _mm_load_ps(x + i); 
    __m128 av = _mm_load_ps(a + i); 

    __m128 c1v = _mm_cmpgt_ps(xv, P2f); 
    __m128 c2v = _mm_cmplt_ps(xv, M2f); 

    __m128 cv = _mm_or_ps(c1v, c2v); 

    xv = _mm_and_ps(av, cv)); // <<< change this line to get a[i] *= 2.0f (a[i] += a[i]) 
           //  instead of a[i] += x[i] 

    av = _mm_add_ps(av, xv); 

    _mm_store_ps(a + i, av); 
} 
+0

Cảm ơn rất nhiều. Một điều nữa, thay đổi câu trả lời thay vì [i] + = x [i], đó là [i] + = 2.0f? – NeilDA

+0

Tôi cũng gặp phải một [i] * = 2.0f. Thay thế _mm_and_ps thành _mm_mul_ps dường như không hoạt động ở đây. Trừ khi tôi đang làm gì đó sai. Nó vẫn sẽ làm việc trong trường hợp đó? – NeilDA

+0

@NeilDA: không - điều đó sẽ không hoạt động, vì bạn cần nhân với 1.0 (không thay đổi) hoặc 2.0 ('* = 2.0f'). –

1

Tôi sẽ chỉ thêm vào câu trả lời tuyệt vời của Phao-lô mà bạn chỉ cần làm một so sánh đơn, bằng cách tận dụng sự đối xứng về số không:

const __m128 absMask = (__m128)_mm_set1_epi32(0x7fffffff); 
const __m128 two = _mm_set1_ps(2.0f); 

for (int i = 0; i < n; i += 4) { 
    __m128 xv = _mm_load_ps(x + i); 
    __m128 av = _mm_load_ps(a + i); 
    __m128 absxv = _mm_and_ps(xv, absMask); // |x| 
    __m128 mask = _mm_cmpgt_ps(absxv, two); // |x| > 2 ? 
    xv = _mm_and_ps(xv, cv);    // |x| > 2 ? x : 0 
    av = _mm_add_ps(av, xv);    // |x| > 2 ? a + x : a + 0 
    _mm_store_ps(a + i, av); 
} 
+0

hiện nó vẫn hoạt động với av * = 2.0f thay vì + =? – NeilDA

+0

@NeilDA: tất nhiên. –