zoukankan      html  css  js  c++  java
  • 浅谈Miller-Rabin素数检测算法

    浅谈Miller-Rabin素数检测

    对于素数判断的操作,我们通常使用的是时间复杂度为(O(sqrt N))的试除法。按理说这种复杂度已经是较优秀的了,但是假如给定的需要判断的数极其之大,并且给定的时限不够以(O(sqrt N))的试除法来判断,该怎么办?

    题出错了

    想得美。

    于是,今天的主角出场了:Miller-Rabin素数检测

    Miller-Rabin素数检测算法用于在短时间内判断出一个数是否是质数,时间复杂度比试除法优秀,应该是(O(T imes log N))级别的(T为检测轮数)。

    Miller-Rabin算法的实现原理

    其实,试除法是目前能实现的百分百正确率判断质数的最快方法。Miller-Rabin之所以能够比它更快,是在牺牲了正确率的基础上。(汗)但是千万不要质疑这个算法的正确性。这种有一定容错率的算法统称为概率型算法,它们的特点就是不保对,但是用起来的确非常的爽。并且,它们的容错率也非常低,可以用多次检测来弥补。

    经过理论证明,Miller-Rabin的错误率是(4^{-T}),T是检测轮数,一般来讲,当(T)达到50左右时,就可以将错误率降到非常低的程度。甚至,比计算机本身出错的概率还要低。

    那么,在了解了Miller-Rabin的随机性之后,我们接下来要学习它的实现原理。

    Miller-Rabin的实现原理利用了费马小定理。费马小定理的内容是:

    [a^{p-1}equiv 1\,\,\,\,(mod\,\,p) ]

    (p)为质数)

    如果想详细了解费马小定理,敬请参考百度百科。

    那么,这个费马小定理就可以作为素数性的一个判断依据。往简单说,就是针对一个大整数,如果(a^{p-1}\%p=1),那么这个数有很大可能是质数。反之,那么这个数一定不是质数。

    好啦!那就拿(a^{p-1}\%p),快速幂取模一下看一看就得了!

    这当然是错的。首先,这种方式的错误率很高,你需要反复地用不同的a检测很多次,时间复杂度噌噌上,最后还有可能依然是错误答案。所以我们应该在费吗小定理的基础上再加一个约束条件,使得算法能够稳定、有序的输出正确解。

    介绍下一个理论依据:二次探测定理

    二次探测定理的内容是:

    如果一个数(p)是质数,对于一个(xin (0,p))(xin Z),方程(x^2 equiv 1\,\,\,\,(mod\,\,p))的解有且只有两个:(x=1)(x=p-1)

    那么,在快速幂累乘的基础上,反复判断现在的(p)是否符合二次探测定理,就大大增加了其正确性。

    具体的实现方式是:

    如果一个数(p)是质数,那么(p-1)一定会是个偶数(你不要拿2来刚我),那么,对于这个指数(p-1),我们可以将其分解成(m imes 2^k)的形式,其中(m)为奇数。那么根据快速幂的原理,我们就会依次对以下数列进行二次探测定理的检测:

    [m,2m,4mcdots m imes 2^{k-1},m imes 2^k ]

    如果这些都合法,最后用费马小定理判断一下是否合法即可。

    Miller-Rabin算法的模板

    bool Miller_check(int a,int n)
    {
    	int ret=1;
    	int b=n-1;
    	while(b)
    	{
    		if(b&1)
    			ret=(ret*a)%n;
    		int x=a;//采用临时变量保存改变前的a
    		a=(a*a)%n;
    		if(a==1 && x!=1 && x!=n-1)//当a为1的时候,方程成立,开始判断解。
    			return 0;//不是素数
    		b>>=1;
    	}
    	return (ret==1)?1:0;
    }
    bool Miller_Rabin(int n,int t)
    {
    	if(n==2)
    		return 1;
    	if(n<2 || !(n&1))
    		return 0;
    	while(t--)
    	{
    		srand(time(NULL));
    		int a=rand();//a要随机数
    		if(!Miller_check(a,n))
    			return 0;
    	}
    	return 1;
    }
    

    要注意的是,因为我们普遍用Miller-Rabin检测大数,所以在实际应用的时候往往要开long long。代码为了美观简化就删去了这个步骤,请应用的时候一定要加上。

    Miller-Rabin算法大体就是这样!谢谢大家的观看!!

  • 相关阅读:
    【Linux】【Chrome】安装Chrome浏览器的攻略
    ubuntu下安装程序的三种方法
    scala学习笔记
    安装scala
    安装java
    Python学习笔记
    Linux安装python
    软件测试笔记
    Linux安装微信
    PUTTY学习
  • 原文地址:https://www.cnblogs.com/fusiwei/p/12222848.html
Copyright © 2011-2022 走看看