美文网首页
2019-03-24

2019-03-24

作者: 木马音响积木 | 来源:发表于2019-03-24 07:22 被阅读0次

今天写下来,关于筛子算法,计算素数,针对大数的判断。
简单写一下算法,假设计算40000以内的素数。

筛子算法, 百度。
判断一个数x,是不是素数,只需判断这个数,能否整除 从3到 (根号下x 后 向上取整)之间的素数。
对于大数,这节省很多。
它的底层数学逻辑是,中学时学过一个因式分解定理,他说任何一个非质(合)数都可以分解成质数的连乘积。

我的算法实现,伪码如下:
1、先建立一个4万个元素的list ,a =[0,1,0,1.......] ,这里的0 是因为下标从零开始,把所有的偶数下标,和偶数值,都写为0.
对这个list 进行处理,最后算法结束后,如果value=1 ,就记录其下标,这些下标组成素数列表。
2、从网上获得,素数列表,根据开方原理,c列表就是下面这些,只需要从3,到201 (201不是素数,删除)。
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 。
这很容易获得,百度。这里是处理边界的关键,
199X199=39601 201X199 =39999 ,而一眼就能看出39999 能被3整除。
又因为200,201,都不是素数。

3、开始循环,从b中取出第一个素数3, 把a[3k]设置为0,when 3k >40000 就停。
4、再从b中取出第二个素数5, 把a[5k]设置为0,when 5k >40000 就停。
5、继续循环,直到199,算法结束。
6、用下标,输出。
具体用python实现,代码如下,里面,用了,两种方法对比,还有计时,略复杂。
2.7 python 版本。

# -*- coding: UTF-8 -*-

import time,math
start=time.clock()

def is_prime(number):
    if number > 1:
        if number == 2:
            return True
        if number % 2 == 0:
            return False
        for current in range(3, int(math.sqrt(number) + 1), 2):
            if number % current == 0: 
                return False
        return True
    return False
    
a8=list()    
for i3 in range(3,39998) :
    if is_prime(i3):
        a8.append(i3)       
#print(a8)
    
a=list()
a2=list()
'''
for i in range(0,39999):
    if i%2==0:
        a.append(0);
    else:
        a.append(1);
'''
#use another way to full the list a
listbase =[0,1,0,1]
a=listbase*10000
a.pop()
# check that the list a is the same 
#print(a)

c=[3 ,5 ,7, 11, 13, 17, 19, 23, 29,\
31 ,37, 41, 43 ,47 ,53 ,59 ,61, 67, 71,\
73, 79 ,83 ,89, 97,101 ,103 ,107 ,109 ,113,\
127,131, 137 ,139 ,149 ,151, 157, 163 ,167, 173,\
179 ,181, 191, 193 ,197 ,199]
#print(c)

#b=[3 ,5 ,7, 11, 13, 17, 19, 23, 29]
'''
for ka in c:
    ii=2
    while(ka*ii<=39998):
        #error control
        a[ka*ii]=0
        ii+=1
'''
sum=0
#这个地方是列表遍历,可以采用list.pop(),
#而后多线程跑函数mark。终于可以并行处理了。

for ka in c:
    #以下可以构造一个函数,比如,mark函数。    
    ii=ka            #开始点,很重要,直接把下面的if else 去掉了。
    #这个地方注意,列表下标溢出,应该加上错误处理
    while(ka*ii<=39998):
        #error control
        #if ii<ka:
           # ii+=1
           # continue
        #else:
        a[ka*ii]=0  #实现算法第三步
        sum+=1  #只是为了技术,看算法细节用
        ii+=2 # 去掉偶数     ,这是关键细节 
#print(a)

print(sum)  #only for test 


'''
结果
26890   #循环体执行的次数
0
0.146193

26890
0
0.126677     #a 的生成方式的不同,节约了时间。

通过与下面的算法比较,我的循环次数明显要小,几乎是一半,运行时间短
'''
'''
参考了 http://www.cnblogs.com/zqxLonely/p/4054550.html 的代码,感谢了。
for ka in c:
    #素数判断
    #if(flag[i]=='0'){
    j=ka*ka
    while(j<39999):
        a[j]=0
        sum+=1
        j+=ka
        
    #for (j=ka*ka;j<39999;j+=ka):
    #flag[j]='1';
        #a[j]=0
        #sum+=1
        #j+=ka
        
print(sum)
'''
'''
结果
53755   #循环体执行的次数
0
0.157856
'''
#for index,item in enumerate(sequence):
# get one list ,xiabiao and his value,a is a list,sushu
for index,item in enumerate(a):
#for i in a:
    if item==1:
        a2.append(index)
#print(a2[1:])

a9=a2[1:]
#duibi ,check it is good way to get the prime list 
print(cmp(a8,a9))

t=(time.clock()-start)
print (t)

但愿有用。注意,程序中的几个常数,应该在 前头定义,来增强程序的重用性。
编程坚持的底线是能用的常数,直接用。不要用变量。

这里指的是list c 的直接引入。

另外,从结构化考虑,写个函数,
应该读入40000后,根据根号40000 +1 ,去一个长长的素数list 中去截取,来生成list c 。

相关文章

网友评论

      本文标题:2019-03-24

      本文链接:https://www.haomeiwen.com/subject/ejjyvqtx.html