素数判定

素数定理\(\pi(x) = \frac{x}{\ln(x)}\),即不超过 \(x\) 的素数的个数接近于 \(\frac{x}{\ln(x)}\)

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

素数判定

朴素的质数判断

判断一个数 \(x\) 是否为素数,从素数的定义(大于1的整数中,只能被1和这个数本身整除的数)得出方法,又因为若 \(i\)\(x\) 的因数,那么 \(\frac{x}{i}\) 也一定是 \(x\) 的因数,所以枚举 \(2-\sqrt{n}\) 的有可能是 \(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\) 为素数时,有 \(a^{p-1}\equiv1\pmod p\)

那么假设:一个与 \(p\) 互质的数 \(a\) 满足 \(a^{p-1}\equiv1\pmod p\),那么这个数 \(p\) 就为素数。

但是,这个假设并不成立,有些合数也会满足这个假设,例如:\(341 = 11\times 13\)\(2^{340}\equiv1\pmod {341}\)

如果 \(a^{p-1}\equiv1\pmod p\)\(p\) 不是素数,则 \(p\) 被称为以 \(a\) 为底的 伪素数。事实上,\(341\) 是最小的伪素数基数。

所以说 费马小定理的逆定理 并不成立,即满足 \(p\)\(a\) 互质,且 \(a^{p-1}\equiv1\pmod p\) 的数,不一定是质数。

对于合数 \(p\),如果对于所有正整数 \(a\)\(a\)\(p\) 互素,都有同余方程 \(a^{n-1}\equiv1\pmod p\) 成立,则合数 \(p\)卡迈克尔数(Carmichael Number),又称为 费马伪素数

而且我们知道,若 \(p\) 为卡迈克尔数,则 \(2^p-1\) 也是一个卡迈克尔数,从而卡迈克尔数的个数是无穷的。

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(k\log^3 n)\),利用 FFT 等技术可以优化到 \(O(k\log^2n\log\log n\log\log\log n)\)

二次探测定理

\(p\) 为奇素数,那么 \(x^2\equiv1\pmod p\) 的解为 \(x\equiv1\pmod p\)\(x\equiv p-1\pmod p\)

证明:

\[x^2\equiv1\pmod p\\ x^2-1\equiv0\pmod p\\ (x-1)(x+1)\equiv0\pmod p\\ \therefore x\equiv1\pmod p\ 或\ x\equiv p-1\pmod p \]

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

我们由 费马小定理 和 二次探测定理 可以将 \(a^{p-1}\) 写作 \((a^{k})^2\) 的形式,再加一次判断 \(a^k\) 是否为 \(1\)\(p-1\)

如果 \(a^k \equiv 1\pmod p\)\(a^k\) 又可以写作 \((a^{k-1})^2\)

\(\dots\dots\)

若出现 \(a^{d*2^{r-i}}\equiv p-1\pmod p,\ i\in[0,r)\) 时,\(a^{d*2^{r-i}}\) 完全可以写作 \((a^{d*2^{r-i-1}})^2\),但是此时不存在一个奇素数 \(p\),满足 \(a^{d*2^{r-i-1}}\bmod p=1\)\(a^{d*2^{r-i-1}}\bmod p = p-1\)

那么这个数为 合数

我们尽可能的将所有的 \(2\) 提出,将 \(a^{p-1}\) 写成 \(a^{d\times 2^t},\ d\in\{2x-1\mid x\in\mathbb{N}\}\)\(d\) 为奇数)的形式。

这样进行 \(t\) 次实验,\(p\) 不是素数的可能性为 \(\frac{1}{4^t}\),老祖宗们说。

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 @ 2023-01-10 09:02  Ciaxin  阅读(150)  评论(0编辑  收藏  举报