Miller-Rabin算法

前置知识

  • 费马小定理
    \(p\)为素数, \(a\)为正整数,且\(gcd(a,p) = 1\),则\(a^{p-1}\equiv 1(mod p)\).

    • 证明:首先证明三个小性质
      因为\(p\)为素数,所以\(gcd(i,p)=1,1\le i \le p-1,i为整数\), 则可推出:

      \[gcd((p-1)!,p)=1 \]

      又因为\(gcd(a,p)=1\), 所以 $$gcd(i \ast a,p)=1,1\le i\le p-1$$
      \(a = b*q+r,1\le r< p\),则\(gcd(i*r,p)=1\).
      假设存在两个不同的\(i\),\(c和d\),满足\(c*r\equiv d*r(\mod p) (c< d)\)
      那么\((d-c)*r\equiv 0(\mod p)\) ,即 \(p|(d-c)*r\).
      又因为\(1\le d-c < p\), 这与\(gcd(i*r,p)=1\)矛盾.
      所以\(i*r,1\le i\le p-1\)没有任何两个不同的i使得这两个数模\(p\)同余。
      所以 $$ i\ast a不存在两个不同的i使得这两个数能在模p的意义下同余$$

      接下来我们就可以证明费马小定理了。
      我们从上面的推断可以得出,\(\prod_{i=1}^{p-1} i\ast a \equiv \prod_{i=1}^{p-1} i (\mod p)\)

      即 $$ (p-1)! \ast a^{p-1} \equiv (p-1)! (\mod p) $$
      即 $$ a^{p-1} \equiv 1 (\mod p)$$

  • 二次探测定理
    \(p\)为奇素数且\(x^2 \equiv 1(\mod p)\), 则\(x\equiv 1(\mod p)\)\(x \equiv p-1(\mod p)\).
    证明:\(x^2 \equiv 1(\mod p)\)
    \((x-1)(x+1) \equiv 0(\mod p)\)
    \(x_1 = q_1*p+1,x_2 = q_2*p-1,q_1,q_2为整数\), 显然符合\(x\equiv 1(\mod p)\)\(x \equiv p-1(\mod p)\)

    对于要验证的数\(p\), 我们可以选择一些正整数\(a\),使用费马小定理来测试,若有一个\(a\)不符合那\(p\)就不是素数.
    但是这只是必要非充分条件,实际上存在一种强伪素数\(p\),符合:
    $$ \forall a<p, a^{p-1}\equiv 1( \mod p) $$
    啊 这。 所以不能用费马小定理直接判断素数。
    所以我们需要第二次探测
    首先对p使用费马小定理进行判断,若不符合直接判合数。
    \(2|p-1\), 则我们需要判断是否符合\((x^{{p-1}/2})^2\)\(p\)为1或\(p-1\).
    \((x^{{(p-1)}/2})^2\)\(p\)值既不是1也不是\(p-1\),则\(p\)是合数.返回false。
    若是1,则继续递归。\(k=(p-1) \rightarrow k>>=1 \rightarrow ... ;\) 直到k为奇数。返回true.
    若是\(p-1\),则返回true。
    通过多取几个x来提高测试的准确率。一般来说取2~23中的所有素数就可满足要求。

    class MillerRabin {
    public:
      Con int P[10] = { 2,3,5,7,11,13,19,61,2333,24251 };
      bool check(int x, int p) {
      	if (!(x%p) || Qpow(p%x, x - 1, x) != 1) { return false; }
      	ll k = x - 1, t;
      	while (!(k & 1)) {
      		t = Qpow(p%x, k >>= 1, x); 
      		if (t ^ 1 && t ^ (x - 1)) return false;
      		if (!(t ^ (x - 1))) return true;
      	}
      	return true;
      }
      bool IsPrime(int x) {
      	if (x < 2) return false;
      	for (Reg int i = 0; i <  10; ++i) {
      		if (!(x^P[i])) return true;
      		if (!check(x, P[i])) return false;
      	}
      	return true;
      }
    }MR;
    
posted @ 2020-06-24 18:00  Cha2a_zzZ  阅读(135)  评论(0)    收藏  举报