素数测试与随机算法

这篇博客还是去年十一月的时候写的,数学多,写起来还挺费力的。写的过程其实也是自己把所有这些东西串起来的过程,收获挺大,但也挺费神。当时没有写完,就一直存在草稿箱里了。现在暂时没有写完的动力,先发出来再说吧~

这周上计算复杂性的时候讲到随机算法,这类算法有时能在概率意义下(例如以1-p的概率输出正确解,p可以是任意小的数)很高效地解决不少问题。70年代提出的随机素数测试最先引起了人们对这类随机算法的关注,这些算法也得到了广泛的应用,例如密码学里面的RSA就使用了这种随机素数测试。

我自己花了点功夫把这种算法的各个细节都推敲了一遍,发现很多以前学过的数学知识都奇妙地串联起来了。今天晚上从学校回来的时候还在想,或许这就是Steve Jobs当年说过的connecting dots?是啊,这些东西当时在学的时候或许真没意识到以后会用上,有谁会想到一道高中作业题会在研究生的时候用上呢?与其说这是上帝的安排,不如感谢自己当时的努力。所以,只要好好去做好当下的事情,这些积累起来的点滴,在未来的某个时候会不经意的连起来。

回到素数测试。这里要讲的是如何判断一个数是不是素数。如果我们能做到这一点,很多事情就都好办了,例如RSA的核心就是大数的素数分解,一个有效的素数判定方法可以让我们得到很大的素数,从而保证密码的可靠性。

那么如何判断一个数n是否素数呢?首先想到的就是按照定义,检查除了1和它自身以外n还有没有其它因子。如果n可以分解为n=pq,则p、q中较小的那个将不超过sqrt(n),故穷举2~sqrt(n)的所有素数检查n是否能被其整除即可。这种方法的复杂度是O(sqrt(n)),当n很大的时候(例如n~2^1000),这样的复杂度是不可接受的。不过从这方法我自然地就想到了高中还在准备NOIP的时候TOJ上的数素数问题,那时花了好长时间优化算法,才终于没有超时得以AC :)

素数测试是一种可以避免这样穷举的方法。这种方法的背后,是一个简单的想法:为了判断一个数是不是素数,我们进行一系列测试,看这个数是不是具有素数的性质,每个测试检测一个性质,如果这个数通过了所有测试,那么我们就认为这个数是素数。这与一个客户到银行去试图找回银行卡密码时银行柜员对他进行的测试是同一个性质,只不过这时的测试是检查该客户的身份证信息是否与银行记录的一致,如果测试通过,银行就认为这个用户是账户拥有者本人。

个人身份证信息可以被认为是一个人的唯一标识,素数也有类似的性质。如下的Wilson定理就刻画了一种这样的性质:

           p是素数当且仅当(p-1)! = (p-1) mod p。

(p-1)! = (p-1) mod p等价于(p-2)! = 1 mod p。这里首先证明,如果p是素数,则模p剩余类Z[p](即集合{[1], ..., [p-1]},其中[j]表示模p余j的数的集合,可将[j]简记为j)以及其上的乘法运算构成一个群。这个结论在后面也会用到。

说明一个集合及其上定义的运算构成群,需说明其满足群的定义:
1) 该集合对该运算封闭。
2) 乘法满足结合律。
3) 存在单位元。a*1 = a。
4) 对于Z[p]中每个元素a,都存在其逆元即另一元素b使得a*b=1。

1~3这几点对于Z[p]都是显然成立的。4) 这一点成立,是因为首先1和p-1的逆元是自身,对于a等于2,3,...,p-2的情况,若不存在这样的逆元b,则a*b可取的值为2,3,...,p-1,但Z[p]中b的可能取值总共有p-1个,根据抽屉原理必存在b和b',使得a*b = a*b’也即ab=ab' mod p,因此a(b-b')=0 mod p,而由于p是素数所以这是不可能的,故任意元素都有逆元。

据此,可以说明每个元素的逆元都不同且唯一。另外,若p为素数,则a*a=1 mod p的解只有a=1和a=p-1两个。这是因为如果a*a=1 mod p,则a*a - 1 = 0 mod p,即(a+1)(a-1) = 0 mod p,当p为素数时,(a+1)(a-1)必须为零,否则p就有a+1和a-1的部分因子了。

从而当p为素数时,我们可以把2,3,...,p-2两两配对,使得每对的乘积都为1,因此(p-2)! = 1 mod p。另一方面,如果(p-2)! = 1 mod p,则p为素数,因为若p有非平凡的因子q,则(p-2)!除p的余数也一定是q的倍数,不可能为1。这就证明了Wilson定理。

根据这个定理,判断任何数n是否是素数时,只需要检测一个性质:(n-1)! = (n-1) mod n是否成立就可以了。

不过,不要高兴得太早,因为 (n-1)! mod n 很难计算!即便是每步计算都只保留除n的余数以避免空间不足的问题,(n-1)! mod n也需要O(n)的时间来计算,对于很大的n来说,这是不可行的。Wilson定理不能直接运用,那能不能检测其他的性质呢?当然可以,Fermat小定理给出了一种能够有效计算的素数性质:

          如果p是素数,则a^p = a mod p对于所有0<a<p成立。

或者等价地,a^(p-1) = 1 mod p对所有0<a<p成立。为什么这个性质容易检测呢?因为对任意n,0<a<n,指数a^n mod n都可以在O(log(n))的时间内计算出来,方法是简单的分治,每次都把a的指数拆成相同的两半。

Fermat小定理可以用下面的引理简单地导出:

          若p是素数,则对任意x, y,有(x + y)^p = (x^p + y^p) mod p。

假定这个引理成立,则可用归纳法证明对于所有a,定理成立:首先1^p = 1^p mod p显然成立;然后设定理对a成立,利用上面引理,有(a+1)^p = (a^p + 1^p) mod p = (a + 1) mod p,故定理对a+1也成立。

引理的证明使用二项式定理就可以了。因为(x + y)^p = x^p + C(p,1)x^(p-1)y + ... + C(p, p-1) xy^(p-1) + y^p。当p为素数时,p|C(p,k)对于所有0<k<p成立。我清楚地记得这是一道高中的排列组合题目,而且位于我们当时做的那本练习题的右下角。 :)

为什么p|C(p,k)对于所有0<k<p都成立呢?因为组合数C(p,k) = p(p-1)...(p-k+1)/[1*2*...*k]这个式子中,分子有p这个因子,而分母没有这个因子,p不是分子分母的公因子,故不会被消掉(p是素数,所以也不可能消掉p的任何一部分)。又由于C(p,k)是个整数,所以C(p,k)是p的倍数。至此,Fermat小定理证明完毕。

有了能够高效计算的Fermat小定理,我们就可以对整数n进行测试了。测试的时候,随机选择一组a的值,检查Fermat小定理的结论是不是对所有选出的a成立。

不过,对于某些合数n来说,也有一些a满足Fermat小定理的结论,例如a=1的时候定理的结论对任何n都是成立的。

posted on 2012-01-15 11:56  alexajia  阅读(1310)  评论(0编辑  收藏  举报

导航