本文主要是介绍Miller-Rabin素数检测算法笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
摘自:https://blog.csdn.net/u010646250/article/details/51927085
本文内容主要参考《程序员的数学思维修炼》一书中对素数和余数的讲解及这篇博文:
Miller-Rabin素数测试学习笔记
以及这篇文章:
数论部分第一节:素数与素性测试(这篇文章非常好,很清晰的讲解了从素数定义到素数检测算法的过程,比我看到的其他所有资料都好,就是有点长)
先介绍一个概念:互素(或叫互质)
如果a和b两个数的公约数只有1,那么a和b互质,记做(c,m)=1。
根据素数定义,素数与所有小于它的正整数互素。
再介绍几个余数的性质及推广出的几个变换:
(a + b) mod p == (a mod p + b mod p) mod p
(a * b) mod p == ((a mod p) * (b mod p)) mod p
ab mod p == (a mod p)b
要想理解Miller-Rabin,需要先了解一下费马小定理。
Miller-Rabin素数检测算法是基于费马小定理的改进概率算法。
费马小定理
假如p是质数,且(a,p)=1,那么 a^(p-1)≡1(mod p)[或( ap-1 mod p ≡ 1),mod是取模的意思,下同]。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
(摘自百度百科)
费马小定理是关于素数判定的必要非充分条件,即可以说p是质数且a、p互质的情况下a(p-1)≡1(mod p),而不能说只要满足恒等式且a、p互质,p就一定是素数。由此引出伪素数的概念:
伪素数,又叫做伪质数:它满足费马小定理,但其本身却不是素数。若n能整除2^(n-1)-1 [或(2n-1-1)],并且n是非偶数的合数,那么n就是伪素数。
(摘自百度百科)
事实上,偶伪素数也是存在的,并且已被证明有无穷多个。
在伪素数中,存在一组特殊的数,叫做卡迈克尔数,定义为:
对于合数n,如果对于所有正整数b,b和n互素,都有同余式b^(n-1)≡ 1 (mod n) [或(bn-1 mod n ≡ 1)]成立,则合数n为Carmichael数。
(摘自百度百科)
可见,卡迈克尔数一定是合数,且满足费马小定理。卡迈克尔数也被证明有无穷多个,而前一亿个数中,只有255个卡迈克尔数。
庆幸的是,虽然费马小定理的逆定理不完全成立,但在大多数情况下还是有效的。
Fermat素性测试
基于费马小定理 ap-1 mod p≡1公式,(随机地)选取若干个小于p的正整数为a,若所有的a都满足p-1 mod p≡1,则基本认为p是素数。
Fermat素性测试实际上就是对费马小定理的应用。
统计表明,在前10亿个自然数中共有50847534个素数,而满足2^(n-1) mod n = 1的合数n有5597个,这些合数都是以2为底的伪素数。其中一些合数可能在a=2时通过了测试,却不能通过a=3时的测试。能同时通过a=2和a=3的测试的合数叫做以2和3为底的伪素数,前10亿中只有1272个。所以,Fermat素性测试需要做相互独立的若干轮随机测试来降低出错的可能性。
然而,坑爹的是,即使取遍1到n-1的所有整数进行素性测试,仍然会存在一些伪素数没有被查出来,这些数被称为卡迈克尔数(上文有介绍),前10亿中有600多个。
Miller-Rabin素数测试
Miller-Rabin素数测试基于下面的新定理:
如果p是素数,x是小于p的正整数,且x2 mod p = 1,那么要么x=1,要么x=p-1。这是显然的,因为x2 mod p = 1相当于p能整除x2-1,也即p能整除(x+1)(x-1)。由于p是素数,那么只可能是x-1能被p整除(此时x=1)或x+1能被p整除(此时x=p-1)。(ps:素数p只能整除0和它自己)
(摘自数论部分第一节:素数与素性测试)
通过上面这个定理来加强费马小定理,可以得到这个公式:
ad*2r mod p =1
根据上面的定理和公式,在进行Fermat测试时,还需测试d*2r-1时ad*2r mod p是否等于1或者p-1,如果通过则测试d*2r-2时是否成立,直到r=0或者ad*2r-s mod p = p-1,其中0≤s≤r-1。
要测试N是否为素数,首先将N-1分解为 2sd。在每次测试开始时,先随机选一个介于[1,N-1]的整数a,之后如果对所有的r∈[0,s-1],若ad mod N≠1且a2rd≠-1则N是合数。否则,N有3/4的概率为素数。
(摘自维基百科)
上面用新定理加强费马小定理的原理我本人并不是很理解,所以这里用一种自己想到的方法来解释(可能是错的,不要介意 ʅ(‾◡◝))。
ap-1 mod p=1 –>
ad*2r mod p=1 –>
(ad*2r-1)2 mod p=1 –>
(ad*2r-1 mod p)*(ad*2r-1 mod p)=1
所以(ad*2r-1 mod p)的结果只能是±1,其中-1等价于p-1。
如果最上面的式子成立,那么后面的式子都应该成立,并且可以重复其中的过程直到r=1,或者等式右边是p-1。如果右边是p-1,那么式子就不能继续分解下去,过程到此为止。
有人将上面利用加强费马小定理测试素性的过程叫做Miller测试。
通过上面的素性测试可以有效筛掉大部分伪素数。比如,基于原本的费马小定理,341是个最小的底为2的伪素数,而用加强费马小定理,最小的底为2的伪素数是2047,最小的底为2和3的伪素数则是1 373 653,可见效果是非常显著的。
完整的Miller-Rabin素数检测过程就是:进行相互独立的k轮测试,每轮在小于待测素数p的正整数中随机选取a的值,利用加强费马小定理进行Miller测试,通过所有测试的p就可以认为是素数,p被误判的概率是4-k。
有一些非常实用的现成结论可以在进行素数测试时降低算法运行时间:如果被测数小于4 759 123 141(47亿),那么只需要测试三个底数2, 7和61就足够了;如果每次都用前7个素数(2, 3, 5, 7, 11, 13和17)进行测试,所有不超过341 550 071 728 320(3百万亿)的数都是正确的;如果选用2, 3, 7, 61和24251作为底数,那么10^16内唯一的强伪素数为46 856 248 255 981(4.6*1013)。
下面是Miller-Rabin素数检测的流程图:
开始将p-1表示成d*2^r 选择底数a,素数测试论述s计算 a^(d*2^r) mod p结果等于1?r>0?s>1?r=r-1,s=s-1是素数结束结果等于p-1?不是素数yesnoyesnoyesnoyesno
变量s是控制测试轮数的,实时上没有必要将0~s之间所有的数都测一遍,就像上面所说,选择几个特定的数就足以覆盖大部分情况。
这篇关于Miller-Rabin素数检测算法笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!