用常数双指数优化幂之和

时间:2015-05-28 12:56:53

标签: c++ optimization

我已经实现了一种算法,该算法在某些时候需要计算向量元素的幂的总和。功率是正的双倍,在循环期间是恒定的。我发现,这个计算目前是我的程序的瓶颈,并想知道是否有办法加速以下代码片段:

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调用。有没有人知道更好的实现方法,或者是否有可以使用的库函数来完成这项工作?

2 个答案:

答案 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