代码片段有什么区别?

What is the difference in the Code Snippets?

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

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;
  }

不同的部分是双重的对于属性其中一个应该比另一个快吗??如果可以,请您解释一下原因,因为我不明白。

在第一个例子中:

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]

有了这个改变,两个版本在功能上是相同的,即产生相同的结果。它们仅在添加元素的顺序上有所不同。

由于二维数组的内存布局和缓存系统的工作方式,第一个版本的性能可能优于第二个。另一方面,编译器可能会优化这两个版本以使其性能相同。

仅当 MN 值为 equal 时,两个代码才相似,否则两个代码块不同。

Case-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 列的数组,您正在对每个行-列元素求和 sum+=a[i][j]。这是一个很好的代码,因为外循环旋转等于行数,内循环旋转等于列数。

Case-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 不相同,则会产生一个大问题。例如,M2N5 即它像 int a[2][5] 和外循环从 0 迭代到 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;
}

正如其他人所说,由于二维数组的内存布局和缓存系统的工作方式,第一个版本的性能可能优于第二个。另一方面,编译器可能会优化这两个版本以使其性能相同。

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

然而,由于多维数组的元素在内存中的存储方式和缓存架构,在最内层循环 中循环最后一个数组维度可以 比其他方式更快现代 CPU。

此处要搜索的字词是 'cache locality' 和 'stride of arrays'