• 与数论的厮守01:素数的测试——Miller Rabin


      看一个数是否为质数,我们通常会用那个O(√N)的算法来做,那个算法叫试除法。然而当这个数非常大的时候,这个高增长率的时间复杂度就不够这个数跑了。

      为了解决这个问题,我们先来看看费马小定理:若n为素数,a与n互质,则an-1Ξ1(mod n)。于是有人想过把它倒过来判断n是否为素数。首先,若a与n不互质,那么n为合数。所以只需要满足an-1Ξ1(mod n)即可,这个a干脆就让它等于2了。即判断2n-1Ξ1(mod n)是否成立。若不成立,那么n必定为合数。但成立时n就是素数吗?又有人找出了个数:2340Ξ1(mod 341),但是发现341是合数(11*31)。那我们能不能直接把a换成另一个数呢?答案是否定的。因为对于所有a,都存在an-1Ξ1(mod n),其中n为合数。于是这个方法就出错了。但是紧接着Miller Rabin测试对这个方法进行了改进。

      Miller Rabin的依据是,当n为素数时,x2Ξ1(mod n)的根有两个:x=1和x=n-1。这个根叫做平凡平方根(真的拗口)。因此,如果对于模n存在1的非平凡平方根,则n是个合数。

      那么Miller Rabin怎么改进的呢?

        ①选取多个基数a;

        ②寻找模n为1的非平凡平方根:令2t*u=n-1(t>=1,u为奇数),则an-1=a2t*u=(au)2t。先算出x=au mod n,再把x平方t次,每次模上n,这样我们就得到了一个长度为t+1的序列。我们希望这个序列以1结尾,并且若某一项为1,则前一项必须为1或n-1,否则n就是合数。

      这并不是简单地验证一下费马小定理。Miller Rabin会对一个数进行s次测试,其出错率低至2-s

      然后是代码(喜人的rand):

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    inline long long pow(long long a, long long b, long long p){
        long long ans = 1 % p;
        while(b){
            if(b & 1) ans = ans * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ans;
    }
    
    inline bool judge(long long n, long long a){
        long long u = 0, t = n - 1;
        while(t % 2 == 0) u++, t /= 2;
        long long x = pow(a, t, n);
        for(long long i = 1; i <= u; i++){
            long long next = x * x % n;
            if(next == 1 && x != 1 && x != n - 1) return true;
            x = next;
        }
        return x == 1 ? false : true;
    }
    
    inline bool rabin(long long n){
        if(n == 2) return true;
        if(n < 2 || n % 2 == 0) return false;
        for(long long i = 1; i <= 10; i++){
            long long a = rand() % (n - 2) + 2;
            if(judge(n, a)) return false;
        }
        return true;
    }
    
    int main(){
        srand(time(0));
        long long t, in;
        scanf("%lld", &t);
        while(t--){
            scanf("%lld", &in);
            printf("%s\n", rabin(in) ? "yes" : "no");
        }
        return 0;
    }

      据说重庆OI出过一道Miller Rabin的题。

      总结:

        要点1.Miller Rabin是将费马小定理倒转过来,验证n是否存在非平凡平方根.

        要点2.平凡平方根:x2Ξ1(mod n),x=1或x=n-1

        要点3.对于基数a的判断基于倍增的思想.

  • 相关阅读:
    Sql 格式化日期
    shape 格式标准
    flex 状态
    flex 特效集
    invalidateProperties
    flex for循环
    关于继承
    win32常见寄存器register
    asm寻址方式
    java jni调用 非托管 dll
  • 原文地址:https://www.cnblogs.com/akura/p/10708849.html
Copyright © 2020-2023  润新知