Python 谁能教我如何进一步优化这个';打印到第n个素数';剧本

Python 谁能教我如何进一步优化这个';打印到第n个素数';剧本,python,algorithm,optimization,performance,numbers,Python,Algorithm,Optimization,Performance,Numbers,我今年17岁,在Python编程语言的帮助下开始编程 我一直在寻求优化这个算法,也许是通过消除其中一个循环,或者通过更好的测试来检查素数 试图计算和显示100000个素数时,脚本会暂停约6秒,因为它会在素数列表作为输出返回控制台之前用素数填充列表 我一直在尝试使用 print odd, 为了简单地打印每个找到的素数,对于较小的输入(如n=1000)来说速度更快,但是对于n=1000000,列表本身的打印速度要快得多(在pythonshell和控制台中) 也许整个代码/算法都应该修改,但脚本应该

我今年17岁,在Python编程语言的帮助下开始编程

我一直在寻求优化这个算法,也许是通过消除其中一个循环,或者通过更好的测试来检查素数

试图计算和显示100000个素数时,脚本会暂停约6秒,因为它会在素数列表作为输出返回控制台之前用素数填充列表

我一直在尝试使用

print odd,
为了简单地打印每个找到的素数,对于较小的输入(如n=1000)来说速度更快,但是对于n=1000000,列表本身的打印速度要快得多(在pythonshell和控制台中)

也许整个代码/算法都应该修改,但脚本应该基本保持不变:用户键入要打印的素数(n),脚本返回所有素数,直到第n个素数

from time import time
odd = 1
primes = [2]
n = input("Number of prime numbers to print: ")
clock = time()
def isPrime(number):
    global primes
    for i in primes:
        if i*i > number:
            return True
        if number%i is 0:
            return False
while len(primes) < n:
    odd += 2
    if isPrime(odd):
        primes += [odd]
print primes
clock -= time()
print "\n", -clock
raw_input()
从时间导入时间
奇数=1
素数=[2]
n=输入(“要打印的素数:”)
时钟=时间()
def iPrime(编号):
全局素数
对于素数中的i:
如果i*i>编号:
返回真值
如果编号%i为0:
返回错误
而len(素数)
我可能想重写整个脚本,使用类似Atkin的筛子:

然而,我只是Python的初学者(甚至是编程方面的初学者:我两周前才开始编写代码),要想弄清楚如何用Python编写Atkin算法的筛选,对我来说是一个相当大的挑战


我希望有一个谷歌黑客能帮我解决这样的问题:(

一个简单的优化,可以在不完全破解代码的情况下应用

  • 随着列表变长,每个素数上的i*i变得非常浪费。相反,在循环外计算i的平方根,并在循环内根据该值进行测试
然而,平方根本身是一个复杂且昂贵的计算,大多数候选数将被拒绝,因为它可以被一个较低的素数(3,5,7)整除,所以这不是一个很好的优化(悲观化?)但是我们实际上不需要那么精确,简单地检查素数是否小于该值的三分之一,就可以产生类似的效果,而不需要平方根计算的计算成本,但是,要牺牲相对较少的不必要的测试。

您可以使用,只需简单地扭转一下:

  • 定义第一个素数2,将达到的最大数(
    max
    )设置为2
  • 生成从
    max+1
    max+n
    n
    连续数字列表
  • 对列表中的素数进行筛选。筛选时,将每个素数的起始数设置为列表中可除以素数的最小数
  • 如果金额达不到,转到2
  • 通过这种方式,您可以控制列表的长度,并且随着长度的增加,速度会更快。然而,这是对算法的彻底修改,并且更难编程

    下面是一个非常粗糙的示例代码,但这只需要不到原始代码的70%的时间:

    from math import sqrt
    from time import time
    primes = [2]
    max = 3
    n = input("Number of prime numbers to print: ")
    r=2
    clock = time()
    def sieve(r):
        global primes
        global max
        s = set(range(max,max+r))
        for i in primes:
            b=max//i
            if (b*i<max):
                b=b+1
            b=b*i
            while b<=max+r-1:
                if b in s:
                    s.remove(b)
                b=b+i
        for i in s:
            primes.append(i)
    while len(primes) < n:
        r=primes[-1]
        sieve(r)
        max=max+r
    primes=primes[0:n]
    print primes
    clock -= time()
    print "\n", -clock
    raw_input()
    
    从数学导入sqrt
    从时间导入时间
    素数=[2]
    最大值=3
    n=输入(“要打印的素数:”)
    r=2
    时钟=时间()
    def筛(r):
    全局素数
    全局最大值
    s=设定值(范围(最大值,最大值+r))
    对于素数中的i:
    b=最大值//i
    
    如果(b*i任何以5结尾的数字,而不是5,都不是素数。所以你可以用一个语句跳过任何以5结尾的大于5的数字。

    正如魏子尧已经说过的那样,我也会尝试一个筛子实现。我唯一要改进的是将其作为所用大小的起点


    在纯python中计算逆函数并不简单,但迭代方法应该足够好,这样你就可以很好地了解筛子必须有多大。因为我不太记得定理的详细证明,而且现在是早上6点,其他人必须插手说如果该定理保证了可用于使用简单筛而不必担心其增长的任何特定上边界。不幸的是,事实并非如此。

    如前所述,所提出的算法无法显著改进。如果要求快速解决方案,则埃拉托斯筛是合适的。尺寸x>=55
    ,则筛的de>x可使用
    n>=x/(Lnx+2)
    进行计算。该方程可使用牛顿迭代法进行求解。提出的算法比原始算法快约10倍:

    def sieveSize(n):
        # computes x such that pi(x) >= n (assumes x >= 55)
        x = 1.5 * n # start
        y = x - n * math.log(x) - 2 * n
        while abs(y) > 0.1:
            derivative = 1 - n/x
            x = x - y / derivative
            y = x - n * math.log(x) - 2 * n
        return int(x) + 1
    
    def eratosthenes(n):
        # create a string flags: flags[i]=='1' iff i prime  
        size = sieveSize(n)
        flags = ['1'] * size # start with: all numbers are prime
        flags[0] = flags[1] = '0' # 0 and 1 are not primes
        i = 0
        while i * i < size:
            if flags[i] == '1':
                for j in range(i * i, size, i):
                    flags[j] = '0'
            i += 1
        return flags
    
    def primes(n):
        flags = eratosthenes(n)
        prims = []
        for i in range(0, len(flags)):
            if flags[i] == '1':
                prims.append(i)
        return prims
    
    prims = primes(100000)
    
    def-sieveSize(n):
    #计算x,使pi(x)>=n(假设x>=55)
    x=1.5*n#开始
    y=x-n*math.log(x)-2*n
    当abs(y)>0.1时:
    导数=1-n/x
    x=x-y/导数
    y=x-n*math.log(x)-2*n
    返回int(x)+1
    def埃拉托斯坦(n):
    #创建一个字符串flags:flags[i]=“1”iff i prime
    尺寸=筛分尺寸(n)
    flags=['1']*size#开头:所有数字都是素数
    标志[0]=标志[1]='0'#0和1不是素数
    i=0
    而i*i
    这是一个很好的问题,但我认为它更适合codereview.stackexchange.com。堆栈溢出主要用于有明确答案的特定编程问题。我只是尝试计算sqrt(数字)