【问题标题】:python prime numbers Sieve of Eratosthenespython素数埃拉托色尼筛法
【发布时间】:2013-10-21 03:45:06
【问题描述】:

您好,谁能告诉我如何在此代码中实现 Sieve of Eratosthenes 以使其更快?如果您能用筛子完成它,我们将不胜感激。在这个特定的代码中,我真的很难做到这一点。

#!/usr/bin/env python
import sys

T=10 #no of test cases
t=open(sys.argv[1],'r').readlines()

import math
def is_prime(n):
    if n == 2:
        return True
    if n%2 == 0 or n <= 1:
        return False
    sqr = int(math.sqrt(n)) + 1
    for divisor in range(3, sqr, 2):
        if n%divisor == 0:
            return False
    return True

#first line of each test case
a=[1,4,7,10,13,16,19,22,25,28]
count=0
for i in a:

    b=t[i].split(" ")
    c=b[1].split("\n")[0]
    b=b[0]

    for k in xrange(int(b)):
        d=t[i+1].split(" ")

        e=t[i+2].split(" ")
        for g in d:
            for j in e:
                try:
                    sum=int(g)+int(j)
                    p=is_prime(sum)         
                    if p==True:
                        count+=1
                        print count
                    else:
                        pass
                except:
                    try:
                        g=g.strip("\n")
                        sum=int(g)+int(j)
                        p=is_prime(sum)
                        if p==True:
                            count+=1
                            print count
                        else:
                            pass
                    except:
                        j=j.strip("\n")
                        sum=int(g)+int(j)
                        p=is_prime(sum)
                        if p==True:
                            count+=1
                            print count
                        else:
                            pass

print "Final count"+count

【问题讨论】:

标签: python performance primes


【解决方案1】:

我能想到的最快实现

def sieve(maxNum):
    yield 2
    D, q = {}, 3
    while q <= maxNum:
        p = D.pop(q, 0)
        if p:
            x = q + p
            while x in D: x += p
            D[x] = p
        else:
            yield q
            D[q*q] = 2*q
        q += 2
    raise StopIteration

来源:http://code.activestate.com/recipes/117119-sieve-of-eratosthenes/#c4

替换这部分

import math
def is_prime(n):
    if n == 2:
        return True
    if n%2 == 0 or n <= 1:
        return False
    sqr = int(math.sqrt(n)) + 1
    for divisor in range(3, sqr, 2):
        if n%divisor == 0:
            return False
    return True

primes = [prime for prime in sieve(10000000)]
def is_prime(n):
    return n in primes

除了10000000,你可以放任何你需要素数的最大数。

【讨论】:

  • 我如何把它放在这段代码中??你能告诉我如何在上面的代码中应用它吗?会很有帮助
  • 它变得更慢了:(
  • 你给了什么而不是 10000000?
  • @user2876096 不,不是。我给了你使用的代码而不是is_prime。使用它。
  • 您展示的sieve 算法必须在postponed variation 中使用。它使用更少的内存并且变得更快。
【解决方案2】:

这里发布的原始海报和其他解决方案都犯了同样的错误;如果您使用模运算符或任何形式的除法,您的算法是试除法,不是埃拉托色尼筛,并且会慢得多,O(n^2) 而不是 O(n log日志 n)。这是一个简单的 Python 埃拉托色尼筛法:

def primes(n): # sieve of eratosthenes
    ps, sieve = [], [True] * (n + 1)
    for p in range(2, n + 1):
        if sieve[p]:
           ps.append(p)
           for i in range(p * p, n + 1, p):
               sieve[i] = False
    return ps

这应该会在不到一秒的时间内找到所有小于一百万的素数。如果您对使用素数编程感兴趣,我在我的博客中谦虚地推荐 essay

【讨论】:

  • 当我添加你的代码时,我得到错误 nameerror is_prime not defined
  • 您能否在我发布的代码中更新它。我不知道该怎么做。
【解决方案3】:

在 Python 中加速筛子的一个老技巧是使用花哨的 ;-) 列表切片表示法,如下所示。这使用 Python 3。在 cmets 中记录了 Python 2 所需的更改:

