当前位置:   article > 正文

C++高效的质数的判断(2种方法)_c++判断质数

c++判断质数

前提准备

在开始质数的讨论之前,我们先预备一下:

质数的定义:若一个正整数除了1和它自身之外不能被任何自然数整除,则该数称为质数,也叫素数。否则为合数

由定义可知,所有小于等于1的数既不是质数,也不是合数

质数的分布较为稀疏,对于一个足够大的数S,不超过S的质数大约有\frac{N}{InN}个,也就是说每InN个数约有一个质数,这点读者了解即可。

质数的判断(试除法)

对于质数的判断,最简单也最容易想到的方法就是一个一个的筛选,也叫试除法。

如果要判断一个数N,那么我们要对2~N-1的所有数都筛选一遍吗,显然不用。首先肯定的是N-1肯定不能整除N,那么是否能进一步缩小范围。我先给出答案:2~sqrt(N)

严谨的证明过程如下图:(注释:\left \lfloor \right \rfloor\left \lceil \right \rceil分别表示向下,向上取整)

 那好,利用这个性质,我们就可以写出一下代码:

Code(O(sqrt(N)))

  1. #include<cstdio>
  2. bool isprime(int num){
  3. if(num==2)
  4. return true;
  5. if(num%2==0 || num<2)
  6. return false;
  7. else{
  8. for(int i=3;i*i<=num;i+=2){
  9. if(num%i==0){
  10. return false;
  11. }
  12. }
  13. return true;
  14. }
  15. }
  16. int main(){
  17. int x;
  18. scanf("%d",&x);
  19. if(isprime(x)){
  20. printf("Yes");
  21. }
  22. else{
  23. printf("No");
  24. }
  25. return 0;
  26. }

尽管如此,这个代码还是优化了许多,我们单独考虑2这个情况,然后从3开始只枚举奇数。

难道这就是最快的算法吗?


Miller-Robbin算法

其实还有一个更厉害的算法,名为Miller-Robbin算法,要想学会,我们首先需要理解一个定理:

费马小定理

                         对于一个质数 p,任意一个自然数a,那么: a^{p}\equiv a(mod p) ——1

证明如下图所示:

 证明完之后,我们可以左右同时除以一个a,变形成:

                                                                   a^{p-1}\equiv 1(mod p)——2

这个就不一定成立了,可以发现,当a是p-1的倍数时,左式一定是p的倍数,mod一个p就等于0了,不可能等于右边,所以我们必须加上一个条件

                                                                  a与p-1互质

好了,这就是费马小定理。值得注意的是,费马小定理是判断素数的必要不充分条件。如果一个数是质数,它必然满足一上的等式。但是,满足上列等式的数,并不一定是质数。如:

  1. 561
  2. 1105
  3. 1729
  4. 2465
  5. 2821
  6. 6601
  7. 8911
  8. 10585
  9. 15841
  10. 29341
  11. 41041
  12. 46657
  13. 52633
  14. 62745
  15. 63973
  16. 75361
  17. 101101
  18. 115921
  19. 126217
  20. 162401
  21. 172081
  22. 188461
  23. 252601
  24. 278545
  25. 294409
  26. 314821
  27. 334153
  28. 340561
  29. 399001
  30. 410041
  31. 449065
  32. 488881
  33. 512461

 这种合数称之为卡迈克尔数,561是最小的。他们并不满足费马小定理的逆定理!!!可迈克尔数http://oeis.org/A002997

但是,这种事情发生的概率还是比较小的,我们可以随机生成一批数,排除掉能被p-1整除的数,如果它满足费曼小定理的逆定理,那么该数很大程度上可以称之为质数,不确定就多判定几次。我们再配合一个快速幂求出 a^p-1 mod p的值,完美。

快速幂的详解https://blog.csdn.net/way_back/article/details/122760048?spm=1001.2014.3001.5501

Code(O(1))

  1. #include<cstdio>
  2. #include<cstdlib>
  3. int x;
  4. int pow(int a){
  5. int b=x-1;
  6. int ans=1;
  7. while(b>0){
  8. if(b & 1){
  9. ans=((ans%x)*(a%x))%x;
  10. }
  11. a=a*a%x;
  12. b>>=1;
  13. }
  14. return ans;
  15. }
  16. bool isprime(){
  17. int loop=10;
  18. while(loop--){
  19. int t=rand();
  20. while(t%x==0){
  21. t=rand();
  22. }
  23. if(pow(t)!=1){
  24. return false;
  25. }
  26. }
  27. return true;
  28. }
  29. int main(){
  30. scanf("%d",&x);
  31. if(isprime()){
  32. printf("Yes");
  33. }
  34. else{
  35. printf("No");
  36. }
  37. return 0;
  38. }

用10个循环去判断那些卡迈克尔数,结果如下:

 没有问题,但我要循环5次的话,就出现问题了,如图所示:

 有几个数就判断错误了。我们在保证正确率的前提下再提高效率。


下一个内容我们要讨论如何在一个区间内把质数都筛选出来,不见不散

C++区间质数的筛选https://blog.csdn.net/way_back/article/details/122787801

End~~~

写作不易,谢谢大家支持

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/75313
推荐阅读
相关标签
  

闽ICP备14008679号