素数搜索

本文介绍了两种经典的素数求解算法——试商判别法和厄拉多塞筛法,并给出了具体的程序设计实例。试商判别法适用于直观理解素数的概念,而厄拉多塞筛法在大规模数据处理中更为高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 伽利略:“ 素数是上帝用来描写宇宙的文字 。”

素数,又称为质数,是不能被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  2029
2039  2053  2063  2069  2081
2083  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  1671835
1671853  1671855  1671867  1671883  1671891
1671903  1671909  1671925  1671933  1671939
1671945  1671967
共17个素数。

注意:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值