素数的几种判断方法和实现

素数的几种判断方法和实现
素数的几种判断方法和实现

PS:本来没有决心把这个东西写完的,结果早上写到一半,出去吃个饭,没保存,回来手一抖直接关掉了,好不容易写了一大半了,只能重新写了,坑爹啊,但就是这个插曲,本来还没有决心的我,一下子却坚定了信念,一点要把这个东西写完。就这样开始吧

BY:Lee

下面,我们重新开始

═══════════════════════════════════════════

如何判断一个数是否是素数呢

═══════════════════════════════════════════也许你会认为这是一个简单的问题,但事实上,世界上任何一个问题,都没有你想象中的那么简单1 + 1 是否等于2 ,这便是一个简单而又复杂的问题,呵呵。

突然想把这个东西换一种风格来写了,就这样扯淡扯下去吧。扯的时候文章中多少有内容来自于网络,没有侵权的意思,如果作者看到还请见谅。

═══════════════════════════════════════════下面正式进入正题

═══════════════════════════════════════════

一、朴素判断素数

═══════════════════════════════════════════1. 这种方法被誉为笨蛋的做法:

一个数去除以比它的一半还要大的数,一定除不尽的,这还用判断吗??

很容易发现的,这种方法判断素数,对于一个整数n,需要n-2 次判断,时间复杂度是O(n)在n非常大或者测试量很大的时候,这种笨蛋做法肯定是不可取的。

2. 改进一下下小学生的做法:

3. 再改进一下聪明的小学生的做法

对于一个小于n的整数X,如果n不能整除X,则n必定不能整除n/X。反之相同一个明显的优化,就是只要从2枚举到√n 即可。

因为在判断2的同时也判断了n/2。到√n时就把2到n-1都判断过了。

在这里,这个聪明的小学生还用了i*i <= n 来代替sqrt(n),

这里是避免了调用函数sqrt(),其消耗时间很大,

特别是在大量数据测试的时候消耗很明显。

这个算法的时间复杂度,与最前面的笨蛋做法就好多了,

不过这里好像用sqrt()也没问题啊,,,,这个就不太清楚了。

但是做一个测试发现,如果是这样额话,每一次判断都要计算i*i,

而如果只调用sqrt()函数的话,只需要计算一次。故还是sqrt()函数好一些啊。

对于一个整数N, 需要测试√n-1 次,所以本算法的时间复杂度O(√n)。

4. 再改进一下牛逼的小学生的做法

最后,来看一下这个牛逼的小学生,

确实,对于一个小学生,能够这么牛逼的想到这么多优化,

已经很强大了。

不过其实没什么必要。。。。。。

这里的i+=2,是因为,偶数除了2之外,是不可能是素数的、

所以从3开始,直接+2 。进一步优化。

这个大概就是朴素判断素数方法的最佳优化了。(也许你还有更好的优化)

所以,如果是对于一般的素数判断的话,用上面那个代码吧

小学生毕业了,到了中学,会有怎样的成长呢?

下面来看看中学生们是怎么样判断的。

═══════════════════════════════════════════

二、埃拉托斯特尼筛选法

═══════════════════════════════════════════

埃拉托色尼选筛法(the Sieve of Eratosthenes)简称埃氏筛法,是古希腊数学家埃拉托色尼(Eratosthenes 274B.C.~194B.C.)提出的一种筛选法。

是针对自然数列中的自然数而实施的,用于求一定范围内的质数,

它的容斥原理之完备性条件是p=H~。

可参考:

https://www.360docs.net/doc/4c10054952.html,/wiki/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89 %B9%E5%B0%BC%E7%AD%9B%E6%B3%95

基本原理:

筛素数的基本方法是用来筛选出一定范围内的素数素数筛法的基本原理,利用的是素数p只有1和p 这两个约数,并且一个数的约数一定不大于本身,素数筛法的过程:

把从1开始的、某一范围内的正整数从小到大顺序排列,

1不是素数,首先把它筛掉。

剩下的数中选择最小的数是素数,然后去掉它的倍数。

依次类推,直到筛子为空时结束。

求解用途:

素数筛法经常作为一道题的一部分用来打一定范围内素数表,

然后利用素数表作为基础解题。

*/

执行完本算法之后,isprime[i]中如果是1,表示i为素数,0,表示i不是素数。

所以呢,这个算法执行完一遍之后,就可以在O(1)的时间内判断出MAX以内的任意数,是不是素数了,所以这个算法消耗的时间可以说全部在筛选上了。初看这个算法,会觉得这个算法的时间复杂度是O(N^2),,但其实不是的,在第二个循环中,每次递增的i,当i越来也大的时候,j很快就能超过MAX的,筛选法的实际复杂度是O(n*log(logn))

2. 有思想的中学生的做法

*

这个算法的关键在于if(i % p[j] == 0) break;,它使得任何一个合数,只能被它最小的质因数标记过一次,再一次进行优化。所以整个算法是线性的。但考虑到log(log(100000000))还不到3,

故这个线性算法其实也只有理论的价值罢了。

其实我不这样认为。这样其实可以当成素数表来用,因为定义了一个数组p,存放的都是素数。

讲到这里,你应该对判断素数这个问题有了一个新的认识了。

既要考虑时间上的问题。又要考虑空间上的问题。

也就是这并不是一个无脑问题。

═══════════════════════════════════════════

三、朴素判断+ 筛选法

═══════════════════════════════════════════

那位聪明的小学生已经将朴素法优化到很好了。再深入理解,你确实会发现一个本质问题。

从2到√n 中,存在很多不必要的判断,比如,n不能被2整除的话,n必然不能被4整除,必然不能被2的倍数整除。所以,我们再结合筛选法,优化处理小于√n 的所有素数。这样在大量测试数据的时候,效率就提高很多了。

上面这个代码,就是将两种方法完美结合了,

上面的算法,总的时间复杂度理论上是0(√n)。

