小规模素数筛法效率及复杂度分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

小规模素数筛法效率及复杂度分析

全规模筛法,开方筛法,Eratosthenes筛法的复杂性分析讨论

和Miller Rabin筛法的实现难点分析

计算机学院2011级1班计算机科学与技术(师范)张季伦

本文主要讨论几种小规模教学常用的素数筛法的算法时间复杂性以及实现难度,这几种算法分别是全规模筛法,开方筛法,Eratosthenes筛法和Miller Rabin筛法。其中我将对前三种算法进行较为全面的分析,计算证明和代码实现;对于Miller Rabin算法(它其实是一种随机算法),我将给出一个并不完美但包含其主要思想的算法实现。

我将从思想,原理,复杂度和实现代码几个方面来讨论我所提到的算法。

1.全规模遍历筛法:

a)原理:根据素数的基本定义:只能被1或本身整除的数。我们通过用小于其本

身大于等于2的数去除它,判断余数过后方可知道其素性。

b)伪代码:

1.INPUT N;

2.DEFINE FLAG=0;

3.DEFINE I;

4.FOR(I=2;I

IF(N%I==0) {FLAG=0;BREAK;}

ELSE FLAG=1;

}

5.IF(FLAG==0) OUTPUT UNPRIME;

6.ELSE OUTPUT PRIME;

c)复杂度分析:

a)可以很容易得看出,该算法对于测试一个素数的素性时,复杂度为

O(N)。

b)当测试数据为一个数为N的递增数串时,其复杂度为O(N*N)。

2.开方遍历算法:

a)原理:由初等数论的基本知识可以知道,对于任意一个大于2的合数N来说,

下式是成立的:

N=pow(p1,k1)*pow(p2,k2)*pow(p3,k3)*………………*pow(pn,kn)。

其中:pi (1<=i<=n) 表示已知素数2<=pi<=sqrt(N)+1

在这一点中pow(m,n)代表m的n次方,sqrt(m)代表m的开方,加一是为了保

险起见。

所以,我们对全规模遍历法会有一个优化就是将核心的循环步长由N优化为

至多sqrt(N)+1。

b)伪代码:

1.INPUT N;

2.DEFINE FLAG=0;

3.DEFINE I;

4.FOR(I=2;I

IF(N%I==0) {FLAG=0;BREAK;}

ELSE FLAG=1;

}

5.IF(FLAG==0) OUTPUT UNPRIME;

6.ELSE OUTPUT PRIME;

c)复杂度分析:

i.根据和借鉴全规模的分析方式可以得出,在测试数据为单个数的情

况下,开方筛法的复杂度为O(SQRT(N))。

ii.在递增数串N的输入规模情况下复杂度为O(N* SQRT(N))。

3.Eratosthenes筛法:

a)原理:根据初等数论中的基本算术定理衍生来的Eratosthenes筛法(求连续递

增素数表)。其基本的中心思想是这样的:

i.生成自然数数表

ii.得到第一个素数2,并将2的倍数全部划掉(1就不用说了)

iii.由于要得到一个质数,我们只需要确定他的开方数以内的大于2的自然数不会整除它,所以我们的到3是质数,然后划去3的倍数,

依次类推。

b)一些技巧:

i.由于我们已经知道了对于一个数N,其的质因子会一定小于其开方

的向上取整数,所以对于连续数表来说,我们只需要把最大数开方

取整以内的质数的倍数找出即可,而这个过程又是伴随在主过程中

的。

c)伪代码:

1.INPUT N;

2.DEFINE I,J;

3.J=1;

4.J->FLAG=0;

5.FOR(I=2;I

IF(J IS DELED) CONTINUE;

FOR(J=2*I;J<=N;J=J+I){

J->FLAG=0;

}

}

6.FOR(I=1;I<=N;I++) IF(I->FLAG!=0) OUTPUT I;

d)复杂度分析:

i.可以看出,该算法的时间复杂度是常数级别的。但是其空间复杂度

确是O(N)。

ler Rabin算法:

a)原理:根据费马小定理的一个变种,存在质数P使得下列式子成立:

pow(A,(P-1))=1(MOD P)

0

所以我们只需要找到一个小于P的正整数A,对其做上面的模幂操作判断模数

就可以知道P的素性。

但不幸的是这是一个偏否Monte Carlo这意味着凡是他判断出的合数就一定是

合数,而它宣称的质数不一定是质数(比如1729=7*13*19),这些数被称为强

伪素数(Carmichael数)。正因如此,算法的正确判断也是有一个概率的,我

们一般通过多次重复检测提高准确度(由于该算法是一个随机算法)。

所以我们迫切得需要一种算法将强伪素数踢出去。那就是二次检测算法:

其原理是:

如果P是一个素数,0

通过二次检测P我们的测试成功率大大提高。

但是在这里我找到了两个个新的办法:

一是因为Carmichael数的数量是极少的,100000000以内的Carmichael数只

有255个,所以我打算可以做一个数表,在数据小于100000000时在费马检测

后进行Carmichael数表内的遍历,找出是否是Carmichael数。

二是从一个百度友邻处得到的方法(原文copy如下)

对于大数的素性判断,目前Miller-Rabin算法应用最广泛。一般底数仍然是随机选取,但当待测数不太大时,选择测试底数就有一些技巧了。比如,如

果被测数小于4 759 123 141,那么只需要测试三个底数2, 7和61就足够了。

当然,你测试的越多,正确的范围肯定也越大。如果你每次都用前7个素数(2,

3, 5, 7, 11, 13和17)进行测试,所有不超过341 550 071 728 320的数都是

正确的。如果选用2, 3, 7, 61和24251作为底数,那么10^16内唯一的强伪

素数为46 856 248 255 981。这样的一些结论使得Miller-Rabin算法在OI中

非常实用。通常认为,Miller-Rabin素性测试的正确率可以令人接受,随机选

取k个底数进行测试算法的失误率大概为4^(-k)。(这一段感谢

/new/fremn的分享)

我一会儿要实现的算法就是基于第二种思想来设计的。

我会设计一个数表,然后随机从该数表中抽取数字作为因子。

b)伪代码:

1.INPUT N;

2.DEFINE LIST_1={2,7,61};

相关文档
最新文档