【问题标题】:optimize 2D array in C++在 C++ 中优化二维数组
【发布时间】:2010-05-01 10:53:31
【问题描述】:

我正在处理具有以下特征的二维数组:

const int cols = 500; 
const int rows = 100; 
int arr[rows][cols];

我通过以下方式访问数组 arr 来做一些工作:

for(int k = 0; k < T; ++k) { // for each trainee
  myscore[k] = 0;
  for(int i = 0; i < cols; ++i) { // for each sample  
    for(int j = 0; j < rows; ++j) { // for each expert
      myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
    }   
  }
}

所以我担心数组 'arr' 而不是另一个。我需要使它对缓存更友好,并提高速度。我在想也许可以转置数组,但我不知道该怎么做。我的实现结果只适用于方阵。我如何使它适用于非方阵?

另外,将二维数组映射到一维数组会提高性能吗?如果是这样,我该怎么做?最后,关于我如何优化它的任何其他建议......我已经没有想法了,但我知道 arr[j][i] 是我需要进行更改的地方,因为我正在访问列列而不是逐行,因此根本不适合缓存。

谢谢, 赫里斯托

【问题讨论】:

  • 示例矩阵是非正方形的。是不是像发布的那样坏了?你能把rowscols 放在循环条件中,这样我们就可以看到发生了什么?
  • 对此感到抱歉。我编辑了它

标签: c++ arrays 2d optimization


【解决方案1】:

一般的in-place matrix transposition非常困难的,但是如果您可以将其转置到另一个数组中,那么它非常简单。

const int cols = 500; 
const int rows = 100; 

int arr[rows][cols];
// fill arr[][]

int arrT[cols][rows];
for (int r = 0; r < rows; r++) {
   for (int c = 0; c < cols; c++) {
      arrT[c][r] = arr[r][c];
   }
}

当然,根据您获取arr[][] 的方式,您可以直接填写arrT[][]

但是,可能有一个更简单的解决方案,即简单地交换循环的顺序。

for(int k = 0; k < T; ++k) { // for each trainee
  myscore[k] = 0;
  for(int j = 0; j < rows; ++j) { // for each expert
    for(int i = 0; i < cols; ++i) { // for each sample  
      myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
    }   
  }
}

【讨论】:

  • 我尝试交换 j 和 i 循环,不幸的是它运行速度比其他方式慢,这没有意义。
【解决方案2】:

是的,1d 应该比 2d 快。 C 和 C++ 数组始终是 1d(内部)。 当你打电话给像

array[row][col]

编译器实际计算

col + row * maxcols

并将其用作一维数组的实际索引。你也可以自己做。在整个数组中循环会更快,并且随机访问将与在 2d 数组中一样快。

【讨论】:

  • 您能否解释一下您所说的“循环遍历整个数组会更快,随机访问将与二维数组一样快”是什么意思。我不是很关注你。
  • 循环一维数组不需要额外的计算,只需递增迭代器值并将其用作索引。随机访问需要计算“col+row*maxcols”索引值。
【解决方案3】:
  for(int i = 0; i < N; ++i) { // for each sample  
    for(int j = 0; j < E[i]; ++j) { // for each expert
      ... arr[j][i] ... // each ++j causes a large stride => poor caching
    }   
  }

转置循环:

  for(int j = 0; j < E[i]; ++j) { // for each expert
    for(int i = 0; i < N; ++i) { // for each sample  
      ... arr[j][i] ... // each ++i looks to the next word in memory => good
    }   
  }

当然,如果没有看到程序中的所有其他内容,我不能说这是否会导致问题。如果delta没有副作用,应该没问题。

【讨论】:

  • 我已经这样做了,但运行速度较慢,这无济于事。我一直在隐瞒的是,它使用英特尔的 TBB 运行,并且针对多个内核进行了并行化。它应该运行得更快 b/c 它对缓存更友好,但事实并非如此:/
  • @hristo:听起来你完全误导了我们关于程序的作用以及限制其性能的因素。以后请不要隐瞒这样的事情。
【解决方案4】:

您希望内存访问是相邻的。在您的情况下,只需在访问 arr 时交换 I 和 j。

【讨论】:

  • 这没有意义。我会段错误。我同意我想访问顺序内存,但我认为这不是这样做的方法。
  • @hristo: 也交换数组的维度,所以交换(转置)i 和 j 是有效的
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 2022-11-29
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多