首页 > 其他分享 >Miller–Rabin 素性测试

Miller–Rabin 素性测试

时间:2024-04-14 09:00:10浏览次数:23  
标签:log Miller 测试 素性 Rabin equiv

Miller–Rabin 素性测试(Miller–Rabin primality test)是进阶的素数判定方法。它是由 Miller 和 Rabin 二人根据费马小定理的逆定理(费马测试)优化得到的。因为和许多类似算法一样,它是使用伪素数的概率性测试,我们必须使用慢得多的确定性算法来保证素性。然而,实际上没有已知的数字通过了高级概率性测试(例如 Miller–Rabin)但实际上却是复合的。因此我们可以放心使用。

在不考虑乘法的复杂度时,对数 \(n\) 进行 \(k\) 轮测试的时间复杂度是 \(O(k \log n)\)。Miller-Rabbin 素性测试常用于对高精度数进行测试,此时时间复杂度是 \(O(k \log^3n)\),利用 FFT 等技术可以优化到 \(O(k \log^2n \log \log n \log \log \log n)\)

二次探测定理

如果 \(p\) 是奇素数,则 \(x^2 \equiv 1 \pmod p\) 的解为 \(x \equiv 1 \pmod p\) 或者 \(x \equiv p - 1 \pmod p\)。

要证明该定理,只需将上面的方程移项,再使用平方差公式,得到 \((x+1)(x-1) \equiv 0 \bmod p\),即可得出上面的结论。

实现

根据卡迈克尔数的性质,可知其一定不是 \(p^e\)。

不妨将费马小定理和二次探测定理结合起来使用:

将 \(a^{n-1} \equiv 1 \pmod n\) 中的指数 \(n−1\) 分解为 \(n−1=u \times 2^t\),在每轮测试中对随机出来的 \(a\) 先求出 \(v = a^{u} \bmod n\),之后对这个值执行最多 \(t\) 次平方操作,若发现非平凡平方根时即可判断出其不是素数,否则再使用 Fermat 素性测试判断。

还有一些实现上的小细节:

  • 对于一轮测试,如果某一时刻 \(a^{u \times 2^s} \equiv n-1 \pmod n\),则之后的平方操作全都会得到 \(1\),则可以直接通过本轮测试。
  • 如果找出了一个非平凡平方根 \(a^{u \times 2^s} \not\equiv n-1 \pmod n\),则之后的平方操作全都会得到 \(1\)。可以选择直接返回 false,也可以放到 \(t\) 次平方操作后再返回 false

这样得到了较正确的 Miller Rabin。

代码:

bool MillerRabin(int n) {
    if (n == 2) return true;
    if (n <= 1 || n % 2 == 0) return false;
    ll base[7] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
    ll u = n - 1, k = 0;
    while (u % 2 == 0) u /= 2, k++;
    for (auto x : base) {
        if (x % n == 0) continue;
        ll v = powmod(x, u, n);
        if (v == 1 || v == n - 1) continue;
        for (int j = 1; j <= k; j++) {
            ll last = v;
            v = (__int128)v * v % n;
            if (v == 1) {
                if (last != n - 1) return false;
                break;
            }
        }
        if (v != 1) return false;
    }
    return true;
}

另外,假设 广义 Riemann 猜想(generalized Riemann hypothesis, GRH)成立,则对数 \(n\) 最多只需要测试 \([2, \min\{n-2, \lfloor 2\ln^2 n \rfloor\}]\) 中的全部整数即可 确定 数 \(n\) 的素性。

而在 OI 范围内,通常都是对 \([1, 2^{64})\) 范围内的数进行素性检验。对于 \([1, 2^{32})\) 范围内的数,选取 \(\{2, 7, 61\}\) 三个数作为基底进行 Miller–Rabin 素性检验就可以确定素性;对于 \([1, 2^{64})\) 范围内的数,选取 \(\{2, 325, 9375, 28178, 450775, 9780504, 1795265022\}\) 七个数作为基底进行 Miller–Rabin 素性检验就可以确定素性。

也可以选取 \(\{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37\}\)(即前 \(12\) 个素数)检验 \([1, 2^{64})\) 范围内的素数。

注意如果要使用上面的数列中的数 \(a\) 作为基底判断 \(n\) 的素性:

  • 所有的数都要取一遍,不能只选小于 \(n\) 的;
  • 把 \(a\) 换成 \(a \bmod n\);
  • 如果 \(a \equiv 0 \pmod n\),则直接通过该轮测试。

