码迷,mamicode.com
首页 > 其他好文 > 详细

如何判断素数

时间:2015-01-07 23:18:50      阅读:412      评论:0      收藏:0      [点我收藏+]

标签:

  在OI与密码学等各个方面,我们经常会遇到需要判断素数的情况。这个问题看似简单,实则不然。判素就像是排序,只会快排是不能走遍天下的,想要成为一名神犇,就需要接触更多的算法。

 

一:什么是素数

  素数,也可以叫做质数。如果一个大于1的自然数,除去1和他本身,不能被其他数字整除,那么他就是一个素数。任何一个大于1的自然数,要么是素数,要么是可以写做一堆素数相乘。

 

二:素数的性质

(1)质数p的约数只有两个:1和p。
(2)初等数学基本定理:任一大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,且这种分解是唯一的。
(3)质数的个数是无限的。
(4)质数的个数公式f(n) 是不减函数。
(5)若n为正整数,在n2 到(n+1)2之间至少有一个质数。
(6)若n为大于或等于2的正整数,在n到n! 之间至少有一个质数。
(7)若质数p为不超过n(n≥ 4)的最大质数,则p>n/2
(8)如果P是素数,a是小于P的正整数,那么a^(p-1) mod p = 1(一会要用到,顺便吐槽博客编辑器真的好难用)。
  ……
 
三:判素方法
 
  I:埃拉托斯特尼筛法
  该方法由埃及数学家埃拉托斯特尼提出,它主要用于判断区间1~n内的素数。要得到自然数n以内的全部素数,必须把不大于√n的所有素数的倍数剔除,剩下的就是素数。
  这个办法的原理很好理解,它就是利用了素数的定义,把所有素数的倍数拆掉了。但有人看了后仍然会很疑惑,我们不知道那个是素数,为什么还要用素数来筛呢?而且为什么要用不大于√n的素数?要解释第一个问题,我们需要进入到算法的实现过程中去。
  首先,2是一个素数,我们把2的倍数全部都去掉,然后往下找素数。怎么找呢?接下来第一个没被筛掉的数字3肯定是素数,这是为什么呢?因为一个合数的因数肯定比他本身要小(除去它本身),且一定可以写作比他小的质数的乘积形式,我们用3之前的素数2来进行筛,并没有筛掉3,也就是说3不能写作比他小的质数的乘积形式,那么3肯定是一个素数了。然后继续向下筛,碰到没筛掉的就认为它是素数,用它再来筛。
  然后,我们要来解释第二个问题了。
  用√n来作为界限,我们只是为了减少运算量,那么用比√n大的数字呢?当然可以;用比√n小的数字呢?当然不行。可是,为什么不行。(√n略丑,各位看官将就着看)
  我们用最大的数字n来看,假定这个数可以写作1*n,2*n/2,3*N/3,.......,√n*√n。仔细看这一系列的式子,我们会发现,乘号左边的数字一直在变大,而右边的数字一直在变小,这个原因我想应该不用我去解释了。这个有规律的变化会一直持续的√n*√n,两边数字一样大了,如果再继续变化,又会重复原来的式子了。而比n小的数字x,他开方后也就更小,所以我们只需要求到√n就行了。当然,这个√n的小数部分是没有用的,我们应当将它向下取整。
 
伪代码
  function Eratosthenes;
  begin
   for i:=2 to sqrt(n) do
    if i为素数 then
    筛选
  end;

 

 
 II.试除法
  顾名思义,这个办法就是把比n小的数字统统除一遍,如果没有一个数字可以整除n,那么n就是一个素数了。当然这么变态的方法肯定只适用于,数字少加上数字小的情况。如果一台电脑1s可以计算10^9次,那么我们1S中最大可以判断一个10^18的数字,当然这是加了优化的。
  什么优化呢?从筛法中,我已经说过了,判断质数判断到√n就可以了,这样时间复杂度瞬间小了啊。
  如果这样你还嫌太慢,那么你就只能随机找几个比他小的数字试一试了,这样很容易把某些合数当成质数的。
