我遇到了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 次。
有谁知道可能导致此问题的原因?
谢谢!
答案 0 :(得分:8)
然而,如果我在最后打印总数,它就可以了。
这可能是optimizing compiler效果(合法,符合C11标准n1570)。
由于程序中没有可见的side-effect(没有printf
),因此允许编译器(根据as-if rule)将其优化为无操作程序。< / p>
对于某些版本的GCC或Clang以及某些optimization flags,您可以观察到相同的情况。尝试使用gcc -O3 -S -fverbose-asm
编译代码并查看生成的汇编代码(您将在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
初始化为编译时常量)优化您的函数到main
只调用一些printf
并执行循环计算{ {1}}在编译时(这样的优化是合法的)。您会发现进行这样的优化需要花费大量的工作(当然是几个月,也许是几年!),并且可能not适用于许多现有程序,但您可以乐于实现它。
如果您对浮点计算感兴趣,请务必阅读floating point guide(这很棘手)。