素性测试算法 Miller-Rabin

本文介绍了费马小定理和二次探测定理,并详细解析了Miller-Rabin素性测试算法,通过实例演示如何判断一个数是否为质数,同时提供了算法的C++实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

费马小定理

ppp 为质数, aaa 为任意自然数, 则
ap≡a(modp)  ⟺  ap−1≡1(modp)a^{p} \equiv a\pmod p \iff a^{p-1} \equiv 1 \pmod papa(modp)ap11(modp)

证明略。

二次探测定理

ppp 为质数,则 x2≡1(modp)x^2 \equiv 1 \pmod px21(modp) 的解为 x1=1,x2=p−1x_1 = 1, x_2 = p-1x1=1,x2=p1

略证:

x2≡1(modp)x2−1≡0(modp)(x+1)(x−1)≡0(modp)p∣(x−1)×(x+1) x^2 \equiv 1 \pmod p \\ x^2 - 1 \equiv 0 \pmod p \\ (x +1)(x-1) \equiv 0 \pmod p \\ p | (x - 1)\times (x+1) x21(modp)x210(modp)(x+1)(x1)0(modp)p(x1)×(x+1)

Miller-Rabin

我们都知道,如果 ppp 为质数那么有 ap−1≡1(modp)a^{p-1} \equiv 1 \pmod pap11(modp)。但反命题不一定成立,比如令 a=2a=2a=2,那么有 2340 mod 341=12^{340} \bmod 341 = 12340mod341=1,但是 341=11×31341 = 11 \times 31341=11×31。那么再试一下 a=3a=3a=3,发现 3340 mod 341=563^{340} \bmod 341 = 563340mod341=56,所以 341341341 不是质数。

那么能不能多选几个质数去做检测呢?但是有一些合数,叫做 Carmichael 数,比如 561=3×11×17561 = 3\times11 \times17561=3×11×17,所有合法的底数都无法将它检测出来。

那么接下来就是正题了——Miller-Rabin 素性测试算法。先拿 341341341 举个栗子,看看这个算法在干什么。

先说明一个显而易见的命题,对于任意质数 ppp2∣p−12| p -12p1。那么看看 Miller-Rabin 干了什么。

因为 2340≡1(mod341)2^{340} \equiv 1 \pmod {341}23401(mod341),那么有21702≡1(mod341)2^{{170}^2} \equiv 1 \pmod {341}217021(mod341),若将 21702^{170}2170 看作一个整体,根据二次探测定理,如果 341341341 是一个质数,那么 2170 mod 341=1/3402^{170} \bmod 341 = 1 / 3402170mod341=1/340。可以发现 2170 mod 3412^{170} \bmod 3412170mod341111。那么还适用二次探测定理,再看看 285 mod 3412^{85} \bmod 341285mod341,发现它为 323232,所以 341341341 不是质数。

int ksm(int a, int k, int p) {
  	int res = 1;
  	while (k) {
    	if (k & 1) res = res * a % p;
    	a = a * a % p;
    	k >>= 1;
  	}
  	return res % p;
}
int MR(int x, int p) {
	if (ksm(x, p-1, p) != 1) return 0;
	int k = p - 1;
	while (!k & 1) {
		k >>= 1;
		int t = ksm(x, k, p);
		if (t == p - 1) return 1;
		if (t != 1) return 0;
	}
	return 1;
}
int RP(int p) {
	if (p == 2 || p == 3 || p == 5 || p == 7 || p == 11) return 1;
	if (p == 0) return 0;
	return MR(2, p) && MR(3, p) && MR(5, p) && MR(7, p) && MR(11, p);
}
int main() {
	while (1) {
		int x = read();
		printf("%d\n", RP(x));
	}
	return 0;
}

可以发现 Miller-Rabin 的时间按复杂度为 O(klog⁡2n)O(k \log^2 n)O(klog2n),其中 kkk 为测试次数,通常五次就够了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值