这取决于系统和编译器。在 Linux 上,使用 GCC 4.7.2 并使用gcc -O2 vishaid.c -o vishaid
程序编译立即返回,并且编译器通过删除它们来优化所有调用isPrime1
(我检查了生成的汇编代码gcc -O2 -S -fverbose-asm
,然后main
甚至不调用isPrime1
)。GCC 是对的:因为isPrime1
没有副作用并且没有使用它的结果,所以可以删除它的调用。那么for
循环体是空的,所以也可以优化。
要吸取的教训是,在对优化的二进制文件进行基准测试时,最好在代码中产生一些真正的副作用。
此外,算术告诉我们,i
如果没有小于其平方根的除数,则某些是素数。所以更好的代码:
int isPrime1(long t) {
long i;
double r = sqrt((double)t);
long m = (long)r;
if(t==1) return 0;
if(t%2==0) return 0;
for(i=3;i <= m;i +=2)
if(t%i==0) return 0;
return 1;
}
在我的系统上(带有 i7 3770K Intel 处理器的 x86-64/Debian/Sid,运行该程序的核心频率为 3.5GHz)long
-s 是 64 位。所以我编码
int main ()
{
long i = 0;
long cnt = 0;
time_t s, e;
s = time (NULL);
for (i = 3; i < 2147483647; i++)
{
if (isPrime1 (i) && (++cnt % 4096) == 0) {
printf ("#%ld: %ld\n", cnt, i);
fflush (NULL);
}
}
e = time (NULL);
printf ("\n\t Time : %ld secs\n", e - s);
return 0;
}
大约 4 分钟后,它仍然打印了很多行,包括
#6819840: 119566439
#6823936: 119642749
#6828032: 119719177
#6832128: 119795597
我猜这需要几个小时才能完成。30 分钟后它仍在吐痰(缓慢)
#25698304: 486778811
#25702400: 486862511
#25706496: 486944147
#25710592: 487026971
实际上,该程序需要4小时16分钟才能完成。最后的输出是
#105086976: 2147139749
#105091072: 2147227463
#105095168: 2147315671
#105099264: 2147402489
Time : 15387 secs
顺便说一句,这个程序仍然效率很低:包中的程序primes
响应速度更快/usr/games/primes
bsdgames
% time /usr/games/primes 1 2147483647 | tail
2147483423
2147483477
2147483489
2147483497
2147483543
2147483549
2147483563
2147483579
2147483587
2147483629
/usr/games/primes 1 2147483647
10.96s user 0.26s system 99% cpu 11.257 total
它仍然打印了 105097564 行(大多数被 跳过tail
)
如果您对质数生成感兴趣,请阅读几本数学书籍(如果您对效率感兴趣,它仍然是一个研究主题;您仍然可以获得该主题的博士学位。)。从 Wikipedia 上的 Erastothenes和素性测试页面的筛子开始。
最重要的是,首先用调试信息和所有警告编译您的程序(即gcc -Wall -g
在 Linux 上)并学习使用您的调试器(即gdb
在 Linux 上)。然后,您可以在大约一两分钟后中断您调试的程序(使用Ctrl-C
under gdb
,然后让它继续使用cont
命令 to gdb
),然后观察i
main 中的计数器正在缓慢增加。也许还要求提供分析信息(然后使用-pg
选项)。在编写复杂的算术代码时,阅读有关它们的优秀数学书籍是非常值得的(素数测试是一个非常复杂的主题,是大多数密码算法的核心)。gcc
gprof