N = 500
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
for (int k = 0 ; k < N; ++k) {
C[i*N+j]+=A[i*N+k] * B[k*N+j];
}
}
}
执行时间(秒):1.1531820000
for (int j = 0; j < N; ++j) {
for (int k = 0 ; k < N; ++k) {
for (int i = 0; i < N; ++i) {
C[i*N+j]+=A[i*N+k] * B[k*N+j];
}
}
}
执行时间(秒):2.6801300000
矩阵声明:
A=(double*)malloc(sizeof(double)*N*N);
B=(double*)malloc(sizeof(double)*N*N);
C=(double*)malloc(sizeof(double)*N*N);
我运行测试5次而不是计算平均值。任何人都知道为什么会这样?
答案 0 :(得分:4)
使用第二个循环,当你在内循环中增加i时,你会一直进行很多大跳跃,并且在较小程度上k。缓存可能不是很满意。 第一个循环更好,如果你颠倒j和k的顺序,它甚至会更好。
这基本上是data locality的问题。在现代架构上访问主内存非常慢,因此您的CPU将保留最近访问的内存的缓存并尝试预取可能接下来访问的内存。这些缓存非常有效地加速了分组在相同小区域中的访问,或者访问遵循可预测模式的访问。
在这里,我们转变了一种模式,CPU会在内存中大幅跳跃,然后回到一个很好的大部分顺序模式,因此加速。