• 100以内的质数


      质数(prime number)又称素数,有无限个。质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数,这样的数称为质数。

      求解一个算法,我们首先要知道它的数学含义.依据这个原则,首先我们要知道什么是素数.; 素数是这样的整数,它除了表示为它自己和1的乘积以外,无论他表示为任何两个整数的乘积。
    找素数的方法多种多样。
     1 #include <stdio.h>
     2 #include<math.h>
     3 
     4 void main(){
     5     int i,j;
     6     for (i=2;i<100;i++){
     7         int flag=0;
     8         for (j=2;j<sqrt(i);j++){//从2到sqrt(i)进行判断 
     9             if(i%j==0) flag=1;//若存在其他因子,flag=1 
    10         }
    11         if(flag==0) printf("%d-",i);//flag==0则表示不存在除了1和本身的其他因子。可以输出。  
    12     }
    13 } 
      1:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来(一直列到你不想再往下列为止,比方说,一直列到10,000)。第一个数是2,它是一个素数,所以应当把它留下来,然后继续往下数,每隔一个数删去一个数,这样就能把所有能被2整除、因而不是素数的数都去掉。在留下的最小的数当中,排在2后面的是3,这是第二个素数,因此应该把它留下,然后从它开始往后数,每隔两个数删去一个,这样就能把所有能被3整除的数全都去掉。下一个未去掉的数是5,然后往后每隔4个数删去一个,以除去所有能被5整除的数。再下一个数是7,往后每隔6个数删去一个;再下一个数是11,往后每隔10个数删一个;再下一个是13,往后每隔12个数删一个。就这样依法做下去。
    但是编程我们一般不采用上面的方法,并不说这中方法计算机实现不了,或者说实现算法比较复杂。因为它更像一个数学推理。最后我们也给一个算法。
    下面我们介绍几种长用的编程方法。
           2:遍历2以上N的平方根以下的每一个整数,是不是能整除N;(这是最基本的方法)

      其实只要从 2 一直尝试到√x,就可以了。估计有些网友想不通了,为什么只要到√x 即可?
      简单解释一下:因数都是成对出现的。比如,100的因数有:1和100,2和50,4和25,5和20,10和10。看出来没有?成对的因数,其中一个必然小于等于100的开平方,另一个大于等于100的开平方。至于严密的数学证明,用小学数学知识就可以搞定,俺就不啰嗦了。

           3:遍历2以上N的平方根以下的每一个素数,是不是能整除N;(这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
           4:采用Rabin-Miller算法进行验算;
    例如:N=2^127-1是一个38位数,要验证它是否为素数,用上面几个不同的方法:
    验算结果,假设计算机能每秒钟计算1亿次除法,那么
    算法2要用4136年,算法3要用93年,算法4只要不到1秒钟!(这些数据是通过计算得到)
     
     
    下面我们分别实现上面的三种算法:
    以下算法我们不涉及内存溢出,以及大数字的问题。如果测试数字超过2^32,发生内存溢出,你需要自己使用策略解决这个问题,在这里只讨论32位机有效数字算法。
    1:// 算法0:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来
     1 // 最后数组中不为0的数字就是要查找的素数。
     2 void PrimeNumber0()
     3 {
     4      //   int time ::GetTickCount();
     5      //   cout << "start time:" << time << endl;
     6  
     7      int Max[MAX_NUMBER];        // 在栈上分配,栈上空间要求一般都在2M之间,
     8      //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).
     9      memset(Max,0,MAX_NUMBER);
    10      for(int i = 0 ; i < MAX_NUMBER; ++i)
    11      {
    12           Max[i] = i;
    13      }
    14      int cout = 0;// 记录当前i的位置
    15  
    16      // 遍历整个数组
    17      for(i = 1; i < MAX_NUMBER; ++i)
    18      {
    19          if(Max[i] != 0 )// 如果数据不为0,说明是一个素数
    20          {
    21               int iCout = i;
    22               int j = Max[i];// 记录数组中数组位的数字,以便设置
    23               while((iCout+=j) < MAX_NUMBER)
    24               {
    25                    // 把不是素数的数位在数组中置为0
    26                    Max[iCout] = 0;
    27               }
    28               ++cout;
    29          }
    30      }
    31  
    32      //   int time ::GetTickCount();
    33      //   cout << "end time:" << time << endl;
    34 }
     
    2:这个算法可以修改成为,验证一个给定数字是否是一个素数。
     1 // 因为我们讨论多个算法,所以我们把每个算法都单独
     2 // 写在一个或多个函数内。这些函数并不要求输入值和返回值
     3 // 如果你需要这些结果,可以自己修改。
     4  
     5 // 算法1:遍历2以上N的平方根以下的每一个整数,是不是能整除N;
     6 void PrimeNumber1()
     7 {
     8 //   int time ::GetTickCount();
     9 //   cout << "start time:" << time << endl;
    10  
    11      int Max[MAX_NUMBER/2];      // 在栈上分配,栈上空间要求一般都在2M之间,
    12 //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
    13 // 所以没有必要申请和所求数字同样大小的空间。
    14      memset(Max,0,MAX_NUMBER);
    15      Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧
    16      int cout = 1;// 记录素数个数
    17  
    18      // 挨个数进行验证
    19      bool bflag = true;
    20      for(int i = 3; i < MAX_NUMBER; ++i)
    21      {
    22          bflag = true;
    23          // 需要是使用数学库(math.h)中sqrt
    24          int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度
    25          // 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度
    26          for (int j = 2; j < iTemp; ++j)
    27          {
    28               if(i%j == 0)// 求余,如果为0说明,可以整除,不是素数。
    29               {
    30                    bflag = false;
    31                    break;
    32               }
    33          }
    34          // 经过验证是素数,放入数组。
    35          if(bflag)
    36          {
    37               Max[cout++] = i;
    38          }
    39      }
    40  
    41 //   int time ::GetTickCount();
    42 //   cout << "end time:" << time << endl;
    43  
    44 }
     
    3:这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道
     1 // 算法2:遍历2以上N的平方根以下的每一个素数,是不是能整除N;
     2 // (这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
     3 void PrimeNumber2()
     4 {
     5      //   int time ::GetTickCount();
     6      //   cout << "start time:" << time << endl;
     7  
     8      int Max[MAX_NUMBER/2];      // 在栈上分配,栈上空间要求一般都在2M之间,
     9      //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
    10      // 所以没有必要申请和所求数字同样大小的空间。
    11      memset(Max,0,MAX_NUMBER);
    12      Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧
    13      int cout = 1;// 记录素数个数
    14  
    15      // 挨个数进行验证
    16      bool bflag = true;
    17      for(int i = 3; i < MAX_NUMBER; ++i)
    18      {
    19          bflag = true;
    20          // 需要是使用数学库(math.h)中sqrt
    21          int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度
    22          // 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度
    23 /////////////////////////////////////////////////////////////////////////////////
    24          // 修改的是这里以下的部分
    25          for (int j = 0; j < cout; ++j)
    26          {
    27               if(i%Max[j] == 0)// 求余,如果为0说明,可以整除,不是素数。
    28               {
    29                    bflag = false;
    30                    break;
    31               }
    32          }
    33          // 修改的是这里以上的部分
    34 //////////////////////////////////////////////////////////////////////////////////
    35          // 经过验证是素数,放入数组。
    36          if(bflag)
    37          {
    38               Max[cout++] = i;
    39          }
    40      }
    41  
    42      //   int time ::GetTickCount();
    43      //   cout << "end time:" << time << endl;
    44  
    45 }
     
    4:采用Rabin-Miller算法进行验算,Rabin-Miller算法是典型的验证一个数字是否为素数的方法。判断素数的方法是Rabin-Miller概率测试,那么他具体的流程是什么呢。假设我们要判断n是不是素数,首先我们必须保证n 是个奇数,那么我们就可以把n 表示为 n = (2^r)*s+1,注意s 也必须是一个奇数。然后我们就要选择一个随机的整数a (1<=a<=n-1),接下来我们就是要判断 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j<R),如果任意一式成立,我们就说n通过了测试,但是有可能不是素数也能通过测试。所以我们通常要做多次这样的测试,以确保我们得到的是一个素数。(DDS的标准是要经过50次测试)
     
     1 // 算法3:采用Rabin-Miller算法进行验算
     2 //首先选择一个代测的随机数p,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
     3  
     4 //(1) 选择一个小于p的随机数a。
     5 //(2) 设j=0且z=a^m mod p
     6 //(3) 如果z=1或z=p-1,那麽p通过测试,可能使素数
     7 //(4) 如果j>0且z=1, 那麽p不是素数
     8 //(5) 设j=j+1。如果j<b且z<>p-1,设z=z^2 mod p,然后回到(4)。如果z=p-1,那麽p通过测试,可能为素数。
     9 //(6) 如果j=b 且z<>p-1,不是素数
    10  
    11 // 判定是否存在 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j<R),
    12  
    13 bool Witness(int a,int n)
    14 {
    15      // 解释一下数学词汇:
    16      // ceil求不小于x的最小整数,函数原型extern float ceil(float x);求得i的最大值
    17      // log计算x的自然对数,函数原型extern float log(float x);
    18      long i,d=1,x;
    19      for (i=(int)ceil(log((double)n-1)/log(2.0))-1;i>=0;--i)
    20      {
    21          x=d;
    22          d=(d*d)%n;
    23          if ((1==d) && (x!=1) && (x!=n-1))
    24          {
    25               return 1;
    26          }
    27          if ((n-1)&(1<0))
    28          {
    29               d=(d*a)%n;
    30          }
    31      }
    32      return (d!=1);
    33  
    34 }
    35  
    36 // 参数n,是要测定的数字,s是要内部测试的次数。
    37 bool Rabin_Miller(int n,int s)
    38 {
    39      for (int j = 0;j < s; ++j)
    40      {
    41           int a = rand()*(n-2)/RAND_MAX + 1;// 获得一个随机数1<=a<=n-1
    42          if (Witness(a,n))// 利用这个随即数和n进行判断对比,只要有一次返回true,就说明n不是一个素数
    43          {
    44               return false;
    45          }
    46      }
    47      return true;// 通过验证是一个素数
    48 }
    49  
    50 // 算法3:采用Rabin-Miller算法进行验算
    51 // 这个算法是求大素数使用的。所以你的必须想办法支持大数字运算,
    52 // 不然极易造成内存访问失效,我在我的机子上,MAX_NUMBER=10000时就会出现问题,1000就没有问题
    53 void PrimeNumber3()
    54 {
    55     
    56      int Max[MAX_NUMBER/2];// 在栈上分配,栈上空间要求一般都在2M之间,
    57      //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少
    58      // 所以没有必要申请和所求数字同样大小的空间。
    59      int cout = 0;// 记录素数个数
    60      memset(Max,0,MAX_NUMBER/2);
    61  
    62      for(int i = 2; i < 1000; ++i)
    63      {
    64          if(Rabin_Miller(i,20))
    65          {
    66               Max[cout++] = i;
    67          }
    68      }
    69 }

      Miller-Rabin算法是目前主流的基于概率的素数测试算法,在构建密码安全体系中占有重要的地位。通过比较各种素数测试算法和对Miller-Rabin算法进行的仔细研究,证明在计算机中构建密码安全体系时, Miller-Rabin算法是完成素数测试的最佳选择。通过对Miller-Rabin 算 法底层运算的优化,可以取得较以往实现更好的性能。随着信息技术的发展、网络的普及和电子商务的开展, 信息安全逐步显示出了其重要性。信息的泄密、伪造、篡改 等问题会给信息的合法拥有者带来重大的损失。在计算机中构建密码安全体系可以提供4种最基本的保护信息安全的服 务:保密性、数据完整性、鉴别、抗抵赖性,从而可以很大 程度上保护用户的数据安全。在密码安全体系中,公开密钥 算法在密钥交换、密钥管理、身份认证等问题的处理上极其有效,因此在整个体系中占有重要的地位。目前的公开密钥 算法大部分基于大整数分解、有限域上的离散对数问题和椭 圆曲线上的离散对数问题,这些数学难题的构建大部分都需 要生成一种超大的素数,尤其在经典的RSA算法中,生成的素数的质量对系统的安全性有很大的影响。目前大素数的生成,尤其是随机大素数的生成主要是使用素数测试算法,本 文主要针对目前主流的Miller-Rabin 算法进行全面系统的分析和研究,并对其实现进行了优化。

  • 相关阅读:
    互联网实习笔记之shell笔记
    互联网实习笔记之30天总结
    记被论文排版虐的一天
    大论文排版技巧
    Matlab2014a使用VS2015混合编译
    腾讯云服务器创建swap空间
    使用vs2015开发linux:Ubuntu程序
    使用VS2015远程GDB调试
    nullptr、NULL、null和0
    《将博客搬至CSDN》
  • 原文地址:https://www.cnblogs.com/smuxiaolei/p/7533386.html
Copyright © 2020-2023  润新知