使用lbaby筛,求10亿之内的所有素数(Yet Another Prime Algorithm)

本文介绍了一种高效筛选10亿之内的所有素数的方法,通过数学原理及算法优化,实现了对素数的有效识别。利用个位数特征减少候选范围,并采用特制的“lbaby筛”算法进行快速筛选。

求10亿之内的所有素数

原题目在这里:

http://bbs2.chinaunix.net/thread-1433650-1-1.html


1,第一步思考:

只有个位数是 1 ,3 ,7 , 9 的数才可能是素数 -- (结论1)


根据这个结论,可以对 10亿内的自然数作如下 划分:

设 集合G为:{ 个位数 为1,3,7,9}

集合X为:{个位数 为 :0, 2, 4, 5, 6,8的数}



2,第二步,反过来想


如果我们能划掉 集合G中 的非素数,则余下的数都是素数了(筛法)

那么,如何才能找出G中的非素数呢?

看如下定理:


非素数一定能写为两个或两个以上素数的乘积:

g= p1*p2*...*pN (pN为素数,N>=2)

好了,我们的定理就写到这里已经够用了


恩,有同学想到了,用乘法!

举个例子:


比如:

1, 3, 7, 9,

11,13,17,19,

21,23,27,29

这12个数中,

我们拿 3 *3 ,得出9,则可以确定,9不是素数把它划掉

拿3*7得出 21,则可以确定,21不是素数,把它划掉

3*9=27 划掉27





3,确定完备性


如何确定集合G中的数全部是素数呢?


接下来看这两个划分(请参照离散数学中的划分定义):


设 集合G为:{ 个位数 为1,3,7,9}

集合X为:{个位数 为 :0, 2, 4, 5, 6,8的数}



我们知道,两个数相乘,它的个位数字就是 ( 两个数的 个位数的乘积)的个位数 (头晕啊)


例子:

99×88 = 8712


两个数的个位数

9 和8

的它们的乘积为:

72

这个乘积的个位数为:

2

和8712 的个位数是相匹配的。


OKOK,打住,很多同学都已经要睡着了


根据结论:

两个数相乘,它的个位数字就是 ( 两个数的 个位数的乘积)的个位数 (头晕啊)


再回头看集合G,X:

设 集合G为:{ 个位数 为1,3,7,9}

集合X为:{个位数 为 :0, 2, 4, 5, 6,8的数}


结论很明显:

集合G 对乘法是封闭的:就是说,G中的任意元素,经过乘法以后,其结果仍然是G的成员,

集合X对乘法是封闭的:就是说,x中的任意元素,经过乘法以后,其结果仍然是X的成员


G,X对乘法结论:

任意的自然数相乘,只要它结果是在G中,那么它的乘数因子中一定不含X的元素,

如果它的结果在X中,那么它的乘数中至少有一个是X中的元素--(结论2)



非素数一定能写为两个或两个以上素数的乘积:

g= p1*p2*...*pN (pN为素数,N>=2)

---(定理1)

素数


再看上边的结论1:


只有个位数是 1 ,3 ,7 , 9 的数才可能是素数

即 素数必然存在于G中-- (结论1)


我们可以得出如下的算法(N以内的素数求法):

只要G中的元素两两相乘,划掉乘积数,余下的数就是素数了

取G的子集GX:{小于等于N的G的所有元素}

对GX中的G1,G2...Gn ,取两任意两个数相乘,在GX中去掉这个乘积数,直到这个乘积大于N

我把这个算法称为《lbaby筛》(哈哈)


算法的证明:反证法:

假设GX中存在一个数gx 是非素数(gx < N),这个数没有被去掉

根据定理1,

gx 可以写成 gx=p1*p2...*pn(n>=2)

其中p1,..pn 为素数且pn < gx <N

则可以推出:p1,...pn 之中应至少有一个不存在于 GX 中,

证明如下:

因为乘法是可结合的

gx可以写成 是算法中两个数相乘的形式:

gx = p1*px (px= p2*...pn)

根据上边的结论2,可以知道,p1或px 中至少有一个不在

集合G{个位数 为1,3,7,9的自然数}中

若p1 不在G中,就是我们要证明的:p1,...pn 之中应至少有一个不存在于 GX 中

若px 不在G中,则可以重复上述的步骤,直至分解成为不可再分解的形式

仍然可以很容易地推导出结论:p1,...pn 之中应至少有一个不存在于 GX 中

由结论1可知,上边的结论与我们假设集合G的矛盾,所以,假设不成立



4,优化:

A,因为只是记录这个数 是否 素数,所以,每个数只占一个bit即可,

一个字节可以存20以内的素数信息,

计算完成的前两个内存字节:

内存:

0 0 0 10 0 001 01 0 0 1 0 1

应该被解释为:

------------------+|+------------------------------

1 3 7 9 11 13 17 19 21 23 27 29 31 33 37 39

由于bit 4 是被置位的,所以,9不是素数

10亿个数:

10亿/20 = 5千万=50MB 内存

bit所在的内存 位置 就能标记这个数是哪个数

B,只存储个位数是 1,3,7,9的整数

C,内存的写比读代价要高得多,先检测需要置的位,如果已经置位,不需要重复置位

D,使用加法代替乘法


5,烧包的性能测试:

(大2那年写的代码,一闪7年了啊,时光如水):



ly@01:~/tst> time echo | ./tb

arrnum: 6104

^_^ 内存初始化完成,primedat类的对象构造成功

time: 2.95

由于生成的数据很大,一一输出将耗费大量时间

输入"show"显示结果,其它任意字符退出:

real 0m3.008s

user 0m2.972s

sys 0m0.036s

ly@01:~/tst>


以下是烧包的测试机:

ly@01:~/tst> free

total used free shared buffers cached

Mem: 4144748 801780 3342968 0 316120 337872

-/+ buffers/cache: 147788 3996960

Swap: 8369856 4980 8364876

ly@01:~/tst> cat /proc/cpuinfo | grep processor

processor : 0

processor : 1

processor : 2

processor : 3

processor : 4

processor : 5

processor : 6

processor : 7



processor : 6

vendor_id : GenuineIntel

cpu family : 6

model : 23

model name : Intel(R) Xeon(R) CPU E5405 @ 2.00GHz

stepping : 6

cpu MHz : 1995.033

cache size : 6144 KB

physical id : 1

siblings : 4

core id : 1

cpu cores : 4

fdiv_bug : no

hlt_bug : no

f00f_bug : no

coma_bug : no

fpu : yes

fpu_exception : yes

cpuid level : 10

wp : yes

flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe lm constant_tsc pni monitor ds_cpl vmx tm2 cx16 xtpr lahf_lm

bogomips : 3990.10

N年前的代码:

点击下边的链接:

http://www.esnips.com/doc/4358e49f-49f8-4170-a846-5f3adb160a31/tst

选 择

Download tst.rar

就可以下载代码了

-------------------

经过测试,上边的烧包代码有错,稍后给出比较好的实现


转载请注明出处,作者

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值