伪代码
    function sc;
    for i:=2 to sqrt(n) do
    begin
    f=true;
    if
n mod i=0 then       f=false
    if f then
      n为质数
      else
      n为合数
    end;

 

 
  III.费马素性检验
  前面已经提到试除法只能适用于数字少加上数字小的情况,那么如果数字多加上数字大怎么办,那我们只能祭出恐怖的费马素性检验了。
  费马素性检验基于费马小定理,即上面我提到的最后一条性质。我们先来证明一下。
  构造素数p的既约剩余系p={1,2,3,...,p-1}
  因为(a,p)= 1,由引理3可得A = {a,2a,3a,...,(p-1)a}
  也是p的一个既约剩余系。
  由既约剩余系的性质,1x2x3x...x(p-1)≡a·2a·3a·...·(p-1)a (mod p)
  即(p-1)! ≡ (p-1)!·ap-1(mod p)
  易知((p-1)!,p) = 1
  同余式两边可约去(p-1)!,得到ap-1≡1 (mod p)
  这样就证明了费马小定理,是不是很神奇呢。(以上内容来自百度百科)
  这个定理的逆命题不是正确的哦,比如虽然2的340次方除以341余1,但341=11*31,我们将这些不是素数还满足2^(p-1) mod p = 1数字称之为伪素数,实际上这类数字并不多。
  不满足一定是合数,满足可能是素数,这样我们制作一张伪素数表就可以了。那么有多少伪素数呢,已知在十亿以内一共有50847534个素数,而伪素数有5594个,判断出错可能性为0.00011,也许我们需要改进一下算法。
  我们把a换成3再重新试一试,某些伪素数满足2^(p-1) mod p = 1,但不满足3^(p-1) mod p = 1。到这里发生了一些小问题,满足2^(p-1) mod p = 1的叫做伪素数,满足3^(p-1) mod p = 1的难道就不是了么?当然是,我们把伪素数的定义改一下,把满足a^(p-1) mod p = 1的伪素数称为以a为底的伪素数。十亿以内同时满足2^(p-1) mod p = 1和3^(p-1) mod p = 1的数字只有1272个,是不是突然就少了好多。然后我们发现,测试越多越好,那我们就随便抽出几个来测试一下吧,测试越多,出错几率越小。
  那么我们把所有小于n的a都测试一遍,肯定能排除伪素数了吧。╮(╯▽╰)╭,你还真别这么想,Robert Daniel Carmichael在1910年找到了这么一个数,而且这个数连1000都不到,他只有561这么大,而且十亿中有600个这样的数,天哪。
 
 IV.Miller Rabin算法
  我先介绍一下Miller Rabin这个人,哦不,这两个人。Gary Lee Miller是卡内基梅斯大学的计算机系教授,他首先针对判素提出了基于广义黎曼猜想的确定性算法,可是广义黎曼猜想并没有被证明过,于是没有人可以证明他的办法是正确的。后来在耶路撒冷希伯来大学,出现了一名名曰Micheal O. Rabin的教授,在75年,对这种办法做出修改,使其不再基于广义黎曼猜想,实际上,Dr. Rabin早在53年就已经拿到了图灵奖。
  该算法基于以下定理:如果p是素数,x是小于p的正整数,且x^2 mod p = 1,那么要么x=1,要么x=p-1。(二次试探定理)
  这个真心是好证到爆的,我就不证明了,各位看官自己想想吧。
  然后我们需要把这个东西加到fermat里,把它俩搅拌成同一个东西。
  搅拌的过程十分简单,只需要在原算法里加入这个二次试探定理就好了,在测试a^(p-1) mod p = 1的同时,我们还要测试a^2 mod p是否等于1,这个小优化多耗费的时间极少,而取得的效果却极大。
  实际上只用fermat小定理就可以叫做Miller Rabin算法了,但是我们还是更习惯于把两个东西搅拌在一起。
 

 

  

如何判断素数

标签:

原文地址:http://www.cnblogs.com/xstsow/p/4054716.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!