加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-14 04:33:33 所属栏目:大数据 来源:网络整理
导读:看一个数是否为质数,我们通常会用那个O(√N)的算法来做,那个算法叫试除法。然而当这个数非常大的时候,这个高增长率的时间复杂度就不够这个数跑了。 为了解决这个问题,我们先来看看费马小定理:若n为素数,a与n互质,则a n-1 Ξ1(mod n)。于是有人想过把

  看一个数是否为质数,我们通常会用那个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*33)。那我们能不能直接把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("%sn",rabin(in) ? "yes" : "no");
    }
    return 0;
}

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读