但是字常数上已经得到很大的优化了,效率上也比原来的朴素快了好多。

别人统计是快了几十倍吧。这个我不清楚。

但是你会发现始终有一个问题,单纯用筛选法耗空间太多,用朴素法耗时间太多,有没有其他的办法?事实证明是有的。

下面将会接受两种方法,一种是费马测试,一种是米勒拉宾测试。

这两个测试就有点难了,至少对于我来说有点难了。

═══════════════════════════════════════════

四、费马素数测试

═══════════════════════════════════════════

═══════════════════════════════════════════费马小定理:

有N为任意正整数,P为素数,且N不能被P整除(显然N和P互质),

则有:

N^P%P=N(即:N的P次方除以P的余数是N)

公式变形:

(N^(P-1))%P=1

网络分析:

后来分析了一下,两个式子其实是一样的,可以互相变形得到,

原式可化为:(N^P-N)%P=0

(即:N的P次方减N可以被P整除,因为由费马小定理知道N的P次方除以P的余数是N)

把N提出来一个,N^P就成了你N*(N^(P-1)),

那么(N^P-N)%P=0可化为:(N*(N^(P-1)-1))%P=0

请注意上式,含义是:N*(N^(P-1)-1)可以被P整除

又因为N*(N^(P-1)-1)必能整除N(这不费话么!)

所以,N*(N^(P-1)-1)是N和P的公倍数,小学知识了^_^

又因为前提是N与P互质,而互质数的最小公倍数为它们的乘积,

所以一定存在正整数M使得等式成立:

N*(N^(P-1)-1)=M*N*P

两边约去N,化简之:

N^(P-1)-1=M*P

因为M是整数,显然:

(N^(P-1)-1)%P=0

即:

N^(P-1)%P=1

═══════════════════════════════════════════积模分解公式

先有一个引理,如果有:X%Z=0,即X能被Z整除,则有:

(X+Y)%Z=Y%Z

这个不用证了吧...

设有X、Y和Z三个正整数,则必有:(X*Y)%Z=((X%Z)*(Y%Z))%Z

想了很长时间才证出来,要分情况讨论才行:

1.当X和Y都比Z大时,必有整数A和B使下面的等式成立:

X=Z*I+A(1)

Y=Z*J+B(2)

不用多说了吧,这是除模运算的性质!

将(1)和(2)代入(X*Y)modZ得:((Z*I+A)(Z*J+B))%Z

乘开,再把前三项的Z提一个出来,变形为:(Z*(Z*I*J+I*A+I*B)+A*B)%Z(3)

因为Z*(Z*I*J+I*A+I*B)是Z的整数倍……晕,又来了。

概据引理,(3)式可化简为:(A*B)%Z

又因为:A=X%Z,B=Y%Z,代入上面的式子,就成了原式了。

2.当X比Z大而Y比Z小时,一样的转化:

X=Z*I+A

代入(X*Y)%Z得:

(Z*I*Y+A*Y)%Z

根据引理,转化得:(A*Y)%Z

因为A=X%Z,又因为Y=Y%Z,代入上式,即得到原式。

同理,当X比Z小而Y比Z大时,原式也成立。

3.当X比Z小,且Y也比Z小时,X=X%Z,Y=Y%Z,所以原式成立。

═══════════════════════════════════════════快速计算乘方的算法

如计算2^13,则传统做法需要进行12次乘法。

/*计算n^p*/

把2*2的结果保存起来看看,是不是成了:4*4*4*4*4*4*2

再把4*4的结果保存起来:16*16*16*2

一共5次运算,分别是2*2、4*4和16*16*16*2

这样分析,我们算法因该是只需要计算一半都不到的乘法了。

为了讲清这个算法,再举一个例子2^7:2*2*2*2*2*2*2

两两分开:(2*2)*(2*2)*(2*2)*2

如果用2*2来计算,那么指数就可以除以2了,不过剩了一个,稍后再单独乘上它。

再次两两分开,指数除以2:((2*2)*(2*2))*(2*2)*2

实际上最后一个括号里的2 * 2是这回又剩下的,那么,稍后再单独乘上它

现在指数已经为1了,可以计算最终结果了:16*4*2=128

优化后的算法如下:

够完美了吗?不,还不够!看出来了吗?main是没有必要的,并且我们可以有更快的代码来判断奇数。

要知道除法或取模运算的效率很低,

所以我们可以利用偶数的一个性质来优化代码,

那就是偶数的二进制表示法中的最低位一定为0!

其实位运算这个东西我一直也没高太懂,有时间要系统得搞清楚

如果我们现在要对非常非常大的数进行判断,素数表显得无能为力了。

还有就是可以用动态的素数表来进行优化,

这就是大学生的做法了。

但是动态生成素数表的策略又复杂又没有效率,

所以我们还是直接跳跃到专家的做法吧:

根据上面讲到的费马小定理,对于两个互质的素数N和P,必有:N^(P-1)%P=1

那么我们通过这个性质来判断素数吧,当然,你会担心当P很大的时候乘方会很麻烦。不用担心!我们上面不是有个快速的幂模算法么?好好的利用蒙格马利这位大数学家为我们带来的快乐吧!

算法思路是这样的:

对于N,从素数表中取出任意的素数对其进行费马测试,

如果取了很多个素数,N仍未测试失败,那么则认为N是素数。当然,测试次数越多越准确,

但一般来讲50次就足够了。

另外,预先用“小学生”的算法构造一个包括500个素数的数组,

先对Q进行整除测试,

将会大大提高通过率,方法如下:

**************************************************************************************** OK,这就专家的作法了。

等等,什么?好像有点怪,看一下这个数29341,

它等于13 * 37 * 61,显然是一个合数,但是竟通过了测试!!

哦,抱歉,我忘了在素数表中加入13,37,61这三个数,

我其实是故意的,我只是想说明并费马测试并不完全可靠。

