加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

通过标量有效地乘以大复数向量C.

发布时间:2020-12-16 07:35:42 所属栏目:百科 来源:网络整理
导读:我目前正在尝试最有效地执行复数数组的就地乘法(内存以与std :: complex相同的方式对齐,但目前使用我们自己的ADT)由一组标量值相同size作为复数数组. 该算法已经并行化,即调用对象将工作分成线程.这种计算是在数百万的数组上完成的 – 因此,可能需要一些时间
我目前正在尝试最有效地执行复数数组的就地乘法(内存以与std :: complex相同的方式对齐,但目前使用我们自己的ADT)由一组标量值相同size作为复数数组.

该算法已经并行化,即调用对象将工作分成线程.这种计算是在数百万的数组上完成的 – 因此,可能需要一些时间才能完成. CUDA不是这个产品的解决方案,尽管我希望如此.我确实可以获得提升,因此有一些使用BLAS / uBLAS的潜力.

然而,我想,SIMD可能会产生更好的结果,但我对如何使用复杂的数字做得不够熟悉.我现在的代码如下(请记住,这会被分成线程,这些线程对应于目标机器上的核心数).目标机器也是未知的.因此,通用方法可能是最好的.

void cmult_scalar_inplace(fcomplex *values,const int start,const int end,const float *scalar)
{
    for (register int idx = start; idx < end; ++idx)
    {
        values[idx].real *= scalar[idx];
        values[idx].imag *= scalar[idx];
    }
}

fcomplex的定义如下:

struct fcomplex
{
    float real;
    float imag;
};

我已经尝试手动展开循环,因为我的finally循环计数总是2的幂,但编译器已经为我做了这个(我已经展开到32).我已经尝试了对标量的const浮点引用 – 我认为我将保存一个访问权限 – 这证明与编译器已经在做的事情相同.我尝试过STL和转换,哪个游戏结果很接近,但还是更糟.我也试过转换为std :: complex并允许它使用重载运算符来进行乘法的标量*复合,但这最终会产生相同的结果.

那么,任何有想法的人?非常感谢您花时间考虑这个问题!目标平台是Windows.我正在使用Visual Studio 2008.产品也不能包含GPL代码!非常感谢.

解决方法

您可以使用SSE轻松完成此操作,例如

void cmult_scalar_inplace(fcomplex *values,const float *scalar)
{
    for (int idx = start; idx < end; idx += 2)
    {
        __m128 vc = _mm_load_ps((float *)&values[idx]);
        __m128 vk = _mm_set_ps(scalar[idx + 1],scalar[idx + 1],scalar[idx],scalar[idx]);
        vc = _mm_mul_ps(vc,vk);
        _mm_store_ps((float *)&values[idx],vc);
    }
}

请注意,值和标量需要16字节对齐.

或者您可以使用英特尔ICC编译器,让它为您完成艰苦的工作.

UPDATE

这是一个改进版本,它将循环展开2倍,并使用单个加载指令获得4个标量值,然后将其解压缩为两个向量:

void cmult_scalar_inplace(fcomplex *values,const float *scalar)
{
    for (int idx = start; idx < end; idx += 4)
    {
        __m128 vc0 = _mm_load_ps((float *)&values[idx]);
        __m128 vc1 = _mm_load_ps((float *)&values[idx + 2]);
        __m128 vk = _mm_load_ps(&scalar[idx]);
        __m128 vk0 = _mm_shuffle_ps(vk,vk,0x50);
        __m128 vk1 = _mm_shuffle_ps(vk,0xfa);
        vc0 = _mm_mul_ps(vc0,vk0);
        vc1 = _mm_mul_ps(vc1,vk1);
        _mm_store_ps((float *)&values[idx],vc0);
        _mm_store_ps((float *)&values[idx + 2],vc1);
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读