为什么这段代码会进入无限循环

时间:2013-04-21 16:29:23

标签: c long-integer

下面的函数检查整数是否为素数。

我正在运行一个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;
}

4 个答案:

答案 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 erasthothenesprimality 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;
}