(PS:确实,费马测试毕竟只是一个测试。)

**************************************************************************************** 来看一下费马素数测试如何使用

我们发已经现了重要的一点,费马定理是素数的必要条件而非充分条件。

这种不是素数,但又能通过费马测试的数字还有不少,

数学上把它们称为卡尔麦克数,

现在数学家们已经找到所有10 ^ 16以内的卡尔麦克数,

最大的一个是9585921133193329。

我们必须寻找更为有效的测试方法。

数学家们通过对费马小定理的研究,并加以扩展,

总结出了多种快速有效的素数测试方法,

目前最快的算法是拉宾米勒测试算法,

下面介绍拉宾米勒测试。

*/

═══════════════════════════════════════════

五、米勒-拉宾素性测试

═══════════════════════════════════════════

拉宾米勒测试是一个不确定的算法,只能从概率意义上判定一个数可能是素数,但并不能确保。算法流程如下:

1.选择T个随机数A,并且有A

2.找到R和M,使得N=2*R*M+1成立。

快速得到R和M的方式:N用二进制数B来表示,令C=B-1。因为N为奇数(素数都是奇数),所以C的最低位为0,从C的最低位的0开始向高位统计,一直到遇到第一个1。这时0的个数即为R,M为B右移R位的值。

3.如果A^M%N=1,则通过A对于N的测试,然后进行下一个A的测试

4.如果A^M%N!=1,那么令i由0迭代至R,进行下面的测试

5.如果A^((2^i)*M)%N=N-1则通过A对于N的测试,否则进行下一个i的测试

6.如果i=r,且尚未通过测试,则此A对于N的测试失败,说明N为合数。

7.进行下一个A对N的测试,直到测试完指定个数的A

由于能用逐次平方法在O(logn)的时间内算出a^b mod c.米勒拉宾的算法时间主要是花在这里了,所以米勒拉宾算法的时间复杂度是O(logn).对于朴素判断优化的O(√n)来说,要快得多了。

感谢米勒拉宾这位大神吧。

感谢那些在博客里分享自己的成果和点滴的人们,我们的世界,我们自己懂!!!!!!

求素数

素数:是指除了1和该数本身之外,不能被其他任何整数整除的数。 2,3,5,7,11,13,17,19,23………. 判断一个数(比如这个数是n)是否为素数:将n作为被除数,将2~n-1之间各个整数先后 作为除数,如果都不能被整除,则n为素数。 求所有大于1小于整数m的素数: #include void main() { int i ,j, k=1,m; printf("输入一个整数:"); scanf("%d",&m); for(i=2; i void main() { int i,j,m; printf("输入一个整数:"); scanf("%d",&m); for(i=2; i

if(i%j == 0) { printf("i=%d不是素数\n",i); break; } } } } 第一,对于一个自然数N,只要能被一个非1非自身的数整除,它就肯定不是素数,所以不必再用其他的数去除。 第二,对于N来说,只需用小于N的素数去除就可以了。例如,如果N能被15整除,实际上就能被3和5整除,如果N不能被3和5整除,那么N也决不会被15整除。 for(i=2;i<=(n-1);i++) if(n%i==0) 第三,对于N来说,不必用从2到N一1的所有素数去除,只需用小于等于√N(根号N)的所有素数去除就可以了。这一点可以用反证法来证明: 如果N1小于N的整数d1和d2,使得N=d1×d2。如果d1和d2均大于√N,则有:N=d1×d2>√N×√N =N。而这是不可能的,所以,d1和d2中必有一个小于或等于√N。 for(i=2;i<(n=sqrt(n));i++) if(n%i==0) for(i=2;i

求出200——1000之间所有的素数

C语言程序设计 综合实验报告 学院:信息科学与工程学院 专业:自动化1002班 学号:201004134070 姓名:吴君 指导老师: 2011年6月25日武汉科技大学

求出200——1000之间所有的素数,要求1)调用函数判断某数是不是素数; 2)输出结果,每行输出十个; 程序: #include #include int judge(int n)//定义一个函数 {int i,k; k=sqrt(n); for(i=2;i<=k;i++)//判断I是否是素数{ if(n%i==0) { break; } } if (i>k) { return 1;//返回一个函数值 } return 0; }

