素数判定

素数定理π(x)=xln(x),即不超过 x 的素数的个数接近于 xln(x)

另外,本文章参考自OI-wiki,为自用。

素数判定

朴素的质数判断

判断一个数 x 是否为素数,从素数的定义(大于1的整数中,只能被1和这个数本身整除的数)得出方法,又因为若 ix 的因数,那么 xi 也一定是 x 的因数,所以枚举 2n 的有可能是 x 的因数的数。

bool isPrime(int x)
{
	int n = sqrt(x);
	for (int i = 2; i <= n; ++ i)
	{
		if (x % i == 0) return false;
	}
	return true;
}

Fermat素性测试 与 Miller-Rabin素性测试

素性测试的定义与分类

素性测试(Primality test)是一类在 不对给定数字进行素数分解(prime factorization)的情况下,测试其是否为素数的算法。

素性测试有两种:

  1. 确定性测试:绝对确定一个数是否为素数。常见示例包括 Lucas-Lehmer 测试和椭圆曲线素性证明。

  2. 概率性测试:通常比确定性测试快很多,但有可能(尽管概率很小)错误地将 合数 识别为质数(尽管反之则不会)。因此,通过概率素性测试的数字被称为 可能素数,直到它们的素数可以被确定性地证明。而通过测试但实际上是合数的数字则被称为 伪素数。有许多特定类型的伪素数,最常见的是费马伪素数,它们是满足费马小定理的合数。概率性测试的常见示例包括 Miller–Rabin 测试。

OI-WIKI

Fermat素性测试

由 费马小定理 可知,当 p 为素数时,有 ap11(modp)

那么假设:一个与 p 互质的数 a 满足 ap11(modp),那么这个数 p 就为素数。

但是,这个假设并不成立,有些合数也会满足这个假设,例如:341=11×1323401(mod341)

如果 ap11(modp)p 不是素数,则 p 被称为以 a 为底的 伪素数。事实上,341 是最小的伪素数基数。

所以说 费马小定理的逆定理 并不成立,即满足 pa 互质,且 ap11(modp) 的数,不一定是质数。

对于合数 p,如果对于所有正整数 aap 互素,都有同余方程 an11(modp) 成立,则合数 p卡迈克尔数(Carmichael Number),又称为 费马伪素数

而且我们知道,若 p 为卡迈克尔数,则 2p1 也是一个卡迈克尔数,从而卡迈克尔数的个数是无穷的。

int Prime[7] = {2,3,5,7,11,13};
bool Farmet_test(int n)
{
	for (int i = 0; i < 6; ++ i) 
		if (Prime[i] == n) return true;
	
	for (int i = 0; i < 6; ++ i)
		if (Pow(Prime[i],n-1,n) != 1)
			// a^n \equiv a (mod p)	
			return false;
	
	return true;
}

Miller-Rabin素性测试

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

对数 n 进行 k 轮测试的时间复杂度是 O(klog3n),利用 FFT 等技术可以优化到 O(klog2nloglognlogloglogn)

二次探测定理

p 为奇素数,那么 x21(modp) 的解为 x1(modp)xp1(modp)

证明:

x21(modp)x210(modp)(x1)(x+1)0(modp)x1(modp)  xp1(modp)

根据卡迈克尔数的性质,可知其一定不是 pe

我们由 费马小定理 和 二次探测定理 可以将 ap1 写作 (ak)2 的形式,再加一次判断 ak 是否为 1p1

如果 ak1(modp)ak 又可以写作 (ak1)2

若出现 ad2rip1(modp), i[0,r) 时,ad2ri 完全可以写作 (ad2ri1)2,但是此时不存在一个奇素数 p,满足 ad2ri1modp=1ad2ri1modp=p1

那么这个数为 合数

我们尽可能的将所有的 2 提出,将 ap1 写成 ad×2t, d{2x1xN}d 为奇数)的形式。

这样进行 t 次实验,p 不是素数的可能性为 14t,老祖宗们说。

int Prime[7] = {2,3,5,7,11,13};
int TwiceDetect(int a, int k, int p)
{
	int t = 0, x, y;
	while (k&1) t ++, k >>= 1;
	x = y = Pow(a, k, p);
	for (int i = 0; i < t; ++ i)
	{
		y = Mul(x, x, p);
		if (y == 1 && x != 1 && x != p - 1)
			return -1;
		x = y;
	}
	return y;
}
bool Miller_Rabin(int n)
{
	for (int i = 0; i < 6; ++ i) 
		if (Prime[i] == n) return true;
	
	for (int i = 0; i < 6; ++ i)
		if (TwiceDetect(Prime[i],n-1,n) != 1)
			return false;
	
	return true;
}
posted @   Ciaxin  阅读(188)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示