美文网首页
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