void main() {int i,m,k; for(i=201;i<1000;i=i+2) { m=judge(i);//调用自定义函数 if (m==1) { printf("%4d",i); //输出结果 k++; if(k%10==0)//大于10换行 printf("\n"); } } } 输出结果: 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641

C语言求素数(质数)Eratosthenes经典算法

//使用Eratosthenes方法找出指定范围内的所有质数 #include #define SIZE 500 //该方法能够求出2*SIZE 之内的质数#define TRUE 1 #define FALSE 0 int main() { char sieve[ SIZE ]; /* the sieve */ char *sp; /* pointer to access the sieve */ int number; /* number we’re computing */ /* ** Set the entire sieve to TRUE. */ for(sp = sieve; sp<&sieve[ SIZE ]; ) *sp++ = TRUE; /*** Process each number from 3 to as many as the sieve holds. (Note: the ** loop is terminated from inside.) */ for( number = 3; ; number += 2 ){ /* ** Set the pointer to the proper element in the sieve, and stop ** the loop if we’ve gone too far. */ sp = &sieve[ 0 ] + ( number-3 ) / 2; if(sp>= &sieve[ SIZE ] ) break; /* ** Now advance the pointer by multiples of the number and set ** each subsequent entry FALSE. */ while(sp += number, sp<&sieve[ SIZE ] ) *sp = FALSE; } /* ** Go through the entire sieve now and print the numbers corresponding ** to the locations that remain TRUE. */ printf( "2\t" ); for( number = 3, sp = &sieve[ 0 ]; sp<&sieve[ SIZE ]; number += 2, sp++ ){ if( *sp ) printf( "%d\t", number );

求素数列表和判断素数的算法

求素数列表和判断素数的算法 有兴趣阅读本文的读者,应该对素数概念是十分熟悉的了。用计算机程序实现素数计算,集中在2个主要问题上: ?判断一个正整数是否是素数-(算法A) ?求一定范围内的素数列表- (算法B) 关于素数的算法,根据素数的数学性质,大家都会想到如下几个方面: ?用遍历求模的方式判断素数 ?素数都是奇数,可以在奇数数列中寻找素数 ?利用开方来缩小搜索的范围 然后,求素数的计算是复杂的,如果算法写得不好,则耗时较高。在百度百科“素数”条目中的算法程序,是值得商榷的。很多方法是O(N2)的算法。 为此,在本文中探讨了求素数列表和判断素数这两个算法,力图使算法可以达到O (N Log(N))优化级别。在本文中,算法语言选用C#。 1,判断素数的简单实现(算法A-1) ///

///算法A-1,判断素数 /// ///待测正整数 ///是否为素数(为了简化,1以下的整数皆为素数) public static bool IsPrime(int number) { // 为了简化,1以下的整数皆为素数 if(number <= 2) { return true; } // 奇偶性 if (number % 2 == 0) { return false; } // 利用开方缩小范围,优化效果十分明显 int range = (int)Math.Sqrt(number) + 1; // 从3开始的奇数列 for (int current = 3; current <= range; current += 2) { // 判断是否为素数 if (number % current == 0)

C语言素数的几种判断方法

#include #include main() { int i,n; printf("请输入一个数:"); scanf("%d",&n); for(i=2;i=n) printf("素数!"); printf("\n"); } /*main() { int i,n,m; printf("请输入一个整数:"); scanf("%d",&m); n=(int)sqrt(m); for(i=2;i<=n;i++) if(m%i==0) break; if(i>n) printf("素数!\n"); else printf("不是素数!"); }*/ /*int p(int m) { int i,n=sqrt(m); for(i=2;i<=n;i++) if(m%i==0) break; if(i>n) return 1; else return 0; } main() {

int m; for(m=1;m<=10;m++) { if(p(m)) printf("%d ",m); } printf("\n"); }*/ //3-100间所素数。 /*main() { int i,n; for(n=3;n<=100;n++) { for(i=2;i<=n-1;i=i+1) if(n%i==0) break; if(i>=n) printf("%d\t",n); } }*/ /*main() { int i,m,j; for(i=2;i<=10;i++) { m=sqrt(i); for(j=2;j<=m;j++) { if(j%m==0) break; if (j>m) //加上这句,如果检查所有的j全部不能整除m,循环结束后,j一定大于m,这时的i才是素数 printf("%d",i); } } } /* void main() { int i,j,n=0,xx[10]; for(i=1;i<10;i++)

用筛法求出100以内的全部素数

例6、用筛法求出100以内的全部素数,并按每行五个数显示。 【问题分析】 ⑴把2到100的自然数放入a[2]到a[100]中(所放入的数与下标号相同); ⑵在数组元素中,以下标为序,按顺序找到未曾找过的最小素数minp,和它的位置p(即下标号); ⑶从p+1开始,把凡是能被minp整除的各元素值从a数组中划去(筛掉),也就是给该元素值置0; ⑷让p=p+1,重复执行第②、③步骤,直到minp>Trunc(sqrt(N)) 为止; ⑸打印输出a数组中留下来、未被筛掉的各元素值,并按每行五个数显示。 用筛法求素数的过程示意如下(图中用下划线作删去标志): ① 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {置数} ② 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被2整除的数} ③ 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被3整除的数} …… 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被整除的数} Program Exam53; const N=100; type xx=1 .. N; {自定义子界类型xx(类型名)} Var a: array[xx] of boolean; i,j: integer; Begin Fillchar(a,sizeof(a),true); a[1] := False; for i:=2 to Trunc(sqrt(N)) do if a[I] then for j := 2 to N div I do a[I*j]:= False; t:=0; for i:=2 to N do if a[i] then Begin write(a[ i ]:5); inc(t); if t mod 5=0 then writeln end; End. 【例3】输入十个正整数,把这十个数按由大到小的顺序排列(将数据按一定顺序排列称为排序,排序的算法有很多,其中选择排序中的“简单选择排序”是一种较简单的方法) 分析:要把十个数按从大到小顺序排列,则排完后,第一个数最大,第二个数次大,……;因此,我们第一步可将第一个数与其后的各个数依次比较,若发现,比它大的,则与之交换,比较结束后,则第一个数已是最大的数。同理,第二步,将第二个数与其后各个数再依次比较,又可得出次大的数。如此方法进行比较,最后一次,将第九个数与第十个数比较,以决定次小的数。于是十个数的顺序排列结束。 例如下面对5个进行排序,这个五个数分别为829105。按选择排序方法,过程如

判断某个数是否素数

判断某个数是否素数: 1.定义为一个function函数过程 第一种方法: Function prime(ByVal x As Integer) As Boolean 注1 For i = 2 To x – 1 注2 If x Mod i = 0 Then Exit For Next i If i > x - 1 Then prime = True 注3 End Function 注1:这里注意形参前面有ByVal,不要ByVal也是可以的,为什么? 因为在function中并未改变x的值,所以加不加ByVal都正确 注2:此句也可以这样写:For i = 2 To x/2 或 For i = 2 To sqr(x) 注3:此句也可以这样写:If i > x - 1 Then prime = True Else prime = False 思考:为什么不要Else prime = False 程序运行也是正确的 另外注意此处的条件i > x – 1的实际含义 调用的时候(调用函数时,最好不要用带call关键字的调用方法) If prime(x) then……… 第二种方法: Function prime(ByVal x As Integer) As Boolean Prime=false 注1 For i = 2 To x – 1 If x Mod i = 0 Then Exit Function注2 Next i prime = True 注3 End Function 注1 此句要不要都可以,思考为什么 注2和注3两条语句与第一种方法的区别 调用的时候 If prime(x) then……… 第三种方法: Function prime(ByVal x As Integer) As integer Prime=0 For i = 2 To x – 1 If x Mod i = 0 Then Exit Function Next i prime = 1 End Function 此方法与上述方法的区别 调用的时候 If prime(x)=1 then………

