素数在自然数中占有非常重要的地位,素数是一类既简单又神秘的数字。说其简单, 是因为小学生也知道什么是素数;说其神秘,是因为从古至今,多少数学家都想弄明白素 数的规则,却一直没有找到其分布规律。
数学家都没研究出来的规律,程序员当然也不可能会找到。但是,任何事物都有正反 两面,正是由于素数的无规律特点,在密码学中就可以大量采用。另外,在一些齿轮啮合 设计中,也通常将齿轮的齿数设计成素数,以增加两齿轮中两个相同的齿相遇啮合次数的 最小公倍数,这样可增强齿轮的耐用度,减少故障。
2.1 怎么判断素数
怎么判断素数呢?首先需要对素数进行定义,然后根据其定义判断指定的数是不是素 数。对程序员来说,可以按素数的定义编写相应程序对素数进行判断。
2.1.1 什么是素数
数学中的定义是这样的:素数,又称为质数,是指在一个大于1的自然数中,除了1和 此整数自身外,无法被其他自然数整除的数。或者说素数是只有1和本身两个因数的数。
比1大但不是素数的数称为合数。1和0既非素数也非合数。
根据素数的定义,可用如图2-1所示方式列出10以内各数的因数,从而得出2 、3 、5、 7为素数,而4 、6 、8 、9不是素数。
图2-1
从上面的因数分解可看出,10以内共有4个素数。随着数据的增大,素数的分布频率 将变得更稀少,10000以内的素数共有1229个,由于篇幅所限不逐一列出,下面列出1000 以内的168个素数,如图2-2所示。
图2-2
对图2-2所列出的1000以内的素数进行总结,可看出在以100为间隔的区间中素数的个 数是没有规律的,其中:
100以内的素数有25个;
100~200之间的素数有21个;
200~300之间的素数有16个;
300~400之间的素数有16个;
400~500之间的素数有17个;
500~600之间的素数有14个;
600~700之间的素数有16个;
700~800之间的素数有14个;
800~900之间的素数有15个;
900~1000之间的素数有14个。
目前最大的已知素数是257885161-1 (此数字位长度是17425170) ,它是在2013年1月 25日由GIMPS发现的。该组织还在2008年8月23日发现了目前所知第二大的已知素数 243112609-1 (此数字位长度是12978189) 。
在图2-2中列出了1000以内的素数,究竟这些数据是不是素数呢?需要进行验证。
验证一个自然数是否为素数,这个问题在中世纪就引起了人们的注意,当时人们试图 寻找一个公式一劳永逸地解决问题,到了高斯时代,基本上确认了简单的素数公式是不存 在的,因此,高斯认为对素性判定是一个相当困难的问题。从此以后,这个问题吸引了大 批数学家。验证素数的算法可分为两大类,即确定性算法及随机算法,如图2-3所示。
图2-3
确定性算法可得出确定的结果,但通常算法较慢,而随机算法正好相反。通过计算机 进行运算,可解决算法较慢的问题,其算法的实现也很简单。
确定性算法中最常用的就是试除法。试除法是根据素数的定义得出的一种方法,用需 要验证的数N逐个除以从2开始至N-1中的所有数,若能被某一个数整除,表示有一个因 数,说明数N不是素数;若直到N-1都不能被整除,则说明该数是素数。
根据以上思路,可编写以下的试除法函数:
其实,可以对素数的定义进行进一步的分析。要判断数N是否为素数,不需要用N一 直除到N-1才能确认,而只需要除到
就可以了。例如,N=15 ,则能被15整除的除数 有1 、3 、5 ,对于除数5就不用判断,因为N被3整除时其商就是5 ,也就表示N能被5整除 了。
因此,为了减少循环判断的次数,提高程序的执行效率,可将函数is_prime()进行修
改,以提高程序的效率。
从上面的程序可看到,在for循环中以i2与n值进行比较,就可以显著地减少循环的次
数,从而提高验证的效率。
通过验证方法可以验证某个整数是否为素数,而寻找素数的方法,就是寻找在给定限 度内的所有素数排列。例如,要求出1000以内的所有素数,就是一个寻找素数排列的问 题。由于已经有上面定义的is_prime()函数,求出1000以内所有素数的方法就很简单了,
可以用以下程序来完成。
执行以上程序,可得到1000以内的所有素数列表,如图2-4所示。
图2-4
在上面的代码中,通过is_prime()函数来验证指定区间 (2~1000) 中的每一个数是否 为素数,而is_prime()函数中又通过循环进行验证。这种双循环会导致程序执行效率不 高。
这时可考虑采用另一种寻找素数的算法:著名的Eratosthenes求素数方法。下面演示 如何用这种方法求100以内的素数。
Eratosthenes算法假设有一个筛子,用来存放2~100之间的所有数,如图2-5 (a) 所 示。
图2-5
由于偶数都能被2整数,因此偶数都不是素数 (2除外) ,则将这些数筛去,得到如图
2-5 (b) 所示的数据 (设置了背景色的数字将被筛去) 。
接着再将3的倍数筛去,得到如图2-5 (c) 所示结果。
接下来继续将5的倍数筛去,得到图2-5 (d) 所示结果。
最后再将7的倍数筛去,得到如图2-5 (e) 所示结果,即可得到100以内的所有素数。
从图2-5中可看到,在使用Eratosthenes算法进行筛选时,只需要执行4次筛选就完成了 100以内的素数的筛选,效率非常高。如果要筛选的数据范围更大,由于只需要选择已经 筛选过的素数对后面的数进行筛选,因此可快速筛选出后面的素数。
从图2-5中的算法过程可以看出,Eratosthenes算法比试除法的效率要高得多。
根据图2-5中所示的过程编写相应的程序,具体代码如下:
2.1.4 已被证明的素数定理
自古以来就有很多数学家研究素数,因此,得出了许多与素数有关的定理。下面简单 介绍一些已被证明的素数定理。
1 .在(a,2a]之间必有一个素数
在一个大于1的数a和它的2倍之间 (即区间(a,2a]中) 必存在一个素数。如图2-6所
示,可看到在(a,2a]区间中都至少包含一个素数。
图2-6
2 .存在任意长度的素数等差数列
什么是等差数列呢?这是一个古老的数学课题。一个数列从第二项起,从后项减去前
项所得的差是一个相同的常数,则这个数列就被称为等差数列。
用素数构成的等差数列被称为素数等差数列。例如从5开始,以12为间隔常数,就可 以得到这样的序列:
对这个数列来说,只有前5个数是素数,第6个数65能被5整除,不是素数,因此,在
这里得到的是由5个素数构成的素数等差数列:
还有更长的素数等差数列吗?当然有,如下面的10个素数就构成间隔为210的素数等 差数列:
2004年4月18日,格林和陶哲轩两人宣布:他们证明了“存在任意长度的素数等差数 列” ,也就是说,对于任意值K ,存在K个成等差级数的素数。例如K=3 ,有素数序列3 、 5 、7 (两数之间差2) … …K=10 ,有素数序列199 、409 、619 、829 、1039 、1249 、 1459 、1669 、1879 、2089 (两数之间差210) 。他们将长达50页的论文——《素数含有任 意长度的等差数列》张贴在当日的预印本网站上,并向《美国数学年鉴》 (Annals of Mathematics) 投稿。
这是一项惊人的成就,他们的发现揭示了素数中存在的某种规律。他们的证明立即在 国际学术界引起轰动。
3 .其他已证明的素数定理
已证明的素数定理还包括以下几项:
一个偶数可以写成两个数字之和,其中每一个数字最多只有9个质因数。 一个偶数必定可以写成一个质数加上一个合数,其中的因子个数有上界。
一个偶数必定可以写成一个质数加上一个最多由5个因子所组成的合数。后来,有人 简称这个结果为 (1+5) 。
一个充分大偶数必定可以写成一个素数加上一个最多由2个质因子所组成的合数,简 称为 (1+2) 。