米勒拉宾素性检验(代码模板)

本文介绍了一种高效的快速幂算法实现及应用该算法进行素数判断的方法,并给出了线性筛法来寻找一定范围内的所有素数。

typedef long long ll;
ll qpow(ll a, ll n, ll p) // 快速幂
{
    ll ans = 1;
    while (n)
    {
        if (n & 1)
            ans = (__int128)ans * a % p; // 注意!中间结果可能溢出,需要使用__int128过渡
        a = (__int128)a * a % p;
        n >>= 1;
    }
    return ans;
}
bool is_prime(ll x)
{
    if (x < 3) // 特判1,2
        return x == 2;
    if (x % 2 == 0) // 特判偶数
        return false;
    ll A[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}, d = x - 1, r = 0;
    while (d % 2 == 0) // 算出d, r 
        d /= 2, ++r;
    for (auto a : A)
    {
        ll v = qpow(a, d, x); // a^d
        // 如果a^d≡0,说明是a是x的倍数;如果a^d≡1或-1,说明这串数接下来一定都是1,不用继续计算
        if (v <= 1 || v == x - 1) 
            continue;
        for (int i = 0; i < r; ++i)
        {
            v = (__int128)v * v % x; // 同样使用__int128过渡
            if (v == x - 1 && i != r - 1) // 得到-1,说明接下来都是1,可以退出了
            {
                v = 1;
                break;
            }
            // 在中途而非开头得到1,却没有经过-1,说明存在其他数字y≠-1满足y^2≡1,则x一定不是奇素数
            if (v == 1)  
                return false;
        }
        if (v != 1) // 查看是不是以1结尾
            return false;
    }
    return true;
}

每次判断素数只需要O(klogn)

线性筛:在O(N)范围内筛出所有素数


void table()
{
    memset(num,-1,sizeof(num));
    for(int i=2;i<N;i++)
    {
        if(num[i]==-1) prim[pn++]=i;
        for(int j=0;j<pn&&i*prim[j]<N;j++)
        {
            num[prim[j]*i]=prim[j];
            if(i%prim[j]==0) break;
        }
    }
}

### 米勒-拉宾素性检验的定义和原理 米勒-拉宾素性检验是一种概率性算法,用于判断一个给定的整数是否是素数。它基于费马小定理和二次剩余的数学理论,能够高效地处理大数,具有较高的准确性[^1]。 该算法的核心思想是通过随机选择一些基数(称为“测试底数”),并利用这些基数对目标数进行一系列的测试。如果目标数通过了所有测试,则可以认为它很可能是素数;如果在某次测试中失败,则可以确定它不是素数。由于算法是概率性的,因此需要多次测试以提高判断的准确性[^2]。 #### 基本原理 1. **费马小定理**:对于一个素数 $ p $ 和任意整数 $ a $,满足 $ 1 < a < p $,有 $ a^{p-1} \equiv 1 \mod p $。 2. **二次剩余性质**:如果 $ p $ 是一个奇素数,并且 $ a^{p-1} \equiv 1 \mod p $,那么 $ a^{(p-1)/2} \equiv \pm 1 \mod p $。 米勒-拉宾算法将 $ n-1 $ 分解为 $ d \cdot 2^s $ 的形式,然后对选定的底数 $ a $ 进行测试。如果 $ a^d \equiv 1 \mod n $ 或者存在某个 $ r $ 满足 $ a^{d \cdot 2^r} \equiv -1 \mod n $,则 $ n $ 可能是素数。否则,$ n $ 是合数。 #### 算法步骤 1. 将 $ n-1 $ 分解为 $ d \cdot 2^s $。 2. 随机选择一个整数 $ a $,使得 $ 2 \leq a < n $。 3. 计算 $ a^d \mod n $。 4. 如果结果为1或 $ n-1 $,则继续下一轮测试。 5. 否则,重复计算 $ a^{d \cdot 2^r} \mod n $,直到 $ r = s-1 $。 6. 如果所有计算结果都不等于 $ n-1 $,则 $ n $ 是合数;否则,继续下一轮测试。 #### 代码实现 以下是一个基于上述原理的 Python 实现: ```python import random def bin_exp_mod(a, b, n): result = 1 a = a % n while b > 0: if b % 2 == 1: result = (result * a) % n a = (a * a) % n b = b // 2 return result def is_prime(n, k=5): if n < 2: return False if n in (2, 3): return True if n % 2 == 0: return False d = n - 1 s = 0 while d % 2 == 0: d //= 2 s += 1 for _ in range(k): a = random.randint(2, n - 2) x = bin_exp_mod(a, d, n) if x == 1 or x == n - 1: continue for __ in range(s - 1): x = bin_exp_mod(x, 2, n) if x == n - 1: break else: return False return True if __name__ == "__main__": n = int(input("请输入一个整数:")) if is_prime(n): print(f"{n} 可能是素数") else: print(f"{n} 不是素数") ``` #### 应用场景 米勒-拉宾素性检验广泛应用于密码学、网络安全和大数处理领域,尤其是在生成大素数时。由于其高效性和较高的准确性,许多现代加密算法(如 RSA)都依赖于该算法来验证大数的素性。 #### 注意事项 - 算法的准确性取决于选择的测试底数数量 $ k $。增加 $ k $ 可以提高判断的准确性,但也会增加计算时间。 - 对于某些特定的合数(称为“伪素数”),某些底数可能会错误地判断其为素数。因此,需要多次测试以减少这种错误的概率。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值