素数测试

普通代码:

bool prime(int n)
{
	if(n==2) return true;
	if(n<2||n%2==0) return false;
	int j=3;
	while(j<=(int)sqrt(n))
	{
		if(n%j==0) return false;
		j=j+2;
	}
	return true;
}

利用费马小定理,对于给定的整数n,取一个正整数 a (1 < a < n ), 通过计算 d ≡ a n − 1 ( m o d   n ) d \equiv a^{n-1}(mod \ n) dan1(mod n)来判定整数n的素性。
  素数测试: 设a , n 为正整数
  (1)若 a n − 1 a^{n-1} an1 ≠ 1 ( m o d   n ) (mod \ n) (mod n),则n一定为合数。
  (2)若 a n − 1 ≡ 1 ( m o d   n ) a^{n-1}\equiv 1 (mod \ n) an11(mod n),则几乎可以肯定地确认n为素数,因为出错率很小。
注意:如n=1是上面就不成立, 2 34 m o d (   341 ) = 1 2^{34}mod(\ 341)=1 234mod( 341)=1,但341是合数。为了提高测试的准确性,可以随机地选取整数1 < a < n - 1。 费马小定理毕竟只是素数判定的一个必要条件

欧拉定理 :

  设a和m是整数(m>0)。记 φ ( m ) \varphi (m) φ(m)是1到m的整数中与m互素的整数的个数,则 a φ ( m ) ≡ 1 ( m o d   m ) a^{\varphi(m)}\equiv 1 (mod \ m) aφ(m)1(mod m).
证明:略。
为增加测试效率,可利用二次探测定理:如果p是一个素数,0<x<p,则方程 x 2 x^{2} x2≡1(mod p)的解为x=1或x=p-1。
一旦发现违背二次探测条件,即可得出n不是素数的结论。
Miller-Rabin 素数测试算法如下:
输入: n与a(a在2,···,n-1这些数中随机取值)
输出: true 或 false
关于讲解Miller-Rabin的博文,讲得比较有条理
对应的模板题 hdu 2138
上面那篇博客里的主要代码:

bool Miller_Rabin(int n)//利用Miller_Rabin判断n是否为素数
{
    if(n==2) return true;
    if(n<2||(n&1)==0) return false; 
    ll t,a;
	ll y;
	ll x;
    ll u=Mod_t(n-1,t);//求出n-1=u * 2^t 中的u,与t的值
	for(int i=0;i<10;i++) //这里表示用几次a的值,次数越多准确度越高,一般2次正确率就有点高了,一次的话题目数据比较水,还是可以过的
	{
		a=rand()%(n-1) + 1;
		x=Mod_u(a, u, n);//求出a^u mod n的值
		for(int j=0;j<t;j++)
		{
			y=(x*x)%n;
			if(y==1&& x!=1 && x!=n-1) 
				return false;
			x=y;
		}
		if(x!= 1 ) return false ; //经过t次后x=a^(n-1) mod n, (费马小定理)若x不为1,说明n一定不为素数
		
	}
	return true;
}

另一种表示 a n − 1 a^{n-1} an1形式,用二进制表示;
举例:
a 11 = a 1011 ( 幂 用 二 进 制 表 示 ) = a {   [   ( 0 + 1 ) ∗ 2 + 0   ] ∗ 2 + 1   } ∗ 2 + 1 = [ ( 1 ∗ a ) 2 ∗ 1 ] 2 ∗ a 2 ∗ a a^{11}=a^{1011}(幂用二进制表示)= a^{\{\ [\ (0+1)*2+0\ ]*2+1 \ \}*2+1} \\ ={[(1*a)^2*1] ^2*a}^2*a a11=a1011=a{ [ (0+1)2+0 ]2+1 }2+1=[(1a)21]2a2a
下面的代码与上面不同的就是模拟这个运算过程

int B[1000];

ll get_B(int x)
{
    int cnt=0;
    while(x)
    {
        if(x&1)
            B[cnt++]=1;
        else 
            B[cnt++]=0;
        x>>=1;
    }
    return cnt;
}

bool Rb(int n)
{
    if(n==2) return true;
    if(n<2||(n&1)==0) return false;
    ll a=2;//这里a值取2
    ll x=1;
    ll y;
    ll len=get_B(n-1);
    for(int i=0;i<10;i++)
    {
        a=rand()%(n-1)+1;
        x=1;
        for(int i=len-1;i>=0;i--)
        {
            
            y=x*x%n;
            if(y==1&& x!=1&&x!=n-1) 
                return false;
            if(B[i]==1)
                y=y*a%n;
            // cout<<B[i]<<" "<<"y , x ="<<y<<";"<<x<<endl;
            // else  
                // y=y*1%n;
            x=y;
        }
        if(x!=1)
            return false;
    }
    
    return true;
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值