2D矢量优化

2D Vector Optimization

本文关键字:优化 2D      更新时间:2023-10-16

这只是一个紧凑的测试用例,但我有双打的向量,我想填充所有成对差异的方形矩阵(2D矢量)。当使用-O3优化进行编译时,这在我的计算机上大约需要1.96秒(仅从嵌套的双循环中计算)。

#include <vector>
using namespace std;
int main(){
  vector<double> a;
  vector<vector<double> > b;
  unsigned int i, j;
  unsigned int n;
  double d;
  n=10000; //In practice, this value is MUCH bigger
  a.resize(n);
  for (i=0; i< n; i++){
    a[i]=static_cast<double>(i);
  }
  b.resize(n);
  for (i=0; i< n; i++){
    b[i].resize(n);
    b[i][i]=0.0; //Zero diagonal
  }
  for (i=0; i< n; i++){
    for (j=i+1; j< n; j++){
      d=a[i]-a[j];
      //Commenting out the next two lines makes the code significantly faster
      b[i][j]=d; 
      b[j][i]=d;
    }
  }
  return 0;
}

但是,当我评论两行:

b[i][j]=d; 
b[j][i]=d;

该程序在大约0.000003秒内完成(仅从嵌套的双循环计算)!我真的没想到这两行是限制速率的步骤。我已经盯着这个代码了一段时间,但我没有想法。任何人都可以就我如何优化这件简单的代码提供任何建议,以便大大减少时间?

当您评论这两行时,嵌套循环中剩下的一切都是保持计算d,然后丢弃结果。由于这不会对程序的行为产生任何影响,因此编译器只会优化嵌套循环。这就是程序几乎立即完成的原因。

实际上,我通过用g++ -O3进行两次编译代码来确认这一点,一次仅在嵌套环中使用d=a[i]-a[j]语句,然后完全删除了嵌套环。发射的代码是相同的。

尽管如此,您的代码目前比其所需的要慢,因为它缺少缓存。当您在这样的嵌套环中访问二维数组时,如果可能的话,您应该始终安排迭代通过内存连续。这意味着第二个索引应该是变化更快的索引。对b[j][i]的访问违反了此规则并缺少缓存。因此,让我们重写。

之前:

for (i=0; i< n; i++){
    for (j=i+1; j< n; j++){
        d=a[i]-a[j];
        b[i][j]=d; 
        b[j][i]=d;
    }
}

计时:

real    0m1.026s
user    0m0.824s
sys     0m0.196s

之后:

for (i = 0; i < n; i++) {
    for (j = 0; j < i; j++) {
        b[i][j] = a[j] - a[i];
    }
    for (j = i+1; j < n; j++) {
        b[i][j] = a[i] - a[j];
    }
}

计时:

real    0m0.335s
user    0m0.164s
sys     0m0.164s