Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 如何使用SSE指令集绝对2个双浮点数或4个浮点数?(至SSE4)_Gcc_Sse - Fatal编程技术网

Gcc 如何使用SSE指令集绝对2个双浮点数或4个浮点数?(至SSE4)

Gcc 如何使用SSE指令集绝对2个双浮点数或4个浮点数?(至SSE4),gcc,sse,Gcc,Sse,这是我试图使用SSE加速的示例C代码,两个数组的长度为3072个元素,带有双精度,如果我不需要双精度,可以将其降为浮点 double sum = 0.0; for(k = 0; k < 3072; k++) { sum += fabs(sima[k] - simb[k]); } double fp = (1.0 - (sum / (255.0 * 1024.0 * 3.0))); double sum=0.0; 对于(k=0;k

这是我试图使用SSE加速的示例C代码,两个数组的长度为3072个元素,带有双精度,如果我不需要双精度,可以将其降为浮点

double sum = 0.0;

for(k = 0; k < 3072; k++) {
    sum += fabs(sima[k] - simb[k]);
}

double fp = (1.0 - (sum / (255.0 * 1024.0 * 3.0)));
double sum=0.0;
对于(k=0;k<3072;k++){
sum+=fabs(sima[k]-simb[k]);
}
双浮点=(1.0-(和/(255.0*1024.0*3.0));
无论如何,我当前的问题是如何在SSE寄存器中对double或float执行fabs步骤,这样我就可以将整个计算保持在SSE寄存器中,这样它就保持快速,并且我可以通过部分展开这个循环来并行化所有步骤


以下是我找到的一些资源,或者可能是第二个资源的缺点需要进行条件检查。

最简单的方法可能是:

__m128d vsum = _mm_set1_pd(0.0);        // init partial sums
for (k = 0; k < 3072; k += 2)
{
    __m128d va = _mm_load_pd(&sima[k]); // load 2 doubles from sima, simb
    __m128d vb = _mm_load_pd(&simb[k]);
    __m128d vdiff = _mm_sub_pd(va, vb); // calc diff = sima - simb
    __m128d vnegdiff = mm_sub_pd(_mm_set1_pd(0.0), vdiff); // calc neg diff = 0.0 - diff
    __m128d vabsdiff = _mm_max_pd(vdiff, vnegdiff);        // calc abs diff = max(diff, - diff)
    vsum = _mm_add_pd(vsum, vabsdiff);  // accumulate two partial sums
}
\uuum128d vsum=\umm\uset1\upd(0.0);//初始部分和
对于(k=0;k<3072;k+=2)
{
__m128d va=_mm_load_pd(&sima[k]);//从sima、simb加载2个双倍
__m128d vb=_mm_load_pd(&simb[k]);
__m128d vdiff=_mm_sub_pd(va,vb);//calc diff=sima-simb
__m128d vnegdiff=mm_sub_pd(_mm_set1_pd(0.0),vdiff);//计算负差异=0.0-差异
__m128d vabsdiff=_mm_max_pd(vdiff,vnegdiff);//计算abs diff=max(diff,-diff)
vsum=_mm_add_pd(vsum,vabsdiff);//累加两个部分和
}
请注意,这可能不会比现代x86 CPU上的标量代码快多少,因为现代x86 CPU通常有两个FPU。然而,如果您可以降低到单精度,那么您很可能会获得2倍的吞吐量改进


还要注意的是,您需要在循环后将
vsum
中的两个部分和组合成一个标量值,但这是相当简单的操作,并且不是性能关键。

我建议使用位and和掩码。正值和负值具有相同的表示形式,只有最高有效位不同,正值为0,负值为1,请参阅。您可以使用以下选项之一:

inline __m128 abs_ps(__m128 x) {
    static const __m128 sign_mask = _mm_set1_ps(-0.f); // -0.f = 1 << 31
    return _mm_andnot_ps(sign_mask, x);
}

inline __m128d abs_pd(__m128d x) {
    static const __m128d sign_mask = _mm_set1_pd(-0.); // -0. = 1 << 63
    return _mm_andnot_pd(sign_mask, x); // !sign_mask & x
}
inline\uuum128 abs\ups(\uuuuum128 x){

静态常数uum128符号mask=mm_set1_ps(-0.f);/-0.f=1x和x的最大值应为abs(x)。代码如下:

x = _mm_max_ps(_mm_sub_ps(_mm_setzero_ps(), x), x)

我处理部分和的第二部分花了我一点时间,但总体上整个解决方案都起了作用。谢谢你!@Pharaun:谢谢你的反馈-你是否对SSE代码与原始标量代码进行了基准测试,如果是的话,你看到了多大的性能改进?@Paul使用单线程实现,我完成了20%,但通过openMP使用多线程时,这只是一个百分比,因此我仍然需要对其进行调整,并考虑将其移到浮点实现以获得更高的性能。@Paul,刚刚将其移到浮点实现,在普通C上的执行时间减少了约15%到30%,即使启用了openMP,这似乎也有帮助“我的内存带宽+四次泵送浮点值带来了一场大胜。@Pharaun:太好了-很高兴它有帮助。如果你能升级到最新的Sandy Bridge CPU并使用AVX,那么你应该会看到更大的改进。(AVX的浮点值为8倍,而SSE的浮点值为4倍)是的,当我发布这个问题时,我没有意识到这个技巧,但是的,它确实有意义:)当我有时间的时候,我会看看这个,但我想评论一下OpenMP方面……我在这个问题中使用/呈现的片段是另一个大得多的循环中的嵌套循环,我在外部循环中使用OpenMP,而不是内部循环循环:)但是如果OpenMP用于这个较小的内部循环,你是对的。您好,我能够实现这一点,并且它确实将速度提高了几个百分点,这很好:)我真的很喜欢Agner Fog的手册,它们真的很好!
x = _mm_max_ps(_mm_sub_ps(_mm_setzero_ps(), x), x)