大素数测试的Miller-Rabin算法

Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小。出错的概率到底是多少,存在严格的理论推导。

费尔马小定理

  • 如果 p 是质数且(a,p)=1,则有 ap11(modp)
    当然反过来不一定成立。即当 ap1%p=1 时, p 未必是质数。但是这个概率比较小。所以利用费尔马小定理来检测素数,不能保证时刻都对,只能保证出错的概率比较小。
    给定正整数n,问n是否为质数(显然只需判断正奇数),最基本的做法就是计算2n1%n是否为1。如果不是1,n肯定为合数;否则,n可能为质数。

有限域上的平方根定理

  • 如果 p 是一个奇质数且e1,则方程
    x21(modpe)

    仅有两个根 x=1 或者 x=1 ,注意到在模 p 的意义下,x=1等价于 x=p1 ±1 也称为1的平凡平方根
  • 很容易有一个推论,如果对模n存在1的非平凡平方根,n一定是合数

Miller-Rabin算法

利用上面两个定理,就可以构造出Miller-Rabin算法。考虑到n肯定是奇数(偶数的情况自己想去),则n一定可以表示为 n1=2sd ,其中 s1 d 是奇数。则

an1=a2sd=(((ad)2)...)2

也就是说, an1 相当于 ad 平方若干次。例如当 n=7 时, an1 就是 a6 ,就是 a3 的平方。当 n=13 时, an1 就是 a12 ,就是 a3 的平方的平方。
n=13 的情况进行说明(所有运算都是在模n的意义下,以下的文字说明省略了这一点),任取一个 a,1<a<13 ,计算 a3 ,再将其平方一次得到 a6 ,注意到 a3 a6 的平方根(废话),根据平方根定理的推论,如果 a6=1a3±1 ,则 n 肯定是合数。将a6平方一次得到 a12 ,同样,如果 a12=1a6±1 ,则 n 肯定是合数。最后,根据费尔马小定理,如果a121,则 n 肯定是合数。否则,n有极大概率为质数。
为了增加得到正确判断的概率,可以将 a 重复取不同的值,对每一个a验证一次 ad an1 的过程。不过,考虑到ACM的特殊性,测试数据应该不会选择伪素数特别是强伪素数。所以很多题目的AC程序实际上只来一次即可。

typedef long long llt;
//利用二进制计算a*b%mod
llt multiMod(llt a,llt b,llt mod){
    llt ret = 0LL;
    a %= mod;
    while( b ){
        if ( b & 1LL ) ret = ( ret + a ) % mod, --b;
        b >>= 1LL;
        a = ( a + a ) % mod;
    }
    return ret;
}

//计算a^b%mod
llt powerMod(llt a,llt b,llt mod){
    llt ret = 1LL;
    a %= mod;
    while( b ){
        if ( b & 1LL ) ret = multiMod(ret,a,mod),--b;
        b >>= 1LL;
        a = multiMod(a,a,mod);
    }
    return ret;
}

//Miller-Rabin测试,测试n是否为素数
bool Miller_Rabin(llt n,int repeat){
    if ( 2LL == n || 3LL == n ) return true;
    if ( !( n & 1LL ) ) return false;

    //将n分解为2^s*d
    llt d = n - 1LL;
    int s = 0;
    while( !( d & 1LL ) ) ++s, d>>=1LL;

    srand((unsigned)time(0));
    for(int i=0;i<repeat;++i){//重复repeat次
        llt a = rand() % ( n - 3 ) + 2;//取一个随机数,[2,n-1)
        llt x = powerMod(a,d,n);
        llt y = 0LL;
        for(int j=0;j<s;++j){
            y = multiMod(x,x,n);
            if ( 1LL == y && 1LL != x && n-1LL != x ) return false;
            x = y;
        }
        if ( 1LL != y ) return false;
    }
    return true;
}
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值