Miller_Rabin素数检测算法

文章目录

  • Miller_Rabin素数检测算法
    • 费马小定理与二次探测定理证明
      • 算法的思路
        • 备注
          • 实现的代码:
            • 实现的代码的说明:

Miller_Rabin素数检测算法

Miller_Rabin素数检测方法,又称为强伪素数检测方法;
它是以:

  1. 费马小定理:如果p是一个质数,而整数a不是p的倍数,则有 a p − 1 ≡ 1 ( m o d    p ) a^{p-1}\equiv 1(mod \: \, p) ap11(modp)
    当然不过反过来不一定成立,也就是说,如果 a , p 互质,且 a p − 1 ≡ 1 ( m o d p ) a^{p-1}≡1(mod p) ap11(modp),不能推出 p 是质数,比如 Carmichael 数(这个就自行百度吧)。
    解释 a p − 1 ≡ 1 ( m o d    p ) a^{p-1}\equiv 1(mod \: \, p) ap11(modp);意思是: ( a p − 1 − 1 ) (a^{p-1}-1) (ap11)%p ≡ \equiv 0%p;
  2. 二次探测:如果 p 是一个素数,0 < x < p, 则方程 x p − 1 ≡ 1 ( m o d p ) x^{p-1}≡1(mod p) xp11(modp)的解为 x = 1 或 x = p - 1;
  3. 快速幂取模:利用二进制来对于大数进行求幂运算;
    比如要求 a k a^k ak,一般的方法是利用循环求解,所以时间复杂度是O(n),而且当他的个数太大时,long long都无法装得下,这是急需一种方法来实现大数的运算;
    a k = a k 的二进制转化为十进制的公式 a^k= a^{k的二进制转化为十进制的公式} ak=ak的二进制转化为十进制的公式;假设k= 1 ∗ 2 0 + 0 ∗ 2 1 . . . . . . 2 m ( m 未知 ) ; 1*2^{0}+0*2^{1}......2^{m}(m未知); 120+021......2m(m未知)
    ∵ \because ( a ∗ b ∗ c ) % p (a*b*c)\%p (abc)%p= ( a % p ) ∗ ( b % p ) ∗ ( c % p ) (a\%p)*(b\%p)*(c\%p) (a%p)(b%p)(c%p);
    ∴ \therefore a k = a 1 ∗ 2 0 + 0 ∗ 2 1 . . . . . . 2 m a^k=a^{1*2^{0}+0*2^{1}......2^{m}} ak=a120+021......2m 见他拆分开来可得。 a k = a 1 ∗ a 0 ∗ . . . . . . . a m ; a^k=a^{1}*a^0*.......a^{m}; ak=a1a0.......am
    最终 可以将 a k 拆分成一个个比较小的数来分别进行模运算; 可以将a^k拆分成一个个比较小的数来分别进行模运算; 可以将ak拆分成一个个比较小的数来分别进行模运算;
  4. 快速积取模:利用二进制进行大数求积运算;
    ∵ \because ( a ∗ b ∗ c ) % p (a*b*c)\%p (abc)%p = ( a % p ) ∗ ( b % p ) ∗ ( c % p ) ; (a\%p)*(b\%p)*(c\%p); (a%p)(b%p)(c%p);
    与快速幂取模相似;举个例子: 20 × 14 求它的值: 20\times14求它的值: 20×14求它的值:
    20 × 14 = 20 × ( 0 × 2 0 + 2 1 + 2 2 + 2 3 ) 20\times14=20\times(0\times2^0+2^1+2^2+2^3) 20×14=20×(0×20+21+22+23)
    ∴ \therefore 20 × 14 转换成更小的数进行取模运算 20\times14转换成更小的数进行取模运算 20×14转换成更小的数进行取模运算

费马小定理与二次探测定理证明

1、费马小定理证明: 如果p是一个质数,而整数a不是p的倍数,则有 a p − 1 ≡ 1 ( m o d    p ) a^{p-1}\equiv 1(mod \: \, p) ap11(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×4p的模是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×(p1))1%p......(p1)%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×(p1))%p(1×......(p1))%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; ap1×(1......(p1))%p(1×......(p1))%p; 消去 ( 1...... ( p − 1 ) (1......(p-1) (1......(p1);
最终: a p − 1 ≡ 1 ( m o d    p ) 成立; a^{p-1}\equiv 1(mod\:\,p)成立; ap11(modp)成立;
2、二次探测证明: 如果 p 是一个素数,0 < x < p, 则方程 x 2 ≡ 1 ( m o d    p ) x^{2}≡1(mod\:\,p) x21(modp)的解为 x = 1 或 x = p - 1;
易知: x 2 − 1 = 0 ( m o d    p ) x^2-1=0(mod\:\,p) x21=0(modp)
∴ ( x + 1 ) ( x − 1 ) = 0 ( m o d    p ) ; \therefore (x+1)(x-1)=0(mod\:\,p); (x+1)(x1)=0(modp);
很显然1与(p-1)成立;
∵ p 是质数; \because p是质数; p是质数;
∴ 仅有两个成立; \therefore 仅有两个成立; 仅有两个成立;

算法的思路

  1. 先将偶数与1,2先判断好;
  2. 再找两个数s,t。将 2 s × t = x − 1 ; 2^{s}\times t=x-1; 2s×t=x1;
  3. 取较小的质数a(a<30);求出 a t ; a^t; at;
  4. a t a^t at进行s次二次探测;
  5. 如果最后结果符合 ( a p − 1 − 1 ) % p = 0 (a^{p-1}-1)\%p=0 (ap11)%p=0。则成立,否则不成立;
  6. 去多次a来对Miller_Rabin测素,验证算法的正确性;

备注

(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=x1;
而为什么要这样转化呢?
就我个人是这样理解的: ( 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%p1×1;
∴ 成立; \therefore 成立; 成立;

你可能感兴趣的:(基础算法,算法,c++,开发语言)