Miller_Rabin素数测验

来源:互联网 发布:java nanotime 转秒 编辑:程序博客网 时间:2024/05/22 06:10

1.背景
数论学家利用费马小定理研究出了多种素数测试办法,Miller-Rabbin 素数测试算法是其中较快的一种。
二次探测定理:如果p是素数,且0<x<p,则方程x21(mod p)的解为1p1

2.过程
(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,则N通过随机数A的测试;
(5)让A取不同的值对N进行行多次测试(一般要求5~10次,有较高要求的话可以进行20~30次),若全部通过则判定N为素数;

3.概率计算
若N通过一次测试,则N不是素数的概率为25%;
若N通过 t 次测试,则N不是素数的概率为1/( 4 ^ t );
事实上,当 t = 5 时,N不是素数的概率已为1/128,已经大于99.99%。
在实际运用中,可首先用300~500个小素数对N进行测试,以提高测试通过的概率与算法的速度。在随机生成的素数中,选取的随机数最好让 r = 0,则可以省去步骤(3)的操作,进一步减少判定时间。

4.代码

// 18位素数:154590409516822759  // 19位素数:2305843009213693951 (梅森素数)  // 19位素数:4384957924686954497  LL prime[6] = {2, 3, 5, 233, 331};  const int time = 5;LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法        return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;      /*     LL ret = 0;     while(y) {         if(y & 1)             ret = (ret + x) % mod;         x = x * 2 % mod;         y >>= 1;     }     return ret;     */  }  LL qpow(LL a, LL n, LL mod) {      LL ret = 1;      while(n) {          if(n & 1) ret = qmul(ret, a, mod);          a = qmul(a, a, mod);          n >>= 1;      }      return ret;  }  bool Miller_Rabin(LL p) {      if(p < 2) return 0;      if(p != 2 && p % 2 == 0) return 0;      LL s = p - 1;      while(! (s & 1)) s >>= 1;      for(int i = 0; i < 5; ++i) {          if(p == prime[i]) return 1;          LL t = s, m = qpow(prime[i], s, p);          while(t != p - 1 && m != 1 && m != p - 1) {              m = qmul(m, m, p);              t <<= 1;          }          if(m != p - 1 && !(t & 1)) return 0;      }      return 1;  }  阅读全文
原创粉丝点击