是否有一种快速的方法可以在C ++中乘以浮点数组的值,以优化此函数(其中count
是4的倍数):
void multiply(float* values, float factor, int count)
{
for(int i=0; i < count; i++)
{
*value *= factor;
value++;
}
}
解决方案必须适用于Mac OS X和Windows,Intel和非Intel。想想SSE,矢量化,编译器(gcc与MSVC)。
答案 0 :(得分:2)
如果您希望您的代码是跨平台的,那么您将不得不编写与平台无关的代码,或者您将不得不编写#ifdef
的负载。
您是否尝试了一些手动循环展开,并查看它是否有任何区别?
答案 1 :(得分:2)
由于您知道count
是4的倍数,因此您可以展开循环...
void multiply(float* values, float factor, int count)
{
count = count >> 2; // count / 4
for(int i=0; i < count ; i++)
{
*value *= factor;
*(value+1) *= factor;
*(value+2) *= factor;
*(value+3) *= factor;
value += 4;
}
}
答案 2 :(得分:2)
免责声明:很明显,这不适用于iPhone,iPad,Android或未来的等价物。
#include <mmintrin.h>
#include <xmmintrin.h>
__m128 factor4 = _mm_set1_ps(factor);
for (int i=0; i+3 < count; i += 4)
{
__m128 data = _mm_mul_ps(_mm_loadu_ps(values), factor4);
_mm_storeu_ps(values, data);
values += 4;
}
for (int i=(count/4)*4; i < count; i++)
{
*values *= factor;
value++;
}
答案 3 :(得分:2)
你有没有想过OpenMP?
大多数现代计算机都有多核CPU,而且几乎所有主流编译器似乎都内置了OpenMP。你几乎不需要任何费用就可以获得速度。
答案 4 :(得分:0)
最好的解决方案是保持简单,让编译器为您优化它。 海湾合作委员会了解SSE,SSE2,altivec以及其他什么。 如果您的代码太复杂,您的编译器将无法在每个可能的目标上对其进行优化。
答案 5 :(得分:0)
正如您所提到的,有许多架构都有SIMD扩展,SIMD可能是您在优化方面最好的选择。然而,它们都是特定于平台的,而C和C ++作为语言并不是SIMD友好的。
然而,您应该尝试的第一件事是为您的给定构建启用SIMD特定标志。编译器可以识别可以使用SIMD优化的模式。
接下来就是在适当的情况下使用编译器内在函数或汇编来编写特定于平台的SIMD代码。但是,您应该为没有优化版本的平台保留可移植的非SIMD实现。 #ifdef
在支持它的平台上启用SIMD。
最后,至少在ARM上但在英特尔不确定时,请注意较小的整数和浮点类型允许每个SIMD指令进行大量并行操作。
答案 6 :(得分:0)
我认为,没有太多可以做的事情会产生很大的影响。也许你可以使用OpenMP或SSE加快速度。但现代CPU已经非常快了。在某些应用程序中,内存带宽/延迟实际上是瓶颈而且会变得更糟。我们已经有三级缓存,需要智能预取算法来避免大量延迟。因此,考虑内存访问模式也是有意义的。例如,如果您实现了multiply
和add
,请按照以下方式使用它:
void multiply(float vec[], float factor, int size)
{
for (int i=0; i<size; ++i)
vec[i] *= factor;
}
void add(float vec[], float summand, int size)
{
for (int i=0; i<size; ++i)
vec[i] += summand;
}
void foo(float vec[], int size)
{
multiply(vec,2.f,size);
add(vec,9.f,size);
}
你基本上是在内存块上传递两次。根据矢量的大小,它可能不适合L1缓存,在这种情况下,两次传递会增加一些额外的时间。这显然是坏的,你应该尝试保持内存访问“本地”。在这种情况下,单个循环
void foo(float vec[], int size)
{
for (int i=0; i<size; ++i) {
vec[i] = vec[i]*2+9;
}
}
可能会更快。根据经验:尝试线性访问内存并尝试“本地”访问内存,我的意思是,尝试重用已在L1缓存中的数据。只是一个想法。