下面的函数检查整数是否为素数。
我正在运行一个for循环,从3到2147483647(长int的+ ve限制)。
但这段代码挂了,找不到原因?
#include<time.h>
#include<stdio.h>
int isPrime1(long t)
{
long i;
if(t==1) return 0;
if(t%2==0) return 0;
for(i=3;i<t/2;i+=2)
{
if(t%i==0) return 0;
}
return 1;
}
int main()
{
long i=0;
time_t s,e;
s = time(NULL);
for(i=3; i<2147483647; i++)
{
isPrime1(i);
}
e = time(NULL);
printf("\n\t Time : %ld secs", e - s );
return 0;
}
答案 0 :(得分:5)
它最终会终止,但需要一段时间,如果你在内联你的isPrime1
函数时查看你的循环,你有类似的东西:
for(i=3; i<2147483647; i++)
for(j=3;j<i/2;j+=2)
大致为n * n / 4 = O(n ^ 2)。你的环路旅行次数太高了。
答案 1 :(得分:2)
这取决于系统和编译器。在Linux上,使用GCC 4.7.2并使用gcc -O2 vishaid.c -o vishaid
进行编译,程序立即返回,编译器通过删除它来优化对isPrime1
的所有调用(我使用{{1}检查生成的汇编代码},然后gcc -O2 -S -fverbose-asm
甚至不会调用main
)。 GCC是对的:由于isPrime1
没有副作用且未使用其结果,因此可以删除其调用。然后isPrime1
循环有一个空体,因此也可以进行优化。
要吸取的教训是,在对优化的二进制文件进行基准测试时,最好在代码中产生一些真正的副作用。
此外,算术告诉我们,如果没有小于其平方根的除数,则某些for
是素数。所以更好的代码:
i
在我的系统上(x86-64 / Debian / Sid与i7 3770K Intel处理器,运行该程序的核心是3.5GHz)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;
}
- s是64位。所以我编码了
long
大约4分钟后仍然会打印很多行,包括
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;
}
我猜它需要几个小时才能完成。 30分钟后它仍在吐痰(缓慢)
#6819840: 119566439
#6823936: 119642749
#6828032: 119719177
#6832128: 119795597
实际上,该程序需要4小时16分钟才能完成。最后的输出是
#25698304: 486778811
#25702400: 486862511
#25706496: 486944147
#25710592: 487026971
#105086976: 2147139749
#105091072: 2147227463
#105095168: 2147315671
#105099264: 2147402489
Time : 15387 secs
程序包的primes
程序/usr/games/primes
回答得更快
bsdgames
它仍然打印105097564行(大部分被% 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
跳过)
如果您对素数生成感兴趣,请阅读几本数学书籍(如果您对效率感兴趣,它仍然是一个研究课题;您仍然可以获得该学科的博士学位。)从维基百科上的sieve of erasthothenes和primality test页面开始。
最重要的是,首先使用调试信息和所有警告编译程序(例如Linux上的tail
)并学习使用调试器(即{{ 1)}在Linux上)。然后你可以在大约一两分钟后中断你的调试程序(在gcc -Wall -g
下使用gdb
,然后让它继续使用Ctrl-C
命令到gdb
),然后观察main中的cont
计数器正在缓慢增加。也许还要求分析信息(gdb
的{{1}}选项然后使用i
)。当编写复杂的算术事物时,阅读有关它们的优秀数学书籍是非常值得的(素性测试是一个非常复杂的主题,是大多数加密算法的核心)。
答案 2 :(得分:1)
这是一种非常低效的质量测试方法,这就是它似乎挂起的原因。 在网上搜索更有效的算法,例如Sieve of Eratosthenes
答案 3 :(得分:0)
在这里尝试一下,看看它是否真的是一个无限循环
int main()
{
long i=0;
time_t s,e;
s = time(NULL);
for(i=3; i<2147483647; i++)
{
isPrime1(i);
//calculate the time execution for each loop
e = time(NULL);
printf("\n\t Time for loop %d: %ld secs", i, e - s );
}
return 0;
}