def sieve(n):
    "Return all primes <= n."
    np1 = n + 1
    s = list(range(np1)) # leave off `list()` in Python 2
    s[1] = 0
    sqrtn = int(round(n**0.5))
    for i in range(2, sqrtn + 1): # use `xrange()` in Python 2
        if s[i]:
            # next line:  use `xrange()` in Python 2
            s[i*i: np1: i] = [0] * len(range(i*i, np1, i))
    return filter(None, s)

在 Python 2 中,这会返回一个列表;在 Python 3 中是一个迭代器。在 Python 3 下:

>>> list(sieve(20))
[2, 3, 5, 7, 11, 13, 17, 19]
>>> len(list(sieve(1000000)))
78498

他们都眨眼就跑了。鉴于此,以下是构建is_prime 函数的方法:

primes = set(sieve(the_max_integer_you_care_about))
def is_prime(n):
    return n in primes

set() 部分让它变得更快。当然这个函数很简单,你可能想写:

if n in primes:

直接而不是搞砸:

if is_prime(n):

【讨论】:

  • 感谢您的回答,但现在生成素数时。它们不与列表中的数字总和进行比较,因此整个代码更快。
  • 代码比之前更快,非常感谢。但是求和部分和比较部分仍然很慢:(
  • @user2876096,如果您需要更多帮助,我认为您应该提出一个新问题,显示您现在正在使用的确切代码。 这个问题是关于使用筛子的,已经回答了;-)
  • 谢谢我让它工作了。现在它可以在 7 分钟内解决 50000x50000 个列表 :) 非常感谢大家的帮助。
  • @Ajay Yadav,安全总比抱歉好。例如,考虑n=169。取幂是通过在封面下取对数,乘以幂,然后将对数的底提高到该结果来实现的。根据平台数学库的怪癖,169**0.5 可能出现,例如,13.000000000001 或 12.99999999999 而不是 13.0。使用 round() 而不是 int() 可以防止这种情况发生(int(12.99999999) 将返回 12,而不是此处需要的 13)。
【解决方案4】:

这是一个非常快的生成器,减少了内存使用。

def pgen(maxnum): # Sieve of Eratosthenes generator
    yield 2
    np_f = {}
    for q in xrange(3, maxnum + 1, 2):
        f = np_f.pop(q, None)
        if f:
            while f != np_f.setdefault(q+f, f):
                q += f
        else:
            yield q
            np = q*q
            if np < maxnum:  # does not add to dict beyond maxnum
                np_f[np] = q+q

def is_prime(n):
    return n in pgen(n)

>>> is_prime(541)
True
>>> is_prime(539)
False
>>> 83 in pgen(100)
True
>>> list(pgen(100)) # List prime numbers less than or equal to 100
[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]

【讨论】:

    【解决方案5】:

    这是一个简单的生成器,仅使用不预分配内存的加法。筛子只有素数字典那么大,内存使用量只会根据需要增长。

    def pgen(maxnum): # Sieve of Eratosthenes generator
        pnext, ps = 2, {}
        while pnext <= maxnum:
            for p in ps:
                while ps[p] < pnext:
                    ps[p] += p
                if ps[p] == pnext:
                    break
            else:
                ps[pnext] = pnext
                yield pnext
            pnext += 1
    
    def is_prime(n):
        return n in pgen(n)
    
    >>> is_prime(117)
    >>> is_prime(117)
    False
    >>> 83 in pgen(83)
    True
    >>> list(pgen(100)) # List prime numbers less than or equal to 100
    [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]
    

    【讨论】:

      【解决方案6】:

      这是一个简单的集合解决方案。 与许多列表算法相比,这非常快。 由于哈希表,使用集合进行计算要快得多。 (What makes sets faster than lists in python?)

      问候

      ----------------------------------
      from math import *
      
      def sievePrimes(n):
      
          numbers = set()
          numbers2 = set()
          bound = round(sqrt(n))
      
          for a in range(2, n+1):
              numbers.add(a)
      
          for i in range(2, n):
              for b in range(1, bound):
                  if (i*(b+1)) in numbers2:
                      continue
                  numbers2.add(i*(b+1))
          numbers = numbers - numbers2
      
          print(sorted(numbers))
      

      Simple Solution

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-25
        • 1970-01-01
        • 2011-12-16
        • 2017-11-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多