我目前正在尝试最有效地执行复数数组的就地乘法(内存以与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); } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。