If 语句与 C 中的比较 SSE

Posted

技术标签:

【中文标题】If 语句与 C 中的比较 SSE【英文标题】:If statements with comparison SSE in C 【发布时间】:2013-03-12 21:49:53 【问题描述】:

我想实现这个:

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

我已经走了这么远,但不知道下一步该做什么:

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

【问题讨论】:

【参考方案1】:

你已经接近了:

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

诀窍是OR 两个比较结果,然后使用此组合结果作为掩码,使用按位AND 操作将未通过测试的 X 值归零。然后添加被掩码的 X 向量,它将根据掩码将 0 或原始 X 值添加到 A 的每个元素。


对于您在下面的评论中提到的替代版本,您可以这样做:

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


对于您在下面的后续 cmets 中提到的第三个版本 (a[i] *= 2.0),它有点棘手,但您可以通过将表达式视为 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);

【讨论】:

非常感谢。还有一件事,答案怎么会改变,而不是 a[i] += x[i],而是 a[i] += 2.0f? 我也遇到过a[i]*=2.0f。将 _mm_and_ps 替换为 _mm_mul_ps 似乎在这里不起作用。除非我做错了什么。在那种情况下它仍然有效吗? @NeilDA:不——这行不通,因为你需要乘以 1.0(无变化)或 2.0(*= 2.0f)。 @NeilDA:我现在在上面的答案中添加了第三种情况。 啊!我为此苦苦挣扎,并花了很长时间试图理解为什么它在 += 起作用的地方不起作用。希望我早一点知道这个技巧.. 谢谢:)【参考方案2】:

我只想通过利用关于零的对称性来补充 Paul 的出色答案,即您只需要进行一次比较:

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

【讨论】:

以上是关于If 语句与 C 中的比较 SSE的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的条件赋值语句和if——else语句执行效率比较,哪一个效率高些,坐等高手解惑

c语言中if语句条件为赋值语句

如何将结构字段与C中的变量进行比较? [复制]

SSE2:将二维数组中的有符号整数与双精度数相乘并将结果相加在 C 中

R语言中的if else语句

SSE 比较内在 - 如何从比较中获得 1 或 0?