我遇到了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;
}
Run Code Online (Sandbox Code Playgroud)
我还检查它实际上运行循环并调用该函数n次.
有谁知道可能导致这个问题的原因是什么?
谢谢!
但是,如果我在最后打印总数,它可以正常工作.
这可能是一种优化的编译器效果(合法的,符合C11标准n1570).
由于程序中没有可见的副作用(没有printf),因此允许编译器(按照as-if规则)将其优化为无操作程序.
对于某些版本的GCC或Clang,以及一些优化标志,您可以观察到相同的情况.尝试编译代码gcc -O3 -S -fverbose-asm并查看生成的汇编程序代码(您将main在Linux/x86-64上观察到使用GCC 8.1 生成的空)
有谁知道可能导致这个问题的原因是什么?
您的代码,以及您对C 的棘手语义的误解.实现符合C标准(并且您的程序正常运行).
BTW,即使printf理论上,编译器也可以将程序优化为一个简单的常量printf.在实践中,目前的编译器(遗憾地)并不那么聪明.
如果你想要一些强大的基准,n可能取决于程序参数(你仍然需要保持printf,因为你想要一些可见的副作用)或许:
unsigned long n = (argc<2)?1000:(unsigned long)atol(argv[1]);
Run Code Online (Sandbox Code Playgroud)
测量性能时,不要忘记在编译器中启用优化!
顺便说一下,在几年之后(在完成CS课程之后,包括一个关于编译和/或阅读过Dragon Book)之后,你可能会尝试实现一些能够用显式优化你的功能的GCC插件printf(但是仍然n被初始化为编译时常量),main只是调用一些printf并total在编译时进行循环计算(这样的优化是合法的).你会发现,做这样的优化需要大量的工作的(当然个月,甚至数年!),并且可能不适用于很多现有的方案,但你可以有乐趣实现它.
如果您对浮点计算感兴趣,请务必阅读浮点指南(这很棘手).