Rabin_Miller
来源:互联网 发布:田众和时代网络 编辑:程序博客网 时间:2024/05/21 18:45
除以p的余数正好是一个1到p-1的
排列。例如,5是素数,3, 6, 9, 12除以5的余数分别为3, 1, 4, 2,正好就是1到4这四个数。
反证法,假如结论不成立的话,那么就是说有两个小于p的正整数m和n使得na和ma除以p的余数相同。不妨假设n>m,
则p可以整除a(n-m)。但p是素
数,那么a和n-m中至少有一个含有因子p。这显然是不可能的,因为a和n-m都比p小。
用同余式表述,我们证明了:
(p-1)! ≡ a * 2a * 3a * … * (p-1)a (mod p)
也即:
(p-1)! ≡ (p-1)! * a^(p-1) (mod p)
两边同时除以(p-1)!,就得到了我们的最终结论:
1 ≡ a^(p-1) (mod p)
费马小定里的欧拉推广:a^φ(m) ≡ 1 (mod m)(其中φ(m)为与m互质的数的个数)
证明与费马小定理类似
但是费马小定理的逆命题并不正确,即,当满足a^(p-1) mod p = 1的数p不一定是素数,例如p=341,a=2,
而此时p=11*13
后来,人们又发现了561, 645, 1105等数都表明a=2时Fermat小定理的逆命题不成立。虽然这样的数不多,
但不能忽视它们的存在。于是,人们把所
有能整除2^(n-1)-1的合数n叫做伪素数(pseudoprime),意思就是告诉人们这个素数是假的。
不满足2^(n-1) mod n = 1的n一定不是素数;如果满足的话则多半是素数。这样,一个比试除法效率更高的
素性判断方法出现了:制作一张伪素数
表,记录某个范围内的所有伪素数,那么所有满足2^(n-1) mod n = 1且不在伪素数表中的n就是素数。之所以
这种方法更快,是因为我们可以使用
二分法快速计算2^(n-1) mod n 的值,这在计算机的帮助下变得非常容易;在计算机中也可以用二分查找有序
数列、Hash表开散列、构建Trie树等
方法使得查找伪素数表效率更高。
(1)计算奇数M,使得N=(2**r)*M+1
(2)选择随机数A<N
(3)对于任意i<r,若A**((2**i)*M) MOD N = N-1,则N通过随机数A的测试
(4)或者,若A**M MOD N = 1(即i=0时),则N通过随机数A的测试
(5)让A取不同的值对N进行5次测试,若全部通过则判定N为素数
另一种表述供参考,有点难理清:
首先选择一个代测n,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
(1) 选择一个小于n的随机数a。
(2) 设j=0(j<b)且z=a^m mod n
(3) 如果z=1或z=n-1,那麽p通过测试,可能使素数
(4) 如果j>0且z=1, 那麽n不是素数
(5) 设j=j+1。如果b且z<>n-1,设z=z^2 mod n,然后回到(4)。如果z=n-1,那麽n通过测试,可能为素数。
(6) 如果j=b 且z<>p-1,不是素数
若N 通过一次测试,则N 不是素数的概率为 25%,若N 通过t 次测试,则N 不是
素数的概率为1/4**t。事实上取t 为5 时,N 不是素数的概率为 1/128,N 为素数的
概率已经大于99.99%。
在实际应用中,可首先用300—500个小素数对N 进行测试,以提高拉宾米勒测试
通过的概率,从而提高测试速度。而在生成随机素数时,选取的随机数最好让 r=0,
则可省去步骤(3) 的测试,进一步提高测试速度
*/
static boolean Witness(int a,int n)
{
int i,d=1,x;
for (i=(int)Math.ceil(Math.log((double)n-1)/Math.log(2.0))-1;i>=0;--i) {
x=d;
d=(d*d)%n;
if ((1==d) && (x!=1) && (x!=n-1))
return true;
if (((n-1)&(1<<i))>0)
d=(d*a)%n;
}
return (d!=1);
}
static boolean Rabin_Miller(int n,int s)
{
int j,a;
for (j=0;j<s;++j) {
a=(int) (Math.random()*(n-2)+1);
if (Witness(a,n))
return false;
}
return true;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int range=100;
int count=0;
for (int i=3;i<range;i+=2)
if (Rabin_Miller(i,50)) {
count++;
System.out.print(i+"");
if(count%15==0){
System.out.println();
}
}
}
}
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如果任意一式成立,我们就说n通过了测试,但是有可能不是素数也能通过测试。所以我们通常要做多次这样的测试,以确保我们得到的是一个素数。(DDS的标准是要经过50次测试)
采用Rabin-Miller算法进行验算
首先选择一个代测n,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
(1) 选择一个小于n的随机数a。
(2) 设j=0(j<b)且z=a^m mod n
(3) 如果z=1或z=n-1,那麽p通过测试,可能使素数
(4) 如果j>0且z=1, 那麽n不是素数
(5) 设j=j+1。如果b且z<>n-1,设z=z^2 mod n,然后回到(4)。如果z=n-1,那麽n通过测试,可能为素数。
(6) 如果j=b 且z<>p-1,不是素数
[cpp] view plaincopyprint?
#include<iostream.h>
#include<time.h>
#include<stdlib.h>
//随机数产生器
//产生m~n之间的一个随机数
unsigned long random(unsigned long m,unsigned long n)
{
srand((unsigned long)time(NULL));
return(unsigned long)(m+rand()%n);
}
//模幂函数
//返回X^YmodN
long PowMod(long x,long y,long n)
{
long s,t,u;
s=1;t=x;u=y;
while(u){
if(u&1)s=(s*t)%n;
u>>=1;
t=(t*t)%n;
}
return s;
}
//Rabin-Miller素数测试,通过测试返回1,否则返回0。
//n是待测素数。
//注意:通过测试并不一定就是素数,非素数通过测试的概率是1/4
int RabinMillerKnl(unsigned long n)
{
unsigned long b,m,j,v,i;
//先计算出m、j,使得n-1=m*2^j,其中m是正奇数,j是非负整数
m=n-1;
j=0;
while(!(m&1))
{
++j;
m>>=1;
}
//随机取一个b,2<=b<n-1
b=random(2,m);
//计算v=b^mmodn
v=PowMod(b,m,n);
//如果v==1,通过测试
if(v==1)
{
return 1;
}
i=1;
//如果v=n-1,通过测试
while(v!=n-1)
{
//如果i==l,非素数,结束
if(i==j)
{
return 0;
}
//v=v^2modn,i=i+1
v=PowMod(v,2,n);
i++;
}
return 1;
}
intmain()
{
unsigned long p;
int count=0;
cout<<"请输入一个数字"<<endl;
cin>>p;
for(int temp=0;temp<5;temp++)
{
if(RabinMillerKnl(p))
{
count++;
}
else
break;
}
if(count==5)
cout<<"一共通过5次测试,是素数!"<<endl;
else
cout<<"不是素数"<<endl;
return 0;
}
- Rabin_Miller
- Java开源知识库:XWiki安装(Windows平台)
- 2013秋13级预备队集训练习1 K - The Collatz Sequence
- C语言实现状态机
- Effective Objective-C 2.0: Item 30: Use ARC to Make Reference Counting Easier
- 开启手机LogCat:Unable to open log device ‘/dev/log/main’: No such file or directory
- Rabin_Miller
- 2013秋13级预备队集训练习1 L - Linear Cellular Automata
- 重构学习笔记
- 利用WPF建立自适应窗口大小布局的WinForm窗口31
- 运行nslookup出错,bind9启动提示
- github 之 如何在项目中加入专业的文档说明
- 如何在Linux系统下进行C++程序开发
- 最牛B的编码套路
- 初学UI之关灯游戏