我是操作系统的初学者,我正在尝试理解一些代码片段。能告诉我这些代码片段之间的区别吗?
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;
}
不同的部分是双对于属性其中一个应该比另一个更快?如果是这样,请向我解释原因,因为我不明白。
答案 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)
只有当M
和N
值为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][..]
时,M
和N
会产生很大的问题。 M
不相同..例如,2
是N
而5
是int 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]
退出而存在问题,因此您尝试访问超出边界的原因未定义的行为。
因此,只有当M
和N
相同时,两个代码块才相同,否则两者都不同。
首先,第二个代码块是错误的,但您可以通过执行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阵列的内存布局和缓存系统的工作方式,其他人告诉我们,第一个版本可能比第二个版本表现更好。另一方面,编译器可以优化两个版本以执行相同的操作。