最快的方式通过2d数组传播c++

Fastest way to propgate through a 2d Array C++

本文关键字:数组 传播 c++ 2d 方式通      更新时间:2023-10-16

我有2个大的2d数组,这是100 *100。它有一个大的循环来做几次运算。它里面有3个循环;第一个循环在arr1中存储arr2中每个单元格的和乘以数字,第二个循环将两个数组流式传输到文件中,第三个循环在arr2中存储两个数组的和除以数字。

代码解释得更好:

for(int i=1;i<x+1;i++) {//initialize
    for(int j=1;j<y+1;j++) {
        arr1[i][j]=i*j*5.5;
        arr2[i][j]=0.;
    }
}
for (int i=0;i<x+2;i++) {//padding
    vi[i][0]=5;
    vi[i][y+1]=-5;
}
for (int j=0;j<y+2;j++) {//padding
    vi[0][j]=10.;
    vi[x+1][j]=-10.;
}
for(int t=0;t<times;++t) {
    for(int i=1;i<x+1;++i) {
        for(int j=1;j<y+1;j++) {
            arr2[i][j]=(arr1[i+1][j]+arr1[i-1][j]+arr1[i][j-1]+arr1[i][j+1])*1.5;
        }
    }
    arr2[1][1]=arr2[1][y]=arr2[x][1]=arr2[x][y]=0.;
    for(int i=1;i<x+1;++i) {
        for(int j=1;j<y+1;j++) {
            arr1[i][j]=(arr1[i][j]+arr2[i][j])*0.5;
            if(arr2[i][j]+arr1[i][j]>5.)
                cout<<"n"<<t<<"  "<<i-1<<" "<<j-1<<" "<<arr1[i][j]<<" "<<arr2[i][j];
        }
    }
}

整个代码的工作时间超过14秒。我应该如何优化代码工作在最快的时间可能。

您可以使用第三个数组来临时存储arr2的数组值,以便下次运行。第一个循环完成后,用临时数组覆盖arr2—这样就不需要第二个循环了。你可以节省一半的时间。

for (n=0;n<x;n++)
{
   for (i=0;i<maxi;i++)
   {
      for (j=0;j<maxj;j++)
      {
         arr1[i][j]=(arr2[i+1][j]+arr2[i-1][j]+arr2[i][j+1]+arr2[i][j-1])*1.5;
         arr_tmp[i][j] = (arr1[i][j]+arr2[i][j])*0.5;
      }
   }
   arr2 = arr_tmp;
}

注意: OP的代码发生了巨大的变化,以响应关于填充等的评论。原来的代码并没有什么问题——这就是我给出这个答案的基础。

假设您的2D数组以row-major为索引(第一个索引是行,第二个索引是列),那么您的内存访问已经按照最佳缓存利用率的正确顺序进行了(您正在访问附近的元素)。您的最新代码将此假设称为问题,因为您似乎已将'maxi'重命名为'x',这表明您正在索引列主 2D数组(这对于C/c++来说是非标准的)。

它没有指定你如何声明你的2D数组,这可能会有所不同,但我得到了一个很大的改进,通过转换你的实现使用原始指针。我还通过组合操作和交替每次迭代的方向来消除第二个循环(来自您的原始帖子)。我改变了权重系数,使它们相加为1.0,这样我就可以更容易地进行测试(通过生成图像输出)。

typedef std::vector< std::vector<double> > Array2D;
void run( int x, Array2D & arr2 )
{
   Array2D temp = arr2; // easy way to create temporary array of the correct size
   int maxi=arr2.size(), maxj=arr2[0].size();
   for (int n=0;n<x;n++)
   {
      Array2D const & src = (n&1)?temp:arr2; // alternate direction
      Array2D & dst = (n&1)?arr2:temp;
      for (int i=1;i<maxi-1;i++)
      {
         double const * sp0=&src[i-1][1], * sp1=&src[i][1], * sp2=&src[i+1][1];
         double * dp=&dst[i][1];
         for (int j=1;j<maxj-1;j++)
         {
            dp[0]=(sp0[0]+sp1[-1]+4*sp1[0]+sp1[+1]+sp2[0])*0.125;
            dp++, sp0++, sp1++, sp2++;
         }
      }
   }
   if ( (x&1) ) arr2=temp; // copy the result back if the iteration count was odd
} /**/

您可以查看的其他内容(有点依赖于平台):

  • restrict关键字指针(非标准c++)
  • 预取请求——一种特定于编译器/处理器的减少内存访问延迟的方法
  • 确保在编译
  • 时启用了优化
  • 根据数组的大小,您可能会发现将算法列化以更好地利用可用的缓存
  • 是有利的

充分利用可用的计算资源(非常依赖于平台):

    创建基于simd的实现
  • 充分利用你的多核CPU——OpenMP
  • 充分利用你的GPU——OpenCL