miller_rabin大素数随机检测模板

用到两个定理:

  1. 费马小定理

  2. 二次探测定理

如果 p p 是一个素数, 0 < x < p 0<x<p ,则方程 x 2 1 ( m o d p ) x^2≡1(mod p) 的解为 x = 1 x=1 x = p 1 x=p-1

对于待检测数 p p [ 2 , p ] [2,p] 中随机选取 s s a a 判断 a ( p 1 ) 1 m o d p a(p-1) ≡ 1(mod p) 是否成立 一旦发现不成立则可判定 p p 不是素数 为了提高正确的概率在求 a ( p 1 ) a(p-1)%p 的过程中用到定理二 令 p 1 = 2 t k p-1 = 2^t * k (其中k是奇数) 然后 a ( p 1 ) a(p-1) 就相当于 a k 2 t ak*2^t 也就是将 a k ak 平方t次 用 x [ i ] x[i] 来表示平方i次的结果 如果发现 x [ i ] = 1 x[i] = 1 x [ i 1 ] x[i-1] 既不等于 1 1 也不等于 p 1 p-1 那么就可以判定 p p 不是素数了 求 a ( p 1 ) a(p-1)%p 的过程用的是快速幂 在用快速幂的过程中还用到了一个大数相乘取模的优化 即化乘法为加法 即模拟两个数相乘的二进制运算过程 每次相加取模 如果 p p 成功通过检测则判定为素数否则为合数。

Code:

ll x[1005];
ll multi(ll a, ll b, ll p)
{ //      化乘法为加法
	ll temp = 0;
	while (b)
	{
		if (b & (ll)1)
			temp = (temp + a) % p;
		a = (a << 1) % p;
		b >>= 1;
	}
	return temp;
}
ll qpow(ll a, ll b, ll p)
{ //      快速幂
	ll temp = 1;
	while (b)
	{
		if (b & (ll)1)
			temp = multi(temp, a, p);
		b >>= 1;
		a = multi(a, a, p);
	}
	return temp;
}
int miller_rabin(ll n)
{
	if (n == 0 || n == 1)
		return 0;
	if (n == 2)
		return 1;
	int s = 10;
	ll k = n - 1;
	int t = 0;
	while (!(k & (ll)1))
	{
		t++;
		k >>= 1;
	}; //    k如果不是奇数将k转化为奇数
	while (s--)
	{
		ll a = rand() % (n - 2) + 2; //        随机取值
		x[0] = qpow(a, k, n);
		for (int i = 1; i <= t; i++)
		{
			x[i] = multi(x[i - 1], x[i - 1], n); //     记录平方i次的结果
			if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1)
				return 0;
		}
		if (x[t] != 1)
			return 0;
	}
	return 1;
}

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/107511958