首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用标量高效C++实现大复数向量的乘法

用标量高效C++实现大复数向量的乘法
EN

Stack Overflow用户
提问于 2011-07-29 02:44:22
回答 4查看 2.5K关注 0票数 4

我目前正在尝试最有效地将复数数组(内存对齐方式与std::complex相同,但目前使用我们自己的ADT)与与复数数组大小相同的标量值数组进行就地乘法。

算法已经并行化了,即调用对象将工作拆分成线程。此计算是在数组上完成的,以百万为单位-因此,它可能需要一些时间才能完成。CUDA不是这个产品的解决方案,尽管我希望它是。我确实可以访问boost,因此有一些使用BLAS/uBLAS的潜力。

然而,我在想,SIMD可能会产生更好的结果,但我对如何处理复数还不够熟悉。我现在拥有的代码如下(请记住,这段代码被分成与目标机器上的内核数量相对应的线程)。目标机器也是未知的。因此,通用的方法可能是最好的。

代码语言:javascript
复制
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的定义如下:

代码语言:javascript
复制
struct fcomplex
{
    float real;
    float imag;
};

我尝试过手动展开循环,因为我的最终循环计数将始终是2的幂,但编译器已经为我做了这件事(我已经展开到32次)。我尝试了一个对标量的常量浮点引用--我想我会保存一次访问--事实证明这与编译器已经在做的事情是相等的。我已经尝试了STL和transform,这两个游戏的结果很接近,但仍然更糟。我还尝试了强制转换为std::complex,并允许它使用用于标量* complex的重载运算符进行乘法运算,但这最终产生了相同的结果。

那么,有谁有什么想法吗?非常感谢您花时间考虑这一点!目标平台为Windows。我使用的是Visual Studio 2008。产品不能同时包含GPL代码!非常感谢。

EN

Stack Overflow用户

回答已采纳

发布于 2011-07-29 03:42:53

使用SSE可以很容易地做到这一点,例如

代码语言:javascript
复制
void cmult_scalar_inplace(fcomplex *values, const int start, const int end, 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);
    }
}

请注意,valuesscalar需要16字节对齐。

或者,您可以直接使用英特尔ICC编译器,让它为您完成繁重的工作。

更新

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

代码语言:javascript
复制
void cmult_scalar_inplace(fcomplex *values, const int start, const int end, 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, 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);
    }
}
票数 1
EN
查看全部 4 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6864053

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档