我有以下代码用于计算两个向量之间的距离:
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时间。我的问题是:是否有可能以某种方式优化此功能?
注意:
答案 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算法的性能,并且效果非常好。