我正在为考试而学习,并试图解决这个问题:
我有以下 C 代码来做一些数组初始化:
int i, n = 61440;
double x[n];
for(i=0; i < n; i++) {
x[i] = 1;
}
但以下运行速度更快(1000 次迭代中的差异为 0.5 秒):
int i, n = 61440;
double x[n];
for(i=n-1; i >= 0; i--) {
x[i] = 1;
}
我首先认为这是由于访问 n 变量的循环,因此必须进行更多读取(如此处建议的,例如: Why is iterating through an array backwards faster than forwards )。但即使我将第一个循环中的 n 更改为硬编码值,反之亦然,将底部循环中的 0 移动到一个变量,性能仍然保持不变。我还尝试将循环更改为只完成一半的工作(从 0 到 < 30720,或从 n-1 到 >= 30720),以消除对 0 值的任何特殊处理,但底部循环仍然更快
我认为这是因为一些编译器优化?但是我查找生成的机器代码的所有内容都表明 < 和 >= 应该相等。
感谢您的任何提示或建议!谢谢!
编辑:Makefile,用于编译器详细信息(这是多线程练习的一部分,因此是 OpenMP,但对于这种情况,它全部运行在 1 个内核上,代码中没有任何 OpenMP 指令)
#CC = gcc
CC = /opt/rh/devtoolset-2/root/usr/bin/gcc
OMP_FLAG = -fopenmp
CFLAGS = -std=c99 -O2 -c ${OMP_FLAG}
LFLAGS = -lm
.SUFFIXES : .o .c
.c.o:
${CC} ${CFLAGS} -o $@ $*.c
sblas:sblas.o
${CC} ${OMP_FLAG} -o $@ $@.o ${LFLAGS}
Edit2:我用 n * 100 重新进行了实验,得到了相同的结果:
前进:~170s
向后:~120s
与之前的值 1.7s 和 1.2s 类似,只是乘以 100
编辑 3:最小示例 - 上面描述的所有更改都本地化为 vector 更新方法。这是默认的向前版本,比向后版本花费的时间更长
for(i = limit - 1; i >= 0; i--)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
void vector_update(double a[], double b[], double x[], int limit);
/* SBLAS code */
void *main() {
int n = 1024*60;
int nsteps = 1000;
int k;
double a[n], b[n], x[n];
double vec_update_start;
double vec_update_time = 0;
for(k = 0; k < nsteps; k++) {
// Loop over whole program to get reasonable execution time
// (simulates a time-steping code)
vec_update_start = omp_get_wtime();
vector_update(a, b, x, n);
vec_update_time = vec_update_time + (omp_get_wtime() - vec_update_start);
}
printf( "vector update time = %f seconds \n \n", vec_update_time);
}
void vector_update(double a[], double b[], double x[] ,int limit) {
int i;
for (i = 0; i < limit; i++ ) {
x[i] = 0.0;
a[i] = 3.142;
b[i] = 3.142;
}
}
Edit4:CPU 是 AMD 四核 Opteron 8378。机器使用了其中的 4 个,但我在主处理器上只使用了一个(AMD 架构中的核心 ID 0)
最佳答案
这不是反向迭代,而是与零的比较导致第二种情况下的循环运行得更快。
for(i=n-1; i >= 0; i--) {
与零的比较可以用一条汇编指令完成,而与任何其他数字的比较则需要多条指令。
关于c - 为什么在 C 中向后迭代数组比向前迭代快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52833586/