Miller_Rabin素数检测方法,又称为强伪素数检测方法;
它是以:
1、费马小定理证明: 如果p是一个质数,而整数a不是p的倍数,则有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1(mod \: \, p) ap−1≡1(modp)
前提: 若a%p=b%p,c%p=b%p;则: ( a × b ) % p = ( a % p ) ∗ ( b % p ) ∗ ( c % p ) ; (a\times b)\%p=(a\%p)*(b\%p)*(c\%p); (a×b)%p=(a%p)∗(b%p)∗(c%p);
例子: 设 a = 2 , p = 5 。它分别对 a × 1 , a × 2 , a × 3 , a × 4 求 p 的模是 2 , 4 , 1 , 3 设a=2,p=5。它分别对a\times1,a\times 2,a\times 3,a\times4求p的模是2,4,1,3 设a=2,p=5。它分别对a×1,a×2,a×3,a×4求p的模是2,4,1,3
假设: ( a × 1 ) % p . . . . . . ( a × ( p − 1 ) ) ≡ 1 % p . . . . . . ( p − 1 ) % p (a\times1)\%p......(a\times (p-1))\equiv 1\%p......(p-1)\%p (a×1)%p......(a×(p−1))≡1%p......(p−1)%p
∴ \therefore ∴ ( a × 1...... a × ( p − 1 ) ) % p ≡ ( 1 × . . . . . . ( p − 1 ) ) % p ; (a\times1......a\times(p-1))\%p\equiv (1\times......(p-1))\%p; (a×1......a×(p−1))%p≡(1×......(p−1))%p;提出所有的a;
a p − 1 × ( 1...... ( p − 1 ) ) % p ≡ ( 1 × . . . . . . ( p − 1 ) ) % p ; a^{p-1}\times(1......(p-1))\%p\equiv (1\times......(p-1))\%p; ap−1×(1......(p−1))%p≡(1×......(p−1))%p; 消去 ( 1...... ( p − 1 ) (1......(p-1) (1......(p−1);
最终: a p − 1 ≡ 1 ( m o d p ) 成立; a^{p-1}\equiv 1(mod\:\,p)成立; ap−1≡1(modp)成立;
2、二次探测证明: 如果 p 是一个素数,0 < x < p, 则方程 x 2 ≡ 1 ( m o d p ) x^{2}≡1(mod\:\,p) x2≡1(modp)的解为 x = 1 或 x = p - 1;
易知: x 2 − 1 = 0 ( m o d p ) x^2-1=0(mod\:\,p) x2−1=0(modp)
∴ ( x + 1 ) ( x − 1 ) = 0 ( m o d p ) ; \therefore (x+1)(x-1)=0(mod\:\,p); ∴(x+1)(x−1)=0(modp);
很显然1与(p-1)成立;
∵ p 是质数; \because p是质数; ∵p是质数;
∴ 仅有两个成立; \therefore 仅有两个成立; ∴仅有两个成立;
(1)我们可以多选择几个 ,如果全部通过,那么 大概率是质数。
(2) 素数测试中,“大概率”意味着概率非常大,基本上可以放心使用。
(3)当取遍小等于 30 的所有素数时,可以证明int范围内的数不会出错。
(4)代码中我用的 类型,不过实际上miller_Rabin素数测试可以承受更大的范围。
(5)另外,如果是求一个long long类型的平方,可能会爆掉,因此有时我们要用“快速积”,不能直接乘.
#include
using namespace std;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int Quick_mulitiply(int a,int b,int c){ //快速积;a*b%c;
long long ans=0,res=a;
while(b){
if(b&1){
ans=(ans+res)%c;
}
res=(res+res)%c;
b>>=1;
}
return (int)ans;
}
int Quick_power(int a,int n,int c){//快速幂;a^n%p;
int ans=1,res=a;
while(n){
if(n&1){
ans=Quick_mulitiply(ans,res,c);
}
res=Quick_mulitiply(res,res,c);
n>>=1;
}
return ans;
}
bool miller_rabin(int x){
int i,j,k;
int t=x-1;
int s=0;
if(x==2)return true;
if(x==1||x==0)return false;
if(x%2==0)return false;
while(!(t&1)){ //转换为2^s*t=x-1; t为偶数;
s++;
t>>=1;
}
for(i=0;i<10&&prime[i]>n;
if(miller_rabin(n)){
cout<<"true";
}
else{
cout<<"false";
}
return 0;
}
while(!(t&1)){ //转换为2^s*t=x-1; t为偶数;
s++;
t>>=1;
}
这是由于偶数的二进制位数为0;
∴ 将 t 的偶数耗尽变为奇数;这样才能转化成为 2 s × t = x − 1 ; \therefore 将t的偶数耗尽变为奇数;这样才能转化成为2^{s}\times t=x-1; ∴将t的偶数耗尽变为奇数;这样才能转化成为2s×t=x−1;
而为什么要这样转化呢?
就我个人是这样理解的: ( a 2 s × t ) 2 % p = 1 等价于 a 2 s × t % p = 1 (a^{2^s\times t})^{2}\%p=1等价于a^{2^s\times t}\%p=1 (a2s×t)2%p=1等价于a2s×t%p=1
为什么呢?
∵ a 2 s × t % p × a 2 s × t % p ≡ 1 × 1 ; \because a^{2^s\times t}\%p \times a^{2^s\times t}\%p\equiv 1\times 1; ∵a2s×t%p×a2s×t%p≡1×1;
∴ 成立; \therefore 成立; ∴成立;