Code Snippets有什么区别?

时间:2018-06-04 07:36:09

标签: arrays stride cache-locality

我是操作系统的初学者,我正在尝试理解一些代码片段。能告诉我这些代码片段之间的区别吗?

int sum_array_rows(int a[M][N])
 {
    int i,j,sum=0;
    for(i=0;i<M;i++)
      for(j=0;j<N;j++)
        sum+=a[i][j];
    return sum;
  }

int sum_array_col(int a[M][N])
 {
    int i,j,sum=0;
    for(i=0;i<N;i++)
      for(j=0;j<M;j++)
        sum+=a[i][j];
    return sum;
  }

不同的部分是双对于属性其中一个应该比另一个更快?如果是这样,请向我解释原因,因为我不明白。

3 个答案:

答案 0 :(得分:2)

正如其他人所说,如果数组维度不相同,第二个代码段可能会导致溢出错误,因此需要修复此问题。

然而,由于多维数组的元素如何存储在内存和现代CPU的缓存体系结构中,因此在最内层循环中的最后一个数组维度的循环可以更快。 / p>

这里要搜索的术语是“缓存局部性”和“数组步幅”

答案 1 :(得分:1)

在第一个例子中:

i将获得值0,1,2,...,M-1

j将获得值0,1,2,...,N-1

所以sum计算为

sum = a[0][0] + a[0][1] + a[0][2] + ... + a[0][N-1] +
      a[1][0] + a[1][1] + a[1][2] + ... + a[1][N-1] +
      a[2][0] + a[2][1] + a[2][2] + ... + a[2][N-1] +
      ...
      ...
      a[M-1][0] + a[M-1][1] + a[M-1][2] + ... + a[M-1][N-1]

在第二个例子中,这已被切换,以便

i将获得值0,1,2,...,N-1

j将获得值0,1,2,...,M-1

所以现在

sum = a[0][0] + a[0][1] + a[0][2] + ... + a[0][M-1] +
      a[1][0] + a[1][1] + a[1][2] + ... + a[1][M-1] +
      a[2][0] + a[2][1] + a[2][2] + ... + a[2][M-1] +
      ...
      ...
      a[N-1][0] + a[N-1][1] + a[N-1][2] + ... + a[N-1][M-1]

请注意,第二个版本错误,因为参数为int a[M][N],即合法的第一个索引为0..M-1,合法的第二个索引为0..N-1换句话说,如果N和M不同,则第二个版本访问数组越界。

使第二个例子正确。此行sum+=a[i][j];应为sum+=a[j][i];,以便sum现在为:

sum = a[0][0] + a[1][0] + a[2][0] + ... + a[M-1][0] +
      a[0][1] + a[1][1] + a[2][1] + ... + a[M-1][1] +
      a[0][2] + a[1][2] + a[2][2] + ... + a[M-1][2] +
      ...
      ...
      a[0][N-1] + a[1][N-1] + a[2][N-1] + ... + a[M-1][N-1]

通过该更改,两个版本在功能上相同,即产生相同的结果。它们只是添加元素的顺序不同。

由于2D阵列的内存布局和缓存系统的工作方式,第一个版本的性能可能优于第二个版本。另一方面,编译器可以优化两个版本以执行相同的操作。

答案 2 :(得分:0)

只有当MN值为equal时,两个代码的工作方式才相似,否则两个代码块都不同。

案例1: - 请查看以下代码块

int sum_array_rows(int a[M][N]) {
    int i,j,sum=0;
    for(i=0;i<M;i++)
      for(j=0;j<N;j++)
        sum+=a[i][j];
    return sum;
}

此处a是一系列M行和N列&amp;您正在按sum+=a[i][j]对每个行列元素求和。这是一个很好的代码,因为外循环旋转等于行数,内循环旋转等于列数。

案例2 : - 现在看第二个代码块,它会导致溢出。

int sum_array_rows(int a[M][N]) {
    int i,j,sum=0;
    for(i=0;i<N;i++)
      for(j=0;j<M;j++)
        sum+=a[i][j];
    return sum;
}

此处a也是M行和N列的数组。您的第一个外部for循环从0旋转到N,但您只有M行。当你执行sum+=a[i][..]时,MN会产生很大的问题。 M不相同..例如,2N5int a[2][5],即类似0,外部循环从{{迭代1}}到5,你继续做

  • sum+=a[0][j]然后

  • sum+=a[1][j]直到此罚款(bcz M = 2),但什么时候会这样做

  • sum+=a[2][j]sum+=a[3][j]等因为没有a[2][j]a[3][j]退出而存在问题,因此您尝试访问超出边界的原因未定义的行为

因此,只有当MN相同时,两个代码块才相同,否则两者都不同。

首先,第二个代码块是错误的,但您可以通过执行sum+=a[j][i]代替sum+=a[i][j]来纠正它

int sum_array_rows(int a[M][N]) {
    int i,j,sum=0;
    for(i=0;i<N;i++)
      for(j=0;j<M;j++)
        sum+=a[j][i];
    return sum;
}

由于2D阵列的内存布局和缓存系统的工作方式,其他人告诉我们,第一个版本可能比第二个版本表现更好。另一方面,编译器可以优化两个版本以执行相同的操作。