求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
就可以下载代码了
-------------------
经过测试,上边的烧包代码有错,稍后给出比较好的实现
转载请注明出处,作者
本文介绍了一种高效筛选10亿之内的所有素数的方法,通过数学原理及算法优化,实现了对素数的有效识别。利用个位数特征减少候选范围,并采用特制的“lbaby筛”算法进行快速筛选。
946

被折叠的 条评论
为什么被折叠?