求100—200内所有素数

求100——200内所有素数 ①要判断一个数是不是素数,首先要知道什么是素数。回忆一下数学里的知识,什么是素数?只能被自身和1整除的正整数是素数。1既不是素数,也不是合数;2是最小的素数,也是唯一一个是偶数的素数。 ②判断一个正整数m是否为素数有多种方法。 方法1:让m依次被2,3,…,m-1除,如果m不能被2~m-1中的任何一个整数整除,则m是素数。 方法2:让m依次被2,3,…,m/2除,如果m不能被2~m/2中的任何一个整数整除,则m是素数。 方法3:让m依次被2,3,…,sqrt(m)除,如果m不能被2~sqrt(m)中的任意一个整数整除,则m为素数。sqrt(m)为m的平方根。 其中最后一种方法判断速度最快,因此这里采用最后一种方法。 ③判断一个整数是不是素数,由于需要一次一次地做除法,所以要使用循环。 程序如下: #include "math.h" main( ) { int m,i,k,n=0; for(m=101; m<=200; m+=2) { k=sqrt(m); for (i=2;i<=k;i++) if (m%i==0) break; if (i>k) {printf("%5d",m); n=n+1; if (n%10==0) printf("\n"); } } } 运行结果为: 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
本文来自【C语言中文网】:https://www.360docs.net/doc/4c10054952.html,/cpp/html/664.html

质数的判定

质数的判定 舒云水 课本第3页的例1及例1后面的探究问题是“质数的判定” 问题,它有丰富的数学背景,下面给读者做一个简单介绍﹒质数有无穷多个﹒大约在2300年前欧几里得就证明了存在着无穷多个质数﹒尽管如此,迄今为止还没有发现质数的模型或产生质数的有效公式﹒因而寻找大的质数必须借助计算机一个一个地找﹒寻找大质数是数论研究的重要课题之一﹒目前找到的最大质数是梅森质数1 243112609 ,它有12978189位数,如果用普通字号将这个巨数连续写下来,它的长度可超过50公里! 读者可能会产生一个疑问:找大质数有什么用?现在最好的密码是用质数制造的,极难破译﹒ 人们一直在寻找检验一个数是否为质数的方法,最近一些年有了巨大进步﹒你或许会说,检验质数有什么难?确实,看一个数是不是质数,有一种非常自然而直接的方法,这就是我们常用的试除法,即课本例1所用的算法﹒这一方法对检验不太大的数是挺实用的﹒但若数字太大,它就变得十分笨拙﹒假设你在一个快速计算机上实用高效的程序进行试除﹒对于一个10位数字的数,运行程序几乎瞬间就能完成﹒对于一个20位的数就麻烦一点了,需要两个小时﹒对于一个50位的数,则需要100亿年﹒这已经大得不可想象﹒前面讲过最好的密码是用质数制造的,它是用介于60位到100位之间的两个质数制造的,这种计算正是制造这种密码的需要﹒当今庞大的国际数

据通讯网络能安全运行,就得益于这种密码﹒ 如何确定一个100位的数是否为质数呢?数学家做了许多努力,在1980年左右找到了目前可用的最好方法﹒数学家阿德勒曼,鲁梅利,科恩和伦斯特拉研究出一种非常复杂的方法﹒现在以他们的名字的第一个字母命名为ARCL检验法﹒在上面提到的那类计算机上进行ARCL检验,对20位的数只需10秒钟,对50位的数用15秒,100位的数用40秒﹒如果要检查1000位的数,一个星期也就够了﹒可以相信,随着人们对质数的判定算法的研究不断深入及计算机技术的迅猛发展,我们会找到更好更快地检验一个大数是否为质数的方法,发现更多更大的质数﹒

素数的几种判断方法和实现

PS:本来没有决心把这个东西写完的,结果早上写到一半,出去吃个饭,没保存,回来手一抖直接关掉了,好不容易写了一大半了,只能重新写了,坑爹啊,但就是这个插曲,本来还没有决心的我,一下子却坚定了信念,一点要把这个东西写完。就这样开始吧 BY:Lee 下面,我们重新开始 ═══════════════════════════════════════════ 如何判断一个数是否是素数呢 ═══════════════════════════════════════════也许你会认为这是一个简单的问题,但事实上,世界上任何一个问题,都没有你想象中的那么简单1 + 1 是否等于2 ,这便是一个简单而又复杂的问题,呵呵。 突然想把这个东西换一种风格来写了,就这样扯淡扯下去吧。扯的时候文章中多少有内容来自于网络,没有侵权的意思,如果作者看到还请见谅。 ═══════════════════════════════════════════下面正式进入正题 ═══════════════════════════════════════════ 一、朴素判断素数 ═══════════════════════════════════════════1. 这种方法被誉为笨蛋的做法: 一个数去除以比它的一半还要大的数,一定除不尽的,这还用判断吗?? 很容易发现的,这种方法判断素数,对于一个整数n,需要n-2 次判断,时间复杂度是O(n)在n非常大或者测试量很大的时候,这种笨蛋做法肯定是不可取的。

2. 改进一下下小学生的做法: 3. 再改进一下聪明的小学生的做法 对于一个小于n的整数X,如果n不能整除X,则n必定不能整除n/X。反之相同一个明显的优化,就是只要从2枚举到√n 即可。 因为在判断2的同时也判断了n/2。到√n时就把2到n-1都判断过了。 在这里,这个聪明的小学生还用了i*i <= n 来代替sqrt(n), 这里是避免了调用函数sqrt(),其消耗时间很大, 特别是在大量数据测试的时候消耗很明显。 这个算法的时间复杂度,与最前面的笨蛋做法就好多了, 不过这里好像用sqrt()也没问题啊,,,,这个就不太清楚了。 但是做一个测试发现,如果是这样额话,每一次判断都要计算i*i,

