通过2d Array C ++传播的最快方法

时间:2013-04-28 01:32:40

标签: c++ algorithm optimization multidimensional-array

我有2个大的2d阵列,这是100s * 100s。它有一个很大的循环来做几次操作。里面有3个循环; arr1中第一个循环存储arr2中每个单元格的总和乘以数字,第二个循环流将2个数组流式传输到一个文件,第三个循环存储在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秒。我应该如何优化代码以尽可能快地工作。

2 个答案:

答案 0 :(得分:1)

您可以使用第3个数组临时存储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;
}

答案 1 :(得分:1)

注意: OP的代码在响应有关填充等的评论时发生了巨大变化。原始代码并没有什么问题 - 这就是我根据这个答案所做的。

假设您的2D数组已编入索引 row-major (第一个索引是行,第二个索引是列),您的内存访问的顺序已经正确,以获得最佳缓存利用率(随着进度,您将访问附近的元素)。您的最新代码会对此假设提出质疑,因为您似乎已将其重命名为“maxi&#39;成为&#39; x&#39;这表明你正在索引一个 column-major 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