【数论】素数(三):素数判断法(朴素法、模6法、Rabin-Miller及改进)

我的数论-素数部分博客共5part:
基本概念、性质、猜想、定理
素数筛法(埃式筛、欧拉筛、区间筛)
素数判断法(朴素法、模6法、Rabin-Miller及改进)
数的分解(Pollard-rho)
梅森素数(Lucas_Lehmer判定法)

素数判断法

朴素判断法

  • 复杂度 O ( n ) O(\sqrt n) O(n )

  • 优化:2之后,只有奇数有可能是素数,所以先判<=2的情况,然后从i=3每次循环i+=2

for (int i = 2; i <= sqrt(n); i++)
    if (x % i == 0)
        return false;

模6判断法

bool num[5] = {0, 0, 1, 1, 0};
bool prime(int x)
{
    if (x <= 4)
        return num[x]; //4以下直接判断
    if (x % 6 != 1 && x % 6 != 5)
        return false; //6k+2, 6k+3, 6k+4分别有因数2,3,2
    for (int i = 5; i * i <= x; i += 6)
        if (x % i == 0 || x % (i + 2) == 0)
            return false; //i从5开始,以6递增,判断是不是6k+5或6k+1的因数
    return true;          //都不是,就是素数
} //以及对于大数小数k*k<x和k<sqrt(x)差不多快

Miller-Rabin判断法

由费马小定理, n 是 素 数 , p ∤ a ⇒ a n − 1 ≡ 1 ( m o d    n ) n是素数,p\nmid a \Rightarrow a^{n-1}\equiv 1(\mod n) n,paan11(modn) ,反过来不一定。但是概率小,重复操作约30次差不多能保证判断正确。复杂度 O ( log ⁡ n ) O(\log n) O(logn)

// qpow(x,n,m): 计算x^n mod m
// 记得srand
bool Miller_Rabin(int x)
{
    if (x < 2)
        return false;
    if (x == 2)
        return true;
   	if ((x & 1) == 0)
        return false;
    for (int i = 1; i <= 30; i++)
    {
        int base = rand() % (x - 1) + 1; // 随机[1,x)的数
        if (qpow(base, x - 1, x) != 1)
            return false;
    }
    return true;
}

改进Miller-Rabin判断法

二次探测定理:如果 p p p 是一个素数, 且 0 < x < p 0<x<p 0<x<p, 则方程 x 2 % p = 1 x^{2} \% p=1 x2%p=1 的解为 x = 1 x=1 x=1 x = p − 1 x=p-1 x=p1

// 通过 a^(n−1)=1(mod n)来判断 n 是不是素数,并进行二次判断
// 合数返回true
bool check(ll a, ll n, ll x, ll t)
{
    ll ret = qpow(a, x, n); // 快速幂
    ll last = ret;
    for (int i = 1; i <= t; i++)
    {
        ret = multi_add(ret, ret, n); // 乘法改加法防止溢出
        if (ret == 1 && last != 1 && last != n - 1)
            return true; //合数
        last = ret;
    }
    if (ret != 1)
        return true;
    return false;
}
bool Miller_Rabin(ll n)
{
    if (n < 2)
        return false;
    if (n == 2)
        return true;
    if ((n & 1) == 0)
        return false;
    ll x = n - 1, t = 0;
    while ((x & 1) == 0)
        x >>= 1, t++;
    for (int i = 0; i < 8; i++) // 8次差不多了
        if (check(rand() % (n - 1) + 1, n, x, t))
            return false;
    return true;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值