【算法编程】基于Miller-Rabin的大素数测试
基本原理:
费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1.
利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过计算d=a^(n-1)%n来判断n的素性,当d!=1时,n肯定不是素数,当d=1时,n 很可能是素数.
二次探测定理:如果p是一个素数,且0<x<p,则方程x^2%p=1的解为:x=1或x=p-1.
利用二次探测定理,可以再利用费尔马小定理计算a^(n-1)%n的过程中增加对整数n的二次探测,一旦发现违背二次探测条件,即得出n不是素数的结论.
如果n是素数,则(n-1)必是偶数,因此可令(n-1)=m*(2^q),其中m是正奇数(若n是偶数,则上面的m*(2^q)一定可以分解成一个正奇数乘以2的k次方的形式 ),q是非负整数,考察下面的测试:
序列:
a^m%n; a^(2m)%n; a^(4m)%n; ……;a^(m*2^q)%n
Miller-Rabin素性测试伪代码描述:
1、找出整数k,q,其中k>0,q是奇数,使(n-1=2kq)。
2、随机选取整数a,1<a<n-1。
3、Ifaq mod n=1, printf("该数可能是素数!\n");
4、Forj=0 to k-1 , if a^(2^j*q) mod n = n – 1, printf("该数可能是素数!\n");如果步骤3、4都不成立,则printf("该数肯定不是素数!\n")
5、当该数可能是素数时,随机选取整数a,1<a<n-1。若多次都表明可能是素数,则我们有理由相信该数是素数。
具体代码实现:
1.、BigInt.h文件
#ifndef _BIGNUM_H_ #define _BIGNUM_H_ #define SIZE 128 //一个大整数用个字节保存,最多表示位大整数 #define SIZE_2 2* SIZE typedef unsigned char UCHAR; typedef unsigned short USHORT; UCHAR atox(char ch); //将一个十六进制的字符(4位)转位数字,转换失败返回xff typedef struct BigNum //大整数结构 { UCHAR data[SIZE]; //空间为(SIZE * sizeof(UCHAR)),就是SIZE个字节 }BigNum; BigNum Init(char *str); //初始化大整数,str为十六进制字符串 int GetBitFront(BigNum bignum); //有多少bit (前面的0不算) int GetBitEnd(BigNum bignum); //有多少0(即只算末尾的0个数) BigNum MovBitLetf(BigNum bignum, int n);//向左移n位 BigNum MovBitRight(BigNum bignum, int n); //右移n位 int Cmp(BigNum bignum_a, BigNum bignum_b); //大整数比较大小,>返回1,<返回-1,==返回0 BigNum Mod(BigNum bignum_a, BigNum bignum_b); //大整数模运算 BigNum Sub(BigNum bignum_a, BigNum bignum_b); //大整数减法 void print2(BigNum bignum); //以二进制打印 BigNum Mul(BigNum bignum_a, BigNum bignum_b); //大整数乘法 BigNum Div(BigNum bignum_a, BigNum bignum_b); //大整数除法 BigNum Add(BigNum bignum_a, BigNum bignum_b); //大整数加法 void print10(BigNum bignum);//以十进制打印 int b2d(BigNum bignum); //二进制到转十进制 BigNum modMDyn(BigNum a, BigNum power, BigNum mod); //求大整数幂的模 BigNum d2b(int num); //十进制转二进制 int checkprime(BigNum n,BigNum a); #endif
2. BigInt.c文件:
#include <stdio.h> #include<stdlib.h> #include <string.h> #include "BigInt.h" #include "math.h" #include<time.h> void print2(BigNum bignum)//以二进制打印 { if(GetBitFront(bignum)==0) printf("0\n"); else { for(int i=SIZE-GetBitFront(bignum);i<SIZE;i++) { printf("%c",bignum.data[i]); } printf("\n"); } } BigNum Init(char *str) //高位在0 { int j=0; BigNum bignum; for(inti=SIZE-int(strlen(str));i<SIZE;i++) { bignum.data[i]=str[j]; j++; } for(i=SIZE-int(strlen(str))-1;i>=0;i--) bignum.data[i]='0'; return bignum; } int GetBitFront(BigNum bignum) //有多少bit(前面的0不算) { int BitOfBigNum = SIZE; int i=0; while ((bignum.data[i] == '0')&& (BitOfBigNum > 0)) { i++; BitOfBigNum--; } return BitOfBigNum; } int GetBitEnd(BigNum bignum) //有多少0(即只算末尾的0个数) { int BitOfBigNum = SIZE; int num=0; while ((bignum.data[BitOfBigNum -1] == '0') && (BitOfBigNum > 0)) { num++; BitOfBigNum--; } return num; } BigNum MovBitLetf(BigNum bignum, int n)//向左移n位 { int bignum_len =GetBitFront(bignum); for (int i =SIZE- bignum_len; i<SIZE; i++) { if (i - n < 0) { printf("ok\n"); continue; } bignum.data[i - n] =bignum.data[i]; } for (i = SIZE- n; i <SIZE; i++) { bignum.data[i] ='0'; } return bignum; } BigNum MovBitRight(BigNum bignum, int n) //右移n位 { int bignum_len =GetBitFront(bignum); for (int i = SIZE - 1; i >=SIZE-bignum_len; i--) { if (i<0) { continue; } bignum.data[i] =bignum.data[i-n]; } for (i =0; i <SIZE-bignum_len;i++) { bignum.data[i] = '0'; } return bignum; } int Cmp(BigNum bignum_a, BigNum bignum_b) //大整数比较大小,>返回1,<返回-1,==返回0 { int bignum_a_len =GetBitFront(bignum_a); int bignum_b_len =GetBitFront(bignum_b); if(bignum_a_len>bignum_b_len)return 1; if(bignum_a_len<bignum_b_len)return -1; if(bignum_a_len=bignum_b_len) { int max = bignum_a_len; for (int i =SIZE-max; i<SIZE; i++) { if (bignum_a.data[i]> bignum_b.data[i]) { return 1; } if (bignum_a.data[i]< bignum_b.data[i]) { return -1; } } } return 0; } BigNum Sub(BigNum bignum_a, BigNum bignum_b) //大整数减法 { BigNum bignum_c; int temp=0; int temp1=0; int carry = 0; int i; int j=0; for (i = SIZE-1; i >=0; i--) { temp = bignum_a.data[i] -bignum_b.data[i] -carry; temp1=temp; if(temp==-1) temp1=1; if(temp==-2) temp1=0; bignum_c.data[i] =temp1+48; if(temp<0) carry=1; else carry=0; j++; } return bignum_c; } BigNum Mod(BigNum bignum_a, BigNum bignum_b) //大整数模运算 { BigNum bignum_c =Init("0"); BigNum B; B = bignum_b; int bignum_a_len; int bignum_b_len; int bignum_c_len; if (Cmp(bignum_b, bignum_c) == 0) { printf("错误!除数为\n"); return bignum_c; } bignum_a_len =GetBitFront(bignum_a); bignum_b_len =GetBitFront(bignum_b); bignum_c_len = bignum_a_len -bignum_b_len; while (bignum_c_len >= 0) { B = MovBitLetf(bignum_b,bignum_c_len); int m=0; m=Cmp(bignum_a, B); while (Cmp(bignum_a, B) !=-1)//大于等于 { bignum_a =Sub(bignum_a, B); } bignum_c_len--; } return bignum_a; } BigNum Mul(BigNum bignum_a, BigNum bignum_b) //大整数乘法 { BigNum bignum_c =Init("0"); BigNum bignum=Init("0"); int wei=0; wei=GetBitFront(bignum_a)+GetBitFront(bignum_b)-1; int carry[SIZE_2]; int carry1[SIZE_2]; int mod[SIZE_2]; for(int k=0;k<=SIZE_2;k++) { carry[k]=0; carry1[k]=0; mod[k]=0; } int i=0; int j=0; for(i=SIZE-1;i>=0;i--) { for(j=SIZE-1;j>=0;j--) carry[i+j+1]=(bignum_a.data[i]-48)*(bignum_b.data[j]-48)+carry[i+j+1]; } for(k=SIZE_2-1;k>=0;k--) { if(k==SIZE_2-1) carry1[k]=carry[k]; else carry1[k]=carry1[k+1]/2+carry[k]; } wei=GetBitFront(bignum_a)+GetBitFront(bignum_b)-1; bignum=d2b(carry1[SIZE_2-wei]); for(i=SIZE-1,j=SIZE_2-wei;i>=0&&j>=0;i--,j--) carry1[j]=bignum.data[i]-48; for(k=0;k<SIZE_2;k++) { if(carry1[k]!=0) break; } for(i=SIZE-1,j=SIZE_2-1;j>=k;i--,j--) { bignum_c.data[i]=carry1[j]%2+48; } return bignum_c; } BigNum Div(BigNum bignum_a, BigNum bignum_b) //大整数除法 { BigNum bignum_c =Init("0"); BigNum B; int bignum_a_len; int bignum_b_len; int bignum_c_len; if (Cmp(bignum_b, bignum_c) == 0) { printf("错误!除数为\n"); return bignum_c; } bignum_a_len =GetBitFront(bignum_a); bignum_b_len = GetBitFront(bignum_b); bignum_c_len = bignum_a_len -bignum_b_len; while (bignum_c_len >= 0) { B = MovBitLetf(bignum_b,bignum_c_len); while (Cmp(bignum_a, B) !=-1) { bignum_a =Sub(bignum_a, B); bignum_c.data[SIZE-1-bignum_c_len]++; } bignum_c_len--; } return bignum_c; } BigNum Add(BigNum bignum_a, BigNum bignum_b) //大整数加法 { BigNum bignum_c; int temp; int carry = 0; int i; for (i = SIZE-1; i>=0; i--) { temp = bignum_a.data[i]-48+ bignum_b.data[i]-48 + carry; if(temp==2) { temp=0; carry=1; } else if(temp==3) { temp=1; carry=1; } else carry=0; bignum_c.data[i] = temp+48; } return bignum_c; } int b2d(BigNum bignum) //二进制转十进制 { int n=0; int j=0; int result=0; n=GetBitFront(bignum); for(int i=SIZE-1;i>=0;i--) { result=result+(bignum.data[i]-48)*pow(2,j); j++; } return result; } void print10(BigNum bignum) //打印十进制大整数 { int temp[SIZE]; int i = 0; int j; BigNum c; while (Cmp(bignum,Init("0")) == 1) { c=Mod(bignum,Init("1010")); temp[i] = b2d(c); bignum = Div(bignum,Init("1010")); i++; } for (j = i - 1; j >= 0; j--) { printf("%d",temp[j]); } printf("\n"); } BigNum modMDyn(BigNum a, BigNum power, BigNum mod) //求大整数幂的模 { BigNum temp; BigNum result; BigNum t1; temp=Mod(a,mod); result=Init("1"); for(inti=SIZE-1;i>=SIZE-GetBitFront(power);i--) { if(power.data[i]=='1') { t1=Mul(result,temp); result=Mod(Mul(result,temp),mod); } temp=Mod(Mul(temp,temp),mod); } return result; } BigNum d2b(int num) //十进制转二进制 { BigNum bignum; bignum=Init("0"); int a=0; int b=0; int i=1; while(num>0) { a=num%2; num=num/2; bignum.data[SIZE-i]=a+48; i++; } return bignum; } int checkprime(BigNum n,BigNum a) { BigNum k; BigNum q; // BigNum a; BigNum n1;//n1=n-1 BigNum num1;//num1为常数1 BigNum num2;//num2为常数2 BigNum k2;//2^k BigNum k22; int k1=0; //末尾0的个数 num1=Init("1"); num2=Init("10"); k=Init("0"); q=Init("0"); n1=Init("0"); k22=Init("10"); // a=Init("1010");//选择的数 n1=Sub(n,num1); k1=GetBitEnd(n1); k=d2b(k1); q=MovBitRight(n1,k1); k2=Div(n1,q); if(Cmp(modMDyn(a,q,n),num1)==0) { // print2(n); // printf("该数可能是素数!\n"); return 1; } for(int i=0;i<b2d(k);i++) { k22=MovBitLetf(num1,i); if(Cmp(modMDyn(a,Mul(k22,q),n),n1)==0) { // print2(n); // printf("该数可能是素数!\n"); return 1; } } print10(n); printf("该数肯定不是素数!\n"); return 0; } void main()//主函数的内容可以根据你自己的需求编写! { BigNum n;//n为要判断的素数 BigNum k; BigNum q; BigNum a; BigNum n1;//n1=n-1 BigNum num1;//num1为常数1 BigNum num2;//num2为常数2 BigNum k2;//2^k BigNum k22; int k1=0; //末尾0的个数 int flag=0; int aa=10; int i=0; num1=Init("1"); num2=Init("10"); k=Init("0"); q=Init("0"); n1=Init("0"); k22=Init("10"); a=Init("1010");//选择的数 n=Init("1111111111111111111111111111111111111111111111111111111111111111");//最大的64bit数 a可以设128bit内的值 // n=Init("1111"); srand(time(NULL)); n1=Sub(n,Mul(num2,num1)); for(int kk=0;kk<30;kk++)//这里可以自己设置循环次数 { n=Sub(n,Mul(num2,num1));//n每次-2 print10(n); printf("第%d次:\n",kk); flag=checkprime(n,a); while(flag==1&&i<10) { i++; print10(n); aa=rand()%10+5;//注意!n必须大于a a=d2b(aa); flag=checkprime(n,a); printf("ok%d\n",aa); } if(i==10) { i=0; print10(n); printf("该数肯定是素数!\n"); } printf("\n"); } }
运行结果如下:
原文:http://blog.csdn.net/tengweitw/article/details/23952839
作者:nineheadedbird
【算法编程】基于Miller-Rabin的大素数测试的更多相关文章
- Miller_Rabbin大素数测试
伪素数: 如果存在和n互素的正整数a满足a^(n-1)≡1(mod n),则n是基于a的伪素数. 是伪素数但不是素数的个数是非常非常少的,所以如果一个数是伪素数,那么他几乎是素数. Miller_Ra ...
- Miller-Rabin大素数测试模板
根据费马小定理: 对于素数n,a(0<a<n),a^(n-1)=1(mod n) 如果对于一个<n的正整数a,a^(n-1)!=1(mod n),则n必不是素数. 然后就可以随机生成 ...
- Miller Rabin 大素数测试
PS:本人第一次写随笔,写的不好请见谅. 接触MillerRabin算法大概是一年前,看到这个算法首先得为它的神奇之处大为赞叹,竟然可以通过几次随机数据的猜测就能判断出这数是否是素数,虽然说是有误差率 ...
- 大素数测试的Miller-Rabin算法
Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小.出错的概率到底是多少,存在严格的理论推导. 一.费马小定理 假如p是质数,且gcd(a,p)=1,那么 a(p ...
- 大素数测试 求因子 poj 1811
抄别人的 #include<stdio.h> #include<string.h> #include<algorithm> #include<stdlib.h ...
- hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥
Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Pr ...
- 【数论基础】素数判定和Miller Rabin算法
判断正整数p是否是素数 方法一 朴素的判定
- Miller Rabin素数检测与Pollard Rho算法
一些前置知识可以看一下我的联赛前数学知识 如何判断一个数是否为质数 方法一:试除法 扫描\(2\sim \sqrt{n}\)之间的所有整数,依次检查它们能否整除\(n\),若都不能整除,则\(n\)是 ...
- (Miller Rabin算法)判断一个数是否为素数
1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...
随机推荐
- 【mybatis深度历险系列】mybatis中的高级映射一对一、一对多、多对多
学习hibernate的时候,小编已经接触多各种映射,mybatis中映射有到底是如何运转的,今天这篇博文,小编主要来简单的介绍一下mybatis中的高级映射,包括一对一.一对多.多对多,希望多有需要 ...
- /proc/stat 详解
在Linux系统中,可以用/proc/stat文件来计算cpu的利用率.这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻. cat /proc/stat cpu 6 ...
- 找不到BufferedImage这个Class的解决方法
找不到BufferedImage这个Class的解决方法 环境: [1]RedHat AS5 64位 [2]WebSphere6.0 32位版本 正文: 发现原来在RedHat AS4 ...
- svn(subversion)代码版本管理在linux下的一些常见使用命令
以下的操作都是默认你的服务器安装有svn的大前提下进行的. 一.创建版本库 我的版本库存放路径为: /var/svn : 下面我们来创建一个名为 svntet 的版本库 注释: svnadmin ...
- memcached实战系列(五)Memcached: List all keys 查询所有的key
memcached可能当时设计的时候就把它定位为内存性的kv结构的缓存系统.所以没有持久化到磁盘的命令,也没有查看所有key的值得命令.可能觉得没必要吧,你要是缓存1个G内存的数据,自己都头大,还敢看 ...
- Android简易实战教程--第七话《在内存中存储用户名和密码》
首先是配置文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns ...
- Android 之Toast讲解-android学习之旅(一)
Toast比较常用,用于显示简短的提醒,比如网络连接断开等. Toast的简单编码实例 findViewById(R.id.button1).setOnClickListener(new OnClic ...
- ASP.net 路径问题 详解
各位有没有碰到在日常工作中经常在路径设置的时候把 "~/ ../ .../ . / .http://www.cnblogs.com/"这些符号搞混搞乱了?偶尔还会因路径的问题郁闷了 ...
- (NO.00004)iOS实现打砖块游戏(十一):"一闪一闪亮晶晶,我们都是小星星"
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 现在一个基本的游戏逻辑已经搭建好了,但是感觉还是缺点什么呢? 蠢 ...
- A*寻路算法入门(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...