模板题:loj143

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9 + 7;
const int N = 200005;
const int INF = 0x3f3f3f3f;
ll powmod(__int128 x, ll y, ll mod) {
    ll res = 1;
    while (y) {
        if (y & 1) res = res * x % mod;
        y >>= 1;
        x = x * x % mod;
    }
    return res;
}
bool MillerRabin(ll n) {
    if (n == 2) return true;
    if (n <= 1 || n % 2 == 0) return false;
    ll base[7] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
    ll u = n - 1, k = 0;
    while (u % 2 == 0) u /= 2, k++;
    for (auto x : base) {
        if (x % n == 0) continue;
        ll v = powmod(x, u, n);
        if (v == 1 || v == n - 1) continue;
        for (int j = 1; j <= k; j++) {
            ll last = v;
            v = (__int128)v * v % n;
            if (v == 1) {
                if (last != n - 1) return false;
                break;
            }
        }
        if (v != 1) return false;
    }
    return true;
}
int main() {
    ll n;
    while (scanf("%lld", &n) != EOF) {
        if (Mr(n))
            printf("Y\n");
        else
            printf("N\n");
    }
    return 0;
}

标签:log,Miller,测试,素性,Rabin,equiv
From: https://www.cnblogs.com/jxy2012/p/18133743

相关文章

  • 蓝桥杯算法基础(29)字符串匹配(RabinKarp)(KMP)(前缀树,字典树,trie,后缀数组,高度数组)
     RabinKarpRabinKarpS:ABABABm个P:ABBn个1.朴素算法,挨个匹配2.哈希法hash->滚动哈希c0*31^2+c1*31^1+c2类似于进制的求法求hash值(c0*31+c1)*31+c2hash(p)=o(n)hash(s)=o(m*n)privatestaticvoidmatch(Stringp,Strings){longhash_p=hash(p);......
  • 费马素性检验(python实现)
    费马素性检验:给定奇整数n>=3和安全参数t1、随机选取整数b,(b,n)=1,2<=b<=n-22、计算r=b的n-1次方(modn)3、如果r!=1,则n是合数4、上述过程重复t次以下是python代码,如发现错误,请跟博主联系importrandom#n>=3且n是奇整数n=int(input())t=int(input())defgcd(a,b):wh......
  • 数论——Fermat素性检验、Miller-Rabin素性检验
    数论——Fermat素性检验、Miller-Rabin素性检验试除法与素性测试试除法:所有的试除法,无论是\(\mathcalO(n)\)的还是\(\mathcalO(\sqrtn)\)的,其本质都相同:即找\(n\)可能存在的因子\(k\),判断\(k\midn\)。素性测试:旨在不用分解因数的方式,判断一个数是否为质数;素性......
  • Miller Rabin素数判定
    MillerRabin素数判定llqmul(lla,llb,llmod)//快速乘{llc=(ld)a/mod*b;llres=(ull)a*b-(ull)c*mod;return(res+mod)%mod;}llqpow(lla,lln,llmod)//快速幂{llres=1;while(n){if(n&1)res=qmul(res,a,mod);......
  • [macos]karabiner-elements设置
    通过一些映射来方便我的mac操作      20200423:  https://github.com/eret9616/my-karabiner-config ......
  • P4397聪明的燕姿 题解 & Miller~Rabin 质数判定
    涉及质数的时间复杂度都是玄学的。——题记传送门由整数唯一分解定理:\(\coprod\limits_{i=1}^{k}p_i^{c_i}\)有该正整数的正约数为:\(\coprod\limits_{i=1}^k(\sum\limits_{j=0}^{c_i}p_i^j)\)即我们要求有多少个数满足\(\coprod\limits_{i=1}^k(\sum\limits_{j=0}^{c_i}p_i^......
  • Miller-Rabin算法
    原文链接:https://blog.csdn.net/qq_43227036/article/details/100336234OK,前面已经讲了很多判断素数的方法,在判断一个数是否为素数时我们可以采用试除法,但如要求1-n的范围那么时间复杂度很高,所以有了线性的筛法求素数。但如果为了判断一个大数是否为素数却要消耗很大的空间,这显......
  • 素性检验问题和模平方根问题
    因为这两种算法都是随机化算法且都与数论问题有关,而且还有许多微妙的联系,因此放在一起整理.素性检验问题(主要参考资料:【朝夕的ACM笔记】数论-MillerRabin素数判定-知乎(zhihu.com))(不完善的)Fermat素性检验:由Fermat小定理可知,对于素数$p$,所有$a\in[1,p-1]$,$a^{p-......
  • Miller Rabin与Pollard Rho
    先写一下MillerRabin(具体介绍见老板的PPT)对于该算法,先要知道二次探测定理。这个比较简单,看PPT即可但还是要解释一个东西。PPT里面在举例子的时候,用\(2^{340}\)为例子,并说明\(2^{170}\)%\(341\)的结果只能是1或者340,这与二次探测定理的\(x\)要小于\(p\)不矛盾,因为PPT说的是\(2^{......
  • 素性测试--Miller-Rabin算法
    引子今天(23/8/16),老师问了一个有趣的问题:出道题给大家,111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111是不是素数......