素数搜索

来源:互联网 发布:多核优化软件 编辑:程序博客网 时间:2024/05/16 07:27
  • 伽利略:“ 素数是上帝用来描写宇宙的文字 。”

素数,又称为质数,是不能被1与其本身以外的其他整数整除的整数。如2、3、5、7、11、13、17是前几个素数,其中 2为唯一的偶素数

与此相对应,一个整数如果能被除1与其本身以外的整数整除,该整数称为合数或复合数。例如,15能被除1与15以外的整数3、5整除,15是一个合数;

特别地,数 1既不是素数,也不是合数

作为一类特殊的整数,素数是数论中探讨最多的也是难度最大的一类整数,其中有些问题是许多著名数学家提出并研究过的经典问题;


试商判别法

试应用试商判别法求出指定区间上的所有素数,并统计该区间上素数的个数;

1.说明:

试商判别法是依据素数的定义来实施的;

应用试商,法来探求奇数i(只有唯一的偶素数2,不作试商判别)是不是素数,用奇数j(取3,5,…,sqrt(i))去试商,若存在某个j能整除i,说明i能被1与本身以外的整数j整除,i不是素数,若上述范围内的所有奇数j都不能整除i,则i为素数;

有些程序把试商奇数j的取值上限定为 i/2i-1 也是可行的,但并不是可取的,这样无疑会增加了试商的无效循环,理论上说,如果i存在一个大于sqrt(i)且小于i的因数,则必存在一个与之对应的小于sqrt(i)且大于1的因数,因而从判别功能来说,取到sqrt(i)已足够;

判别j整除i常用表达式 i%j=0 实现;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   long c,d,i,j,n,t;   printf("请输入区间上下限c,d(c>2):");   scanf("%ld,%ld",&c,&d);   printf("求区间[%ld,%ld]上的素数:\n",c,d);   if(c%2==0)      c=c+1;   n=0;   for(i=c;i<=d;i+=2)   {      for(t=0,j=3;j<=sqrt(i);j+=2)         if(i%j==0)          /*实施试商*/         {            t=1;            break;         }      if(t==0)            /*标志量t=0时i为素数*/      {         printf("%ld  ",i);         n++;             /*统计素数的个数*/         if(n%5==0)            printf("\n");      }   }   printf("\n共%ld个素数。",n);}

3.程序运行示例及其注意事项:

请输入区间上下限c,d(c>2):2000,2100求区间[2000,2100]上的素数:2003  2011  2017  2027  20292039  2053  2063  2069  20812083  2087  2089  2099共14个素数。

厄拉多塞 筛法

求素数的筛法 是公元前三世纪的 厄拉多塞(Eratosthenes)提出来的

  • 对于一个大整数x,只要知道不超过 sqrt(x) 的所有素数p,划去所有p的倍数2p,3p,…,剩下的整数就是不超过x的全部素数

应用筛法求素数,为了方便实施“划去”操作,应设置数组。每一数组元素对应一个待判别的奇数,并赋初值0,如果该奇数为p的倍数则应划去,对应元素加一个划去标记,通常给该元素赋值-1,最后,打印元素值不是-1(即没有划去)的元素对应的奇数即所求的素数;

在实际应用筛法的过程中,p通常不限于取不超过 sqrt(x) 的素数,而是适当放宽取不超过 sqrt(x) 的奇数(从3开始)。这样做尽管多了一些重复划去操作,但程序实现要简便些;

1.说明:

设置a数组存储区间中的所有奇数,凡“划去”的数组元素赋值“-1”;

在指定区间 [c,d] (约定c为奇数)上所有的奇数表示为 j=c+2*k(k=0,1,…,e,这里 e=(d-c)/2 )。于是k=(j-c)/2是奇数j在数组中的序号(下标)。如果j为奇数的倍数时,对应数组元素作“划去”标记,即 a[(j-c)/2]=-1 ;

根据c与奇数i确定g=2 * int(c/(2*i))+1,使得gi接近区间下限c,从而使划去的gi,(g+2)i,…,在 [c,d] 中,减少无效操作,以提高对广大区间的筛选效率;

最后,凡数组元素 a[k]!=-1,对应的奇数j=c+2*k就为素数;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   long c,d,e,g,i,j,k,n;   static long int a[80000];   printf("请输入区间上下限c,d(c>2):");   scanf("%ld,%ld",&c,&d);   printf("求区间[%ld,%ld]上的素数:\n",c,d);   if(c%2==0)      c=c+1;   e=(d-c)/2;   i=1;   while(i<=sqrt(d))   /*在[c,d]中筛选素数*/   {      i=i+2;      g=2*int(c/(2*i))+1;      if(g*i>d)         continue;      if(g==1)         g=3;      j=j*g;      while(j<=d)      {         if(j>=c)            a[(j-c)/2]=-1;         j=j+2*i;      }   }   for(n=0,k=0;k<=e;k++)      if(a[k]!=-1)       /*输出所得素数*/      {         n++;         printf("%ld  ",c+2*k);         if(n%5==0)            printf("\n");      }   printf("\n共%ld个素数。\n",n);}

3.程序运行示例及其注意事项:

请输入区间上下限c,d(c>2):1671800,1672000求区间[1671800,1672000]上的素数:1671801  1671807  1671813  1671825  16718351671853  1671855  1671867  1671883  16718911671903  1671909  1671925  1671933  16719391671945  1671967共17个素数。

注意:

  • 试商法较为直观,设计容易实现,因此常为程序设计爱好者所采用

  • 筛法在较大区间的搜索与较大整数的判别上效率更高一些,但设计上较难把握

1 0