最近在读一些闲书的时候又遇到了这个神奇的东西,
素数,即只包含其本身因子与1因子的数。
当然,对于这个东西,我们更通常使用的说法是:
只能被1和其本身整除的数。
其实都差不多,这个东西应该是在小学甚至幼儿园就可能遇到的东西。
与素数相对应的数是合数,也就是不止包含其本身与1两个因子。
还有两个比较特殊的数是“1”和“0”,我曾学过的数学系统对这两个数的定义是:既不是质数(也就是素数)也不是合数,至于其他人学过的系统我也听说过将1算在素数中的,但在此不讨论这个问题。
所以我接下来的讨论不包括对“1”和“0”的讨论。
我个人对数学证明的整体的学习是很欠缺的,所以我会尽量用更逻辑一点的语言叙述而不是用数学符号(毕竟我是在看不懂那些用纯数学概念证明的文章)
我突然发现,只要你读到偏理偏工的书,不论是计算机类的导论丛书,还是数学、物理、甚至是化学、机械工程等等方面的导论丛书,在接触到用纯数字证明时,都有可能碰见这个东西。
我最近读的闲书是关于算法的书目,里面提到了对树型、图型、不规则集合等ADT的描述算法的优化型都有可能用到素数,比如对散列表的优化方案中的“再散列”“可扩散列”等等都会出现依靠素数进行高效优化的步骤,甚至于密码的加解密,数据的复序列化等都可能用到。
对于素数这个领域,其应用面之广是我所不能征及的,且讨论其可应用性也不是我这个领域所能描述的。所以我们只讨论一下这个领域最浅层但最核心的东西,那就是求素数。
如果你或者因为兴趣接触过计算机编程(比如我),或者因为专业要求学习过数据结构与算法,那在学习循环,或者是算法实现时应该都接触过素数求法,最常用也最大众化的一般是两种。
第一种是定义法,因为素数只包含1与其本身两个,所以对于一个给定数X,我只要用这个X依次去整除区间[2,X-1]的所有整数,如果被其中某一个数整除,那X就不是素数,反之就是。
第二种不能说是一种方法,而是一个类别,是对第一种的优化,简称优化定义法,比如说根据定义除了2这个数字之外,所有的偶数一定都不是素数(因为X会有2这个因数),所以在给定区间内抛开素数,对剩余部分进行定义法;再比如我们不去考虑[2,X-1]的区间,仅考虑其的给定区间部分,比如说定义法的给定区间只考虑[2,(x)^(1/2)] (ps:我实在不知道该怎么画出根号。。。) 至于这个区间的合理性,也就是为什么可以做到循环至根号x就可以这一点,我不记得了,但这是一个很简单的数学推理,所以忽略。
至于为什么“明明第一种就能解决任何区间的找素数问题,为什么会存在第二种”出现这种问题,答案就一个字,优化,计算机的算力资源是有限的,但第一种看似通用的算法实际上在你想要查找的区间很大时,他要用到的时间也是难以想象的。
这里本来应该引用一下时间复杂度的概念,但这个东西并不会实际影响我们的证明,所以各位如果有兴趣接触到这一方面内容的,可以自行百度。
好了,说了这么多,其实就是为了说明,埃氏筛能够出现的第一个要点就是为了提高查找素数的效率,节省计算机算力资源。
前两天正好也碰到了有人提到埃氏筛这个东西,所以我们今天就主要讨论一下这个东西。(
接下来我们开始说正题,也就是埃氏筛的合理性。
首先,埃氏筛是一种高效查找指定区间内素数的算法,对于其运行的数学描述我就不多赘述,喜欢的可以自行百度。
我会尽量精准的描述这一算法的运行过程。
我们明确两个定理:
第一,在自然数中,除0与1之外的任何数不是素数就是合数。
第二,任何一个合数都是某一素数的倍数。
(ps:我不知道这两个需不需要证明,但我感觉应该是不需要的。)
接下来是埃氏筛的核心:
对于给定区间内的自然数,如果想要得到该区间内的所有素数,那么就要删除所有素数因子的倍数。
这是比较笼统的说法,没有加上不大于根号n的限制条件,也没有纠结对算法的更精细化。
埃氏筛其实是很好理解的一种算法,为什么这么说呢,只要你再看一眼我们明确的两个定理,其实这种算法的合理性就是显而易见的了,比如说,在给定区间[a,b]内,其内部存在的数要么是素数要么是合数(第二个定理),那么删除掉所有的合数,剩下的肯定就是素数。
把2选定为素数颜色红色,再把2的倍数标为绿,去掉,再去掉3的倍数蓝色,5的倍数黄色,7的倍数紫色,剩下的就是素数,我全部涂成红色了。1不是质数也不是合数,就不管。
很简单,对吧?
但如果你和我一样是一个喜欢钻牛角尖的人,那么就会冒出一个小问号,“这么做为什么是合理的呢?”换句话说,为什么我把这个范围内小于范围的素数因子的倍数都删除,就能得到所有的素数呢?会不会存在反例呢?
我相信或许会有人困惑于这个反例,不知道该叙述,其实我们可以把“删除素数因子倍数”的过程称为吞噬(或者筛选),寻找素数的过程称为再生,而这个定理所体现的其实就是吞噬的程度将远大于再生的程度。
什么意思呢? 大概就是说,我们通过吞噬(或者是说筛选)后会得到一个新的集合,埃氏筛则是说明在这个集合里一定存在我们想要找的这个素数(又或者是一个新的素数,也就是这个素数生成的一瞬间就被包裹在集合中)。
如果我们把吞噬与再生当作两个时不时并发的并行计算机,那么吞噬运行的速度远高于再生的速度,这是证明埃氏筛合理性的核心。
对于反证法的证明就不多说了,毕竟反证法非常容易理解。各位可以试着反证一下。
我们从计算机运行的角度进行前进式证明。
假设给定区间[a,b],寻找一个素数X,
对于自然数区间,该数X一定有两个邻接区间,U-与U+,我们规定这两个区间内只存在合数,并且尽量贴合X(为了证明方便,即便某一方里存在素数,我们通过缩小区间也是可以以此证明的)
我们只要能够证明U-与U+两个区间可以完全被小于X的素数因子的倍数“吞噬掉”或者说完全被“筛掉”,那么就说明该算法是合理的。
U-这个部分其实比较简单,这个区间右界就小于X,那么里边的所有合数都要小于X。
根据明确定理二,所有的合数都是某一素数的倍数,在这个区间内所有合数都会是小于X的素数因子的倍数,通过吞噬是可以完全吃掉这一部分。(这里还有一个理念,那就是递归,这一部分是类似于递归的,因为吞噬掉这部分的基础是小于X的素数因子,那么这些因子又会是比其更小的素数因子的基础进行吞噬,直到追溯至“2”与“3”两个数字为止)
U+这个部分,首先我们已经直到其内部小于X的素数因子的倍数已经删除干净了,那么接下来只要能说明大于等于X素数因子的倍数被吞噬就好了。
U+这个部分最大回到多少呢? 最大应该是到2X-1,到不了2X,因为2X肯定不是素数,在找寻大于X的素数时根据递推原则,2X会是大于X的U-,也会被吞噬。
那么在U+到2X-1内是否会存在不能吞噬的部分呢?这样看来是不行的,毕竟2X-1本身是小于X的倍数(2X),换句话说,充其量其本身也只会是小于X的素数因子的倍数,而如此便能将对U-的讨论推广到U+之上。
我们再把这个区间与X推广至任意数。
也就是说对于任意素数,其周围的合数都会完全的被“吞噬掉”,那么该素数就一定可以被找到。
又因为素数被完全吞噬,那么也不会有某个合数是“漏网之鱼”。
如此,U-与U+都会被小于X的倍数吞噬掉,则说明在给定区间内寻找素数X是可行的,且不会被漏掉(因为吞噬的很干净)。
埃氏筛的合理性也就得证。
其实这是并不复杂,却很愚笨的证明方式,在现存的文献与论文中,纯数学推理与逻辑推理证明这个东西的数不胜数,比我所想到的这种方法要更严谨的更简约的也有很多。
但我为什么还要如此的、近乎直白的叙述问题呢,因为我发现,大多数的教科书更喜欢告诉你用的合理性,但不会告诉你其存在的合理性。
换句话说,他们会告诉你:在写算法时只要剔除掉已求素数以及求完的素数的倍数(从2,3开始),剩下的就是素数。
但他们不会多说一句这种算法存在的合理性是因为“任一合数是小于其本身某素数因子的倍数”这么一句简单的东西。
或许是一瞬间就明白的人认为这种东西不用点名,也或许没明白的认为这种东西就应该这样,
也只有像我们这种喜欢钻牛角尖的人愿意啰嗦两句吧。
以前在讨论的时候有人说填鸭式教育会失去知识的敏捷性,或许就会出现这样的情况吧。
我的证明并没有技术含量,所以可能并不存在逻辑上的完全的自恰与严谨(可能有某种情况是我没有想到的),如果各位对于这个东西真的感兴趣,对于计算机领域与算法领域有一定涉足的想法,请去看专门的书籍与讨论文献。
虽然我也只是对这方面在这段时间产生了兴趣罢了。。。。。。
据说现在不提倡那种资源帖了,就不贴了,想要资源的可以学习纵云梯直接google(琉璃神社在谷歌可以直接查到唉,我也才知道。。。。)