我和icc有点问题,到目前为止我还没有找到任何解决方案。我的程序在用gcc编译时运行正常,但在用icc编译时显然不执行任何操作。未出现运行时错误。程序结束得非常快(几毫秒),但预计需要几秒钟(n=10亿,大约11秒)。但是,如果我在最后打印总和,它就可以正常工作。
这是一小段代码:
# include <stdlib.h>
# include <stdio.h>
double f(double x){
double pi = 3.141592653589793;
double value;
value = 50.0 / (pi * (2500.0 * x * x + 1.0));
return value;
}
int main (int argc, char *argv[]){
double a = 0.0, b = 10.0, total = 0.0, x;
unsigned long int i, n = 1000000000;
for(i = 0; i < n; i++){
x = ((n - i - 1) * a + (i) * b) / (n - 1);
total = total + f(x);
}
total = (b - a) * total / (double) n;
//printf("%f\n", total);
return 0;
}
我还检查了它是否真的运行了循环,并调用了函数n次。
有没有人知道是什么导致了这个问题?
谢谢!
发布于 2018-05-28 16:28:56
但是,如果我在最后打印总和,它就可以正常工作。
这可能是optimizing compiler效应(根据C11标准n1570,这是合法的)。
由于您的程序中没有可见的side-effect (没有printf
),因此允许编译器(根据as-if rule)将其优化为无操作程序。
对于某些版本的GCC或Clang,以及一些optimization flags,您可以观察到同样的情况。尝试使用gcc -O3 -S -fverbose-asm
编译您的代码,并查看生成的汇编代码(在Linux/x86-64上,您将观察到在Linux/x86-64上使用GCC 8.1生成的空main
)。
有人知道是什么导致了这个问题吗?
您的代码,以及您对复杂的C语言semantics的误解。实现的行为符合C标准(并且您的程序运行正常)。
顺便说一句,即使有了printf
,理论上编译器也可以将你的程序优化成一个简单的常量printf
。在实践中,当前的编译器(可悲的是)并不那么聪明。
如果您想要一些健壮的基准测试,n
可以依赖于程序参数(并且您仍然需要保留printf
,因为您想要一些可见的副作用):
unsigned long n = (argc<2)?1000:(unsigned long)atol(argv[1]);
在测量性能时,不要忘记在编译器中启用优化!
顺便说一句,在几年内(在学习了更多的CS课程,包括编译课程,和/或读过Dragon Book之后),你可能会尝试实现一些GCC plugin,它可以通过显式的printf
(但n
仍然被初始化为编译时常量)来优化你的函数,只需调用一些printf
并在编译时执行循环计算total
(这样的优化是合法的)。您会发现进行这样的优化需要大量的工作(当然是几个月,可能是几年!),并且not可能适用于许多现有的程序,但是您可以享受实现它的乐趣。
如果您对浮点计算感兴趣,请务必阅读floating point guide (它很棘手)。
https://stackoverflow.com/questions/50562050
复制相似问题