我已经实现了一种算法,该算法在某些时候需要计算向量元素的幂的总和。功率是正的双倍,在循环期间是恒定的。我发现,这个计算目前是我的程序的瓶颈,并想知道是否有办法加速以下代码片段:
double SumOfPowers(std::vector<double>& aVector,double exponent)
{
double help = 0;
size_t sizeOfaVector = aVector.size();
for (size_t k = 0; k < sizeOfaVector; k++)
{
help += std::pow(aVector[k], exponent);
}
return help;
}
我有一种感觉,好像可以利用循环期间指数是常量的事实并减少昂贵的std :: pow调用。有没有人知道更好的实现方法,或者是否有可以使用的库函数来完成这项工作?
答案 0 :(得分:3)
首先,检查循环是否为矢量化。为此,用-O3
构建你的程序(这里和下面我假设gcc编译器;我不太了解其他编译器,但我希望它们有类似的选项)。添加-ftree-vectorizer-verbose=2
选项以获取有关哪些循环被矢量化的详细输出。您可能想要使用选项来获得所需的输出。
如果循环没有矢量化,那么你可以使它矢量化。您可能需要更改循环结构(例如,首先将所有幂计算到一个单独的数组中,然后才计算总和),或者使用某种方式告诉编译器更多信息,例如restrict
声明,有关更多讨论,请参阅"Auto-vectorization with gcc 4.7"。在最糟糕的情况下,我认为,您可以手动实现矢量化,我记得有这样的功能,请参阅Intel's reference或"A practical guide to SSE SIMD with C++"。
对于Visual Studio,首先添加/Qvec-report:2
选项以获取详细报告。上述所有其他建议也适用,您只需要找到相应的MSVC选项。
另一种加快速度的方法是使用-ffast-math
选项牺牲精度。 AFAIK,标准pow
函数使用一些高级逻辑来检查基数或指数实际上接近1的情况,以避免出现精度问题。如果不是这种情况,您可能不需要这种逻辑。我想-ffast-math
会丢掉它,尽管你可能想检查一下。
无论如何,您只需将pow
替换为exp(log(...)*...)
即可手动避免这些检查。这不会给你太多的加速,但你可能会注意到一些好处。此外,如果您经常将相同的向量提升到不同的指数,您可以预先计算log
s。
答案 1 :(得分:2)
不,常量指数不允许可行的优化,除非您的值经常重复(如果是这样:memoize)。 Parallelize是你最好的选择(或根本不pow
)