素数测试(Miller-Rabin测试)

来源:互联网 发布:宠物商城源码 编辑:程序博客网 时间:2024/06/05 03:46

思想参照:[http://www.matrix67.com/blog/archives/234
1.素数的个数无限多且不存在最大的素数
证明反证法:假设存在最大的素数P,则我们可以得到一个新的数为所有的素数向乘加一,即2*3*5*7*……*P+1, 显然它不能被任一素数整除(所有的素数除它都余一),这说明我们找到了一个更大的素数。
2.存在任意长的一段连续数,所有数都是合数(相邻的素数之间的间隔任意大)
证明:当0小于a小于n时n!+a能被a整除。长度为n-1的序列 n!+2,n!+3,n!+4,…,n!+n中,所有的数都是合数。这个结论对所有大于一的整数n都成立,而n可取到任意大。
3.所有大于二的素数都可以唯一的表示成两个平方数之差
证明:大于二的素数都是奇数。假设是这个数值2n+1。由于(n+1)^2 = n^2+2n+1,(n+1)^2和n^2就是我们要找的两个平方数。唯一性:若P能表示成a^2-b^2,则P=a^2-b^2=(a+b)(a-b),由于P、是素数则只能是a-b=1和a+b=P,故解是唯一的。
4.当N为大于2的整数时, 2^n-1和2^n+1两个数中如果其中一个是素数那么另一个肯定是合数
证明:2^n不能被三整除,倘若他被三除余一那么2^n-1就能被三整除,如果他被三除余二,那么2^n+1就能被三整除,总之,2^n+1 和2^n-1肯定有一个能被三整除。
5.如果p是素数,a是小于p的正整数,则a^(p-1)mod p = 1
首 先我们证明这样一个结论:如果p是一个素数的话,那么对任意一个小于p的正整数a,a, 2a, 3a, …, (p-1)a除以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)
Miller-rabin算法:
是一个用来快速判断一个正整数是否为素数的算法。

它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) %p恒等于1。也就是对于所有小于p的正整数a来说都应该符合a^(p-1) % p恒等于1,因为质数p的欧拉数=p-1。

那么根据逆否命题,对于一个p,我们只要举出一个a(a小于p)不符合这个恒等式,则可判定p不是素数。

Miller-rabin算法就是多次用不同的a来尝试p是否为素数。
但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。

它是根据一个定理:如果p是一个素数,那么对于x(0

 #include <iostream> using namespace std ; #define rd(x) (rand()%(x)) typedef unsigned long long ll; ll pow_mod(ll a,ll b,ll r) {     ll ans=1,buff=a;     while(b)     {         if(b&1)             ans=(ans*buff)%r;         buff=(buff*buff)%r;         b>>=1;     }     return ans; } bool test(ll n,ll a,ll d) {     if(n==2) return true;     if(n==a) return false;     if(!(n&1)) return false;     while(!(d&1)) d>>=1;     ll t = pow_mod(a,d,n);     while(d!=n-1&&t!=n-1&&t!=1){        t = t*t%n;//下面介绍防止溢出的办法,对应数据量为10^18次方;         d<<=1;     }     return t == n-1||(d&1)==1;//要么t能变成n-1,要么一开始t就等于1 } bool isprime(ll n){    int a[] = {2,3,5,7};//或者自己生成[2,N-1]以内的随机数rand()%(n-2)+2     for(int i = 0; i <= 3; ++i){         if(n==a[i]) return true;         if(!test(n,a[i],n-1)) return false;     }     return true; } int main() {     int t,ans=0;     ll N;       for(cin >> t;t;t--){        cin >> N;         cout << ((isprime(N))?"Yes":"No") <<endl;  }}

为了防止溢出上述的

   ll pow_mod(ll a,ll b,ll r)    {     ll ans=1,buff=a;     while(b)     {         if(b&1)             ans=(ans*buff)%r;         buff=(buff*buff)%r;         b>>=1;     }     return ans;     }

可以改成:

long long mod_mul(long long a, long long b, long long n) {    long long res = 0;    while (b) {        if(b & 1)            res = (res + a) % n;        a = (a + a) % n;        b >>= 1;    }    return res;}long long pow_mod(long long a, long long b, long long n) {    long long res = 1;    while(b) {        if(b & 1)            res = mod_mul(res, a, n);        a = mod_mul(a, a, n);        b >>= 1;    }    return res;}

但是复杂度也相应的提高了。

0 0