C语言求素数问题算法

1.自然数是0,1,2…… 2.素数是2,3,5……(不包括1的只能背1和它本身整除的自然数) 【1】求10000以内的所有素数。 素数是除了1和它本身之外再不能被其他数整除的自然数。由于找不到一个通项公式来表示所有的素数,所以对于数学家来说,素数一直是一个未解之谜。像著名的哥德巴赫猜想、孪生素数猜想,几百年来不知吸引了世界上多少优秀的数学家。尽管他们苦心钻研,呕心沥血,但至今仍然未见分晓。 自从有了计算机之后,人们借助于计算机的威力,已经找到了2216091以内的所有素数。 求素数的方法有很多种,最简单的方法是根据素数的定义来求。对于一个自然数N,用大于1小于N的各个自然数都去除一下N,如果都除不尽,则N为素数,否则N为合数。 但是,如果用素数定义的方法来编制计算机程序,它的效率一定是非常低的,其中有许多地方都值得改进。 第一,对于一个自然数N,只要能被一个非1非自身的数整除,它就肯定不是素数,所以不 必再用其他的数去除。 第二,对于N来说,只需用小于N的素数去除就可以了。例如,如果N能被15整除,实际 上就能被3和5整除,如果N不能被3和5整除,那么N也决不会被15整除。 第三,对于N来说,不必用从2到N一1的所有素数去除,只需用小于等于√N(根号N)的所有素数去除就可以了。这一点可以用反证法来证明: 如果N是合数,则一定存在大于1小于N的整数d1和d2,使得N=d1×d2。 如果d1和d2均大于√N,则有:N=d1×d2>√N×√N=N。 而这是不可能的,所以,d1和d2中必有一个小于或等于√N。 基于上述分析,设计算法如下: (1)用2,3,5,7逐个试除N的方法求出100以内的所有素数。 (2)用100以内的所有素数逐个试除的方法求出10000以内的素数。 首先,将2,3,5,7分别存放在a[1]、a[2]、a[3]、a[4]中,以后每求出一个素数,只要不大于100,就依次存放在A 数组中的一个单元中。当我们求100—10000之间的素数时,可依次用a[1]-a[2]的素数去试除N,这个范围内的素数可以不保存,直接打印。 【2】用筛法求素数。 简单介绍一下厄拉多塞筛法。厄拉多塞是一位古希腊数学家,他在寻找素数时,采用了一种与众不同的方法:先将2-N的

素数判断程序测试范例

