2014-10-04 54 views
0

我试图在Python 3.4.1中创建一个程序来获取2到100,000的素数。我怎样才能加快我的Python程序?

我的问题是,它需要太多的时间来处理所有的信息,它永远不会给我任何结果。

我已经离开了大约半个小时,它减慢了我所有的电脑,它并没有给我我想要的东西。

我正在使用Eratosthenes的筛算法"Criba de Eratostenes"

这里是我的代码:

from math import * 

def primos(num): 
    num2  = num + 1 
    tnumeros = []      # tnumeros = every number from 2 to num 
    npnumeros= []      # npnumeros = every number that is no prime 
    pnumeros = []      # pnumeros = every prime number 

    for a in range(2, num2): 
     tnumeros.append(a) 

    for i in range(2, int(sqrt(num)) + 1): 
     for j in range(i, int(num/i) + 1): 
      np = i * j 
      npnumeros.append(np) 

    npnumeros = list(set(npnumeros)) 

    for e in tnumeros: 
     if (e in npnumeros): 
      continue 
     else: 
      pnumeros.append(e) 

    return (str("".join(str(pnumeros)))) 

print(primos(100000)) 
+4

这个问题似乎是无关紧要的,因为它没有bug。代码评论可以在[Code Review Stack Exchange](http://codereview.stackexchange.com/)上查询。 – usr2564301 2014-10-04 17:34:40

+0

或者,你可能会认为它有性能问题,所以它的规格失败了? – matsjoyce 2014-10-04 17:41:27

+0

这实际上并不是Eratosthenes的Sieve:该算法同时识别素数并移除每个连续素数的倍数。在这里,您将除去每个*整数的倍数,而不仅仅是几个素数的倍数。 – 2014-10-04 18:26:34

回答

1

不要使用单供npnumeros值;改用集合。你只是在寻找一个号码是否是集合中的感兴趣,所以使它成为一个集从开始:

npnumeros = set() 
# ... 
for i in range(2, int(sqrt(num)) + 1): 
    for j in range(i, int(num/i) + 1): 
     np = i * j 
     npnumeros.add(np) 

# npnumeros = list(set(npnumeros)) # Remove this line, it's no longer needed 

for e in tnumeros: 
    if (e in npnumeros): 
     continue 
    else: 
     pnumeros.append(e) 

原因你的代码是缓慢的是,在列表中查找数为O(N )时间,并且在O(N)循环内做O(N^2)时间。但是在一个集合中查找数字是O(1)次,所以你将在该循环内部有O(N)个时间。从O(N^2)到O(N)将代表处理速度的巨大差异。

如果您不明白我使用的O(N)表示法,请参阅Google "Big O notation"以了解更多信息。

+0

谢谢,我不明白你对O(N)和这些东西,但你说是把npnumeros作为一个集合而不是一个列表来说是正确的,我的程序运行得更快。它需要一点,但它现在运行。 – cotuex 2014-10-04 22:05:44

+0

@cotuex - 基本上,大O符号表示“这个程序需要多长时间取决于其输入数据的大小”。 O(N)表示“程序的运行时间与输入数据中项目的数量N成比例”。 O(N^2)表示运行时间与N的*平方*成比例。因此,如果一个O(N)程序需要2秒才能运行2个输入,则需要7秒才能运行7个输入,而25秒以25个输入运行。如果一个O(N^2)程序需要4秒才能运行2个输入,则需要49秒才能运行7个输入,而运行625秒(10分钟)需要25个输入。 – rmunn 2014-10-05 00:03:18

+0

现在:在列表中查找项目是一个O(N)操作,因为Python在列表中循环遍历,每次比较列表中的每个项目。这需要一定量的时间与N成正比,即列表中的项目数量。如果你还在一个大约有N个项目的循环内运行那个调用,那么所花费的时间与N * N或N平方成正比。这很糟糕:在这种情况下,你的N很大,大约10万,所以N^2是巨大的。将运行时间从“与N平方成正比”降低到“与N成比例”会产生巨大差异。 – rmunn 2014-10-05 00:09:40

0

这是一个严重的截断答案,因为这个问题可能应该移到CR。

一个快速加速就是将npnumeros作为一个集合而不是一个列表。这意味着后面的计算if (e in npnumeros):会显着加快。

修改后的代码:

from math import * 

def primos(num): 
    num2  = num + 1 
    tnumeros = []      # tnumeros = every number from 2 to num 
    npnumeros= []      # npnumeros = every number that is no prime 
    pnumeros = []      # pnumeros = every prime number 

    for a in range(2, num2): 
     tnumeros.append(a) 

    for i in range(2, int(sqrt(num)) + 1): 
     for j in range(i, int(num/i) + 1): 
      np = i * j 
      npnumeros.append(np) 

    npnumeros = set(npnumeros) 

    for e in tnumeros: 
     if (e in npnumeros): 
      continue 
     else: 
      pnumeros.append(e) 

    return (str("".join(str(pnumeros)))) 

print(primos(100000)) 

运行更快〜60倍。

+0

谢谢,你。你说的是rmunn说的,你说得对,但是请你重新检查一下,当你编写代码时,因为在你写代码的时候,我不知道它是代码还是纯文本,而且我知道它是我的代码我不能完全比较我的旧代码和你的代码。不过谢谢你。 – cotuex 2014-10-04 22:08:42