【算法编程】基于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这 ...
随机推荐
- 信用卡3D验证相关资料
3D 验证服务,是银行与VISA .MASTERCARD国际组织联合推出的为保障银行维萨及万事达信用卡持卡客户网上交易安全,防范网上伪冒交易的一项信用卡网上支付安全验证服务( 维萨卡使用的验证服务叫& ...
- FFmpeg的HEVC解码器源代码简单分析:解析器(Parser)部分
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- 集成JPA+springmvc+spring+EJB中的Java EE应用
EJB是sun的JavaEE服务器端组件模型,设计目标与核心应用是部署分布式应用程序.凭借java跨平台的优势,用EJB技术部署的分布式系统可以不限于特定的平台.EJB (Enterprise Jav ...
- 用Maven打包成EAR部署JBoss
基于原理的架构里面,考虑这次升级版本,可谓是一步一个脚印的向上走啊,可以说步步为坎,别人的知识,和自己的知识,相差很多啊,什么都懂点,但是具体没有使用,就理解不深刻了,心有余而力不足,所以一切我们自己 ...
- Latex居中
居中文本 环境:\begin{center} 第一行\\第二行\\...第n行 \end{center}.可以用\\[长度]来插入可以省略的额外行间距.在一个环境内部,可以用命令\centering来 ...
- FFmpeg源代码结构图 - 编码
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- Android项目开发填坑记-so文件引发的攻坚战
故事的最初 我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的so ...
- Cocoa惯性思维调试一例
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 人总有惯性思维,在编程调试里也不例外.你总以为错误是显然的那一 ...
- UNIX网络编程——带外数据小结
TCP没有真正的带外数据,不过提供紧急模式和紧急指针.一旦发送端进入紧急模式,紧急指针就出现在发送到对端的分节中的TCP首部中.连接的对端收取该指针是在告知接收进程发送端已经进入紧急模式,而且该指针指 ...
- Dynamics CRM Microsoft SQL Server 指定的数据库具有更高的版本
在做NLB部署时遇到这么个问题,CRMAPP1安装的CRM版本是6.1已经打了SP1补丁,而在CRMAPP2上的CRM安装包是6.0版本,在选择连接现有部署后,最后一步检测就出了问题,如下图所示. 看 ...