问题描述:键盘输入m和n(10 #include using namespace std; int main() { int m,n,i; static int k=0; cout<<"输入m,m(其中10>m>>n; while(m<=10||m>=n||n>2000) { cout<<"输入数据有误,请再次输入:"<>m>>n; } for(i=m;i<=n;i++) { int x=(int)sqrt((double)i); for(int j=2;j<=x;j++) { if(i%j==0) { break; } else if(j==x) { cout<

一.控制流测试1、控制流图如下:

2、根据以上控制流图: 因为控制流的1-2-3-2部分为用户输入的m,n的重复赋值过程,与输入数据密切相关且每次取值不同,关系到控制流测试,所以将此独立出来:以为节点“2”的复合谓词为或的关系,全为false时只有一种情况,而为true 时有7种情况,对“2”的复合谓词(m<=10||m>=n||n>2000)为真假时其表1如下: 设A:m<=10; B:m>=n; C:n>2000 但是对于节点“2”的情况,并非所有可能都会取到,因为当A为真时,就不会执行B,依此,生成下表2: 根据表2,得出此部分的取值及路径为:

线性筛法求素数的原理与实现

何为线性筛法,顾名思义,就是在线性时间内(也就是O(n))用筛选的方法把素数找出来的一种算法,没用过线性筛素数法的人可能会奇怪,用遍历取余判定素数不是也是线性时间的吗,没错,但是确切的说线性筛法并不是判定素数的,而是在线性时间内求出一个素数表,需要判定是否是素数的时候只要看该数是否在表内就可以瞬间知道是不是素数。 比如想求10000以内的素数,定义表int a[10000],进行线性筛选后,a[n]的值就代表n是不是素数,a[n]如果是1,就代表n是素数,a[n]如果是0,就代表n不是素数,这就是查表。再判定其他的素数也是一样,不用再做任何计算。 而如果用遍历取余,那么每判定一个数都要从头开始再遍历一遍,而线性筛法只在开始一次性运算完,以后只要查表即可,查表通常只需要1条语句。所以如果你的程序从始至终只需要判定那么几次素数那么用遍历取余即可,但是如果需要多次判定素数,而且这个数还不是很小的话,那么线性筛法就会体现出巨大的优越性来。 线性筛法的核心原理就是一句话:每个合数必有一个最大因子(不包括它本身),用这个因子把合数筛掉,还有另一种说法(每个合数必有一个最小素因子,用这个因子筛掉合数,其实都一样,但是我觉得这种方法不太容易说明,这种方法我会在最后给出简略说明)。这个很容易证明:这个小学就知道合数一定有因子,既然是几个数,就一定有最大的一个。最大因子是唯一的,所以合数只会被它自己唯一的因子筛掉一次,把所有合数筛掉后剩下的就全是素数了。 先假设一个数i,一个合数t,i是t最大的因数,t显然可能并不唯一(例如30和45的最大因数都是15)。那么如何通过i知道t呢,t必然等于i乘以一个比i小的素数。先来说这个数为什么一定要比i小,这很显然,如果是i乘上一个比它大的素数,那么i显然不能是t 最大的因子。再来说为什么要是素数,因为如果乘上一个合数,我们知道合数一定可以被分解成几个素数相乘的结果,如果乘上的这个合数x=p1*p2*……,那么 t = i * x = i * p1 * p2……很显然p1* i也是一个因数,而且大于i。所以必须乘上一个素数。 比i小的素数一定有不少,那么该乘哪一个呢,既然t不唯一,那么是不是都乘一遍呢?很显然不行,虽然t不唯一,但全乘一遍很显然筛掉的数的数量远远超过合数的数量。我们先给出结论: 任意一个数i = p1*p2*……*pn,p1、p2、……pn都是素数,p1是其中最小的素数, 设T 为i * M的积(显然T就成了一个合数),也就是T = i * M,(M是素数,并且M<=p1),那么T的最大的因数就是i。 是的,乘上的数要小于等于i最小的质因数。

密码学实验-素数判别

实验报告 实验七、素数判别 实验目的: 1、熟练掌握根据定义判定一个整数n是否为素数的方法及实现。 2、体会素数判定的时效性。 实验内容: 1、写出根据定义判定一个整数n是否为素数的算法及其实现。 2、判定101、10001、10000001、10000000000001是否为素数,并记录执行时间。 实验结果: 如果某个自然数n是素数,那么可能存在这样的情况—在2~n/2范围内没有一个自然数k能够整除n。所以,如果要判断自然数n是否为一个素数,只需要让n不断的去除以从2开始的,到n/2结束的整数k,这是一个反复执行的操作。如果在这个范围内的数没有一个k能够整除n,就说明n是一个素数。反之,只需要存在一个k能够整除n,就说明n不是一个素数。下面是我们对这个算法的分析: (1)首先输入一个需要判定的自然数n; (2)然后,将作为质数标志的字符串变量str的值设置为“是质数”; (3)接着,我们设置一个除数变量,同时也是一个计数变量k,将其初值设置为2; (4)使用第一个判断框,设置循环的条件为“k<=n/2”,因为除数变量k的最大取值不可能超过n/2; (5)使用第二个判断框,设置分支条件“n Mod k = 0”来判定自然数n能否被当前的除数变量k整除,如果条件不成立,则让除数变量k加1,然后返回到循环条件的判断框入口处,否则将质数标记字符串变量的值赋值为“不是质数”,再强行退出循环结构,输出变量str 的值,算法结束; (6)当正常退出循环结构后,也同样要输出质数标记字符串变量str的值,算法结束。对于本次实验,我们首先要把二进制转换成十进制素再利用上述算法判断是否为素数。 运行程序如下所示: #include #include

费马小定理 素数判定 蒙哥马利算法

费马小定理素数判定蒙哥马利算法(强烈推荐) 2009-11-07 12:42 费马小定理素数判定蒙哥马利算法 约定: x%y为x取模y,即x除以y所得的余数,当x

求素数的算法及其复杂度分析

求素数的算法及其复杂度分析2008-04-05 17:46关于搜寻一定范围内素数的算法及其复杂度分析 ——曾晓奇 关于素数的算法是信息学竞赛和程序设计竞赛中常考的数论知识,在这里我跟大家讲一下寻找一定范围内素数的几个算法。看了以后相信 对大家一定有帮助。 正如大家都知道的那样,一个数 n 如果是合数,那么它的所有的因子不超过sqrt(n)--n的开方,那么我们可以用这个性质用最直观的方法 来求出小于等于n的所有的素数。 num = 0; for(i=2; i<=n; i++) { for(j=2; j<=sqrt(i); j++) if( j%i==0 ) break; if( j>sqrt(i) ) prime[num++] = i; //这个prime[]是int型,跟下面讲的不同。 } 这就是最一般的求解n以内素数的算法。复杂度是o(n*sqrt(n)),如果n 很小的话,这种算法(其实这是不是算法我都怀疑,没有水平。当然没 接触过程序竞赛之前我也只会这一种求n以内素数的方法。-_-~)不会耗时很多. 但是当n很大的时候,比如n=10000000时,n*sqrt(n)>30000000000,数量级相当大。在一般的机子它不是一秒钟跑不出结果,它是好几分钟都跑不 出结果,这可不是我瞎掰的,想锻炼耐心的同学不妨试一试~。。。。 在程序设计竞赛中就必须要设计出一种更好的算法要求能在几秒钟甚至一秒钟之内找出n以内的所有素数。于是就有了素数筛法。 (我表达得不清楚的话不要骂我,见到我的时候扁我一顿我不说一句话。。。) 素数筛法是这样的: 1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false. 2.然后: for( i=3; i<=sqrt(n); i+=2 ) { if(prime[i]) for( j=i+i; j<=n; j+=i ) prime[j]=false; } 3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。 原理很简单,就是当i是质(素)数的时候,i的所有的倍数必然是合数。如果i已经被判断不是质数了,那么再找到i后面的质数来把这个质 数的倍数筛掉。 一个简单的筛素数的过程:n=30。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

判断一个数是质数还是合数的方法

判断一个数是质数还是合数的方法 单位:平川区黄峤教管中心双铺中心小学张彦娟 一、质数和合数的意义: 质数:一个数只有1和它本身两个因数,这个数叫作质数。(除2以外所有的质数都是奇数。) 备注: 1、最小的质数是2。 2、既是偶数又是质数的数是2。 3、两个质数相乘的积一定是合数。 合数:一个数除了1和它本身以外还有其他的因数,这个数叫作合数。 备注: 1、最小的合数是4。 2、最大的一位合数是9。 3、1既不是质数,也不是合数。 二、判断一个数是质数还是合数有两种方法: 方法一:⑴判断一个数是质数还是合数需要看这个数的因数的个数,只有2个因数的数一定是质数,有3个或3个以上因数的数是合数。 ⑵个位上是0,2,4,6,8和5的数(除了0,2和5)一定不是质数,质数个位上的数字只能是1,3,7和9。 方法二:判断一个自然数是不是质数,可以用所有比它小的质数

从小到大依次去除它,除到商比除数小,而且还有余数,它就是质数,否则不是质数。 三、问题解析: 下面哪些数是合数哪些数是质数 2 25 9 21 31 91 57 42 1、方法解析:因为除了1和它本身以外还有其他的因数的数是合数,所以先根据“2,5和3的倍数特征”来判断这些数除了1和它本身两个因数以外是否有因数2,5,3,如果有就为合数。 2和42有因数2,但2只有1和2两个因数,所以2是质数,42是合数。9,21,57有因数3,它们都是合数。25有因数5,也是合数。91有因数7,是合数。只有31除了1和它本身之外再没有其他的因数,所以31是质数。 2、解答:25,9,21,91,57,42是合数,2,31是质数。 四、100以内的质数: 100以内的质数有:2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,共25个。

筛法求素数

筛法 筛法,是求不超过自然数N(N>1)的所有质数的一种方法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛子。 具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛”,简称“筛法”。(另一种解释是当时的数写在纸草上,每要划去一个数,就把这个数挖去,寻求质数的工作完毕后,这许多小洞就像一个筛子。) 例如,用筛法找出不超过30的一切质数: 不超过30的质数2,3,5,7,11,13,17,19,23,29共10个。 使用pascal语言,利用筛法求素数的代码: ReadLn(n);{需要求2~n之间所有的素数} For i:=2 To n Do a := True;{全部清成真,表示目前是素数} For i:=2 To n Do If a Then{当该数纪录是质数时开始筛选} For j:=1 To n Div i Do a[2 * j] := False;{筛掉所有质数的倍数} sum := 0;{统计范围内有多少个质数} For i:=2 To n Do If a Then Begin{如果是质数就输出} Write(i, ' '); Inc(sum); End; WriteLn(sum);{输出总数} readln(n);(读入N); for i:=2 to n do a[i]:=true;(先将a数组全部定义为素数,即用true代表素数,false 合数) for i:=2 to trunc(sqrt(n)) do(1 to n 也可以,不过比较浪费时间) begin if a[i]=true then (如果这个数是素数,则执行.这样比较省时间) begin for j:=2 to n div i do a[i*j]=false;(将一切可以被2、3、4...整除的数全部定义为合数) end;

判断一个数是否为素数(c语言)

在C语言中,我们经常会用到判断一个数的性质,今天就以如何判断一个数是否为素数为例来说明思路,希望能够达到触类旁通的效果。 1.直接判断一个数是否为素数,代码如下: /* 目的:判断一个数是否是素数 */ # include int main(void) { int val; int i; scanf("%d",&val); for(i = 2; i < val; i++) // 用2到(val-1)的数去除val { if(val % i == 0) // 判断能否整除 break; } if (i == val) printf("YES!\n"); else printf("No!\n"); } 注:for循环的功能: ①若能整除,通过break跳出函数 ②若一直到val-1都不能整除,此时i再自增1到val,不满足i < val 跳出for循环,这时i = val。

2.通过函数来判断 /* 目的:通过函数判断一个数是否是素数 */ # include bool f(int m) { int i; for(i = 2;i < m; i++) { if(m % i == 0) break; } if(i == m) return true; else return false; } int main(void) { int val; scanf("%d",&val); if (f(val)) //注:此处若写成:if (f(val) == true) 也可以。 printf("YES\n"); else printf("NO\n"); } 对比上述两种方法可见,通过函数来实现比较合适,因为如果要判断的数据过多时,要通过第一种方法实现的话,代码太多,而且也不便于调用,因此推荐使用函数实现此功能。

一些素数个数计算

一些素数个数计算 根据自然数数列因子分布规律和不遵从自然数数列的数列因子分布规律,用这两种方法建立计算公式求算素数个数. 标签:数列素数个数计算项差分布规律猜想 一、欧几里得素数 概念:都是整数,其形式为En=Pn+1,其中Pn是Pn的质数阶乘。 前几个欧几里得数3 7 31 211 2311 30031 510511 …… 因为是En=Pn+1,数列中的项差分布与自然数数列项差分布不同,所以,就不能用求自然数数列的奇质数方法计算。根据欧几里得数的阶乘性质和素数个数分布与计算原理,每一个欧几里得数是否奇质数,只能单独计算。 根据欧几里得数的性质,第1、2、3项欧几里得数不可能有因子,只能是奇质数;第4项211因子可能是11和13,不可能是2、3、5、7,以及≥17的奇质数,所以第4项是奇质数的可能性为1×10/11×12/13≈0.839,以后以此类推。欧几里得素数总个数计算公式F=1(第1项)+1(第2项)+1(第3项)+1×10/11×12/13(第4项)+1×12/13×16/17×18/19×22/23×28/29×30/31×36/37×40/41×42/43×46/47(第5项)+…… 随着欧几里得数的不断增大,F也不断缓慢增大,所以,欧几里得素数有无限个。 以上的单个计算方法,适合于随机抽取(项差不遵从自然数数列项差分布规律)的一组数列和自然数数列的奇质数个数计算。项数越多,计算值越准确。 二、费马素数 概念:形式为2n+1(n=2m,m取值为0、1、2、3……则n为1、2、4、8……)前几个费马数是3、5、17、257、65537、4294967297……求其中的素数个数。 从上面可以看出,项差不符合自然数数列分布规律,费马数数列只是2k+1(k取值为0、1、2、3……)数列中的一部分,可以参照上面的欧几里得素数素数计算方法求解。 当k≠1、2、4、8、16……2n数时,叫做非费马数。非费马数都可以进行因式分解,所以,非费马数都是合数,因子是绝大多数奇质数。以上可以得出结论,费马数是非费马数的因子,而非费马数中除费马数因子之外的因子不可能是费马数的因子。又因n=1、2、4、8、16……所以,费马数自身因子不循环分布,并

相关文档
最新文档