C ++中双减法的优化

时间:2012-02-14 19:28:57

标签: c++ performance optimization

我有以下代码用于计算两个向量之间的距离:

double dist(vector<double> & vecA, vector<double> & vecB){
    double curDist = 0.0;
    for (size_t i = 0; i < vecA.size(); i++){
        double dif = vecA[i] - vecB[i];
        curDist += dif * dif;
    }

    return curDist;
}

此功能是我应用程序的主要瓶颈,因为它依赖于大量距离计算,在典型输入上占用超过60%的CPU时间。此外,还有以下一行:

double dif = vecA[i] - vecB[i];

在此功能中占用超过77%的CPU时间。我的问题是:是否有可能以某种方式优化此功能?

注意:

  • 要分析我的应用程序,我使用的是Intel Amplifier XE;
  • 减少距离计算的数量不是一个可行的解决方案 我;

4 个答案:

答案 0 :(得分:5)

我现在可以想到两个可能的问题:

  • 此计算受内存限制。
  • curDist上存在迭代到迭代的依赖关系。

此计算受内存限制。

您的数据集大于CPU缓存。因此,在这种情况下,除非您可以重构算法,否则任何优化都无济于事。


curDist存在迭代到迭代的依赖关系。

您依赖curDist。这将阻止编译器进行矢量化。 (另外,不要总是相信分析器编号到行。它们可能不准确,特别是在编译器优化之后。)

通常,编译器矢量化器可以将curDist拆分为多个部分和,然后展开/向量化循环。但它不能在严格浮点行为下做到这一点。如果你还没有,你可以尝试放松你的浮点模式。或者您可以拆分总和并自行展开。

例如,这种优化是编译器可以用整数做的事情,但不一定用浮点

double curDist0 = 0.0;
double curDist1 = 0.0;
double curDist2 = 0.0;
double curDist3 = 0.0;
for (size_t i = 0; i < vecA.size() - 3; i += 4){
    double dif0 = vecA[i + 0] - vecB[i + 0];
    double dif1 = vecA[i + 1] - vecB[i + 1];
    double dif2 = vecA[i + 2] - vecB[i + 2];
    double dif3 = vecA[i + 3] - vecB[i + 3];
    curDist0 += dif0 * dif0;
    curDist1 += dif1 * dif1;
    curDist2 += dif2 * dif2;
    curDist3 += dif3 * dif3;
}

//  Do some sort of cleanup in case (vecA.size() % 4 != 0)

double curDist = curDist0 + curDist1 + curDist2 + curDist3;

答案 1 :(得分:3)

对于循环的每次迭代,您可以消除对vecA.size()的调用,只需在循环之前调用一次。你也可以循环展开,为每个循环迭代提供更多的计算。你使用什么编译器,以及什么优化设置?编译器通常会为您展开,但您可以手动执行此操作。

答案 2 :(得分:2)

如果可行(如果数字的范围不大),您可能想要使用固定点来探索这些数字而不是双数。

固定点会将这些转换为int操作而不是双操作。

另一个有趣的事情是假设你的个人资料是正确的,查找似乎是一个重要因素(否则乘法可能比减法更昂贵)。

我尝试使用const向量迭代器而不是随机访问查找。它可能有两种方式:1 - 它是常量,2 - 迭代器的串行性质可以让处理器做更好的缓存。

答案 3 :(得分:0)

如果您的平台没有(或没有使用)支持浮点数学的ALU,浮点库本质上很慢并且消耗额外的非易失性存储器。我建议改为使用32位(long)或64位(long long)定点算法。然后将最终结果转换为算法结束时的浮点数。几年前我在一个项目上做了这个,以提高I2T算法的性能,并且效果非常好。