我很难理解为什么这个代码以英特尔编译器12以极快的速度运行,并且使用英特尔编译器16真的变慢了
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i,t;
int n=10000000;
int T=1000;
time_t t1,t2;
// double A[n],B[n],C[n];
double *A = (double*) malloc (sizeof(double)*n);
double *B = (double*) malloc (sizeof(double)*n);
double *C = (double*) malloc (sizeof(double)*n);
for (i=0;i<n;i++)
{
A[i]=1.0;
B[i]=2.0;
}
t1=clock();
for (t=0;t<T;t++)
for (i=0;i<n;i++)
C[i]=A[i]*B[i];
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += C[i];
printf("sum %f\n",sum);
printf("time %f\n",(double)(t2-t1)/CLOCKS_PER_SEC);
}
生成文件: icc -O2 -o array array.c
答案 0 :(得分:5)
可能,其中一个编译器积极地优化了整个繁琐的嵌套循环。您的优化代码似乎最终会以:
结束t1=clock();
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += A[i]*B[i];
编译器完成这样的优化是完全没问题的。您可以通过创建循环迭代器volatile
来阻止优化。
确保在两个编译器上都启用了相同级别的优化。
答案 1 :(得分:2)
两个嵌套循环是可向量的,只要编译器确保A
,B
和C
指向的三个内存区域不是别名。具体而言,通过C
和A
永远无法再次读取存储到B
中的值 - 如果循环的迭代并行运行,则会带来负载和存储的危险除此之外的其他顺序。
在一般情况下,编译器将无法从函数调用返回的指针推断出这一点,尽管它可能合法地了解标准库函数(如malloc()
)的语义。仅功能签名就可以推断。
您看到的差异可能是由于编译器版本之间的别名规则严格性的变化 - 或者可能来自不同的默认选项开关。
将restrict
限定符添加到指针声明会告诉编译器它可以假定通过使用指针不会发生别名,并且程序员有责任保证这一点。
double * restrict A = malloc (sizeof(double)*n);
double * restrict B = malloc (sizeof(double)*n);
double * restrict C = malloc (sizeof(double)*n);