1.Miller-rabin 算法(基于费马小定理/Fermat 定理)
作用:通过概率的方式判断素数。有误判概率,通过多次判断可以使误判概率控制在很小范围。
理论基础:如果n是一个奇素数, 将n-1表示成2^s*r的形式(r是奇 数),a 是和n互素的任何整数, 那么a^r≡1(mod n) 或者对某个j(0≤j ≤s -1, j∈Z) 等式 a^(2^j*r) ≡-1(mod n)成立。 这个理论是通过一个事实经由Fermat定理推导而来: n是一个奇素数,则方程x2 ≡ 1 mod n只有±1两个解。
代码实现:
- #define LL __int64
- const LL NUM=3;//判断次数,每次误判概率1/2.NUM次误判概率为2^(-num)
- LL check(LL a,LL n,LL x,LL t)//合数返回true
- {
- LL ret=pow_mod(a,x,n);//a^x%n
- LL last=ret;
- for(LL i=1;i<=t;i++)
- {
- ret=mult_mod(ret,ret,0); background-color:inherit">//ret^2%n,64位乘法,需要用二进制乘法,类似快速幂。
- if(ret==1 && last!=1 &&last!=n-1)return true;
- last=ret;
- }
- if(ret!=1)return true;
- return false;
- }
- bool Miller_rabin(LL n)//Miller_rabin算法,素数返回true
- {
- if(n<2)return false;
- if(n==2)return true;
- if((n&1)==0)return false;
- LL x=n-1;
- LL t=0;
- while((x&1)==0){x>>=1;t++;}
- for(LL i=0;i<NUM;i++)
- {
- LL a=rand()%(n-1)+1;//生成1~n-1的随机数
- if(check(a,n,t))
- return false;
- }
- return true;
- }
2. Pollard rhos算法:
作用:求解一个数的因子。
原理:设n为待分解的大整数,用某种方法生成a和b,计算p=gcd(a-b,n),直到p不为1或a,b出现循环时为止,若p=n,则说明n是一个素数,否则p为n的一个约数。
算法步骤:选取一个小的随机数x1,迭代生成x[i] = x[i-1]^2+c,一般取c=1,若序列出现循环则退出,计算p=gcd(x[i-1]-x[i],n),若p=1则返回上一步继续迭代,否则跳出迭代过程。若p=n,则n为素数,否则p为n的一个约数,并递归分解p和n/p。
可以在θ(sqrt(p))的期望时间内找到n的一个小因子p。但对于因子很少,因子值很大的大整数n,该方法依然不是很有效。
为了减少反复的次数,算法做了一些改进。该算法用数对(x0,x0)开始,并且用x(i+1)=f(xi) ,迭代计算(x1,x2),(x2,x4),(x3,x6)...(xi,x2i)。在每一次迭代中,我们都应用上述函数式运算(从第二步)第一次计算数对中的第一个元素,第二次计算数对中的第二个元素。
代码实现:
- LL Pollard_rho(LL n,LL c)//Pollard_rho算法,找出n的因子
- LL i=1,j,k=2,y,d,p;
- x=rand()%n;
- y=x;
- while(true)
- i++;
- x=(mul_mod(x,n)+c)%n;
- if(y==x)return n;
- if(y>x)p=y-x;
- else p=x-y;
- d=gcd(p,n);
- if(d!=1&&d!=n)return d;
- if(i==k)
- {
- y=x;
- k+=k;
- }
- }