原理
由费马小定理可知,若p为质数,对于任意与p互质的整数a,有ap-1≡1(modp),假设我们要测试的数是x,然后在1到p-1内随机生成一个数作为底数a,然后测试它是否符合费马小定理,如果不符合则一定不是素数,符合则有可能是素数.单纯用费马小定理检验素数出错率很高(指满足费马小定理又不是素数的数-这些数称为Carmichael数,也称弱可能素数),因此需要一个更强的检定方法.
二次探测定理:p是质数,x2≡1(modp),x的解只能为1或p-1.利用这条定理就可以大大加强我们的素性检测.具体做法如下,对于被测数x,首先检验它是否能通过费马小定理,如果通过了,看p-1是否为偶数(只有p为2的情况不符合),如果是偶数这利用二次检测定理检测x(p-1)/2是否为1或p-1,如果是p-1的话就不能检测下去了,如果是1的话,则有x(p-1)/2≡1(modp),检查(p-1)/2是否为偶数,如果是偶数的话又能再次利用二次探测定理,检测x(p-1)/4的值是否为1或p-1.这样重复检测下去直到xn=p-1或n为奇数时才停止检测,在这期间任何一次检测不通过则可以断定x为合数.由于只用一个底数检测出错率还是不够低,因此一般是用多个底数进行判定,这样出错率才能降到令人接受的程度.由整个检测过程可知,我们刚开始生成的底数a的取值范围可以改进,想一下1n=1(modp),(p-1)n=1(modp)或(p-1)n=-1(modp)恒成立(p-1的用二项式拆开就证明).因此只要在2到p-2内随机生成一个数作为底数a即可.
不过经过一些大佬的验证,如果待测数是在1至1e15里面的话,用固定底数2,3,7,61,24251测速度会快很多,而且不会出错,这组底数能出错的第一个数是46856248255981.这是个RP算法,多次运行可以降低出错率,假设测的次数为n,出错率大约(1/4)n.
代码
#include
#include
#include
#include
#include
#include
#include
#include
#include <string>
#include
#include
#include
#include <set>
#include