Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Eratosthenes筛-寻找素数_Python_Math_Primes_Sieve Of Eratosthenes - Fatal编程技术网

Python Eratosthenes筛-寻找素数

Python Eratosthenes筛-寻找素数,python,math,primes,sieve-of-eratosthenes,Python,Math,Primes,Sieve Of Eratosthenes,澄清一下,这不是家庭作业问题:) 我想为我正在构建的数学应用程序寻找素数&偶然发现的方法 我已经用Python编写了它的一个实现。但是速度太慢了。比如说,如果我想找到所有小于200万的素数。需要20分钟以上。(我在这一点上停了下来)。我怎样才能加快速度 def primes_sieve(limit): limitn = limit+1 primes = range(2, limitn) for i in primes: factors = range(i

澄清一下,这不是家庭作业问题:)

我想为我正在构建的数学应用程序寻找素数&偶然发现的方法

我已经用Python编写了它的一个实现。但是速度太慢了。比如说,如果我想找到所有小于200万的素数。需要20分钟以上。(我在这一点上停了下来)。我怎样才能加快速度

def primes_sieve(limit):
    limitn = limit+1
    primes = range(2, limitn)

    for i in primes:
        factors = range(i, limitn, i)
        for f in factors[1:]:
            if f in primes:
                primes.remove(f)
    return primes

print primes_sieve(2000)
更新: 最后我对这段代码进行了分析&发现从列表中删除一个元素花费了相当多的时间。考虑到它必须遍历整个列表(最坏的情况)才能找到元素&然后删除它,然后重新调整列表(可能会有副本出现?),这是可以理解的。不管怎样,我扔掉了字典的清单。我的新实施-

def primes_sieve1(limit):
    limitn = limit+1
    primes = dict()
    for i in range(2, limitn): primes[i] = True

    for i in primes:
        factors = range(i,limitn, i)
        for f in factors[1:]:
            primes[f] = False
    return [i for i in primes if primes[i]==True]

print primes_sieve1(2000000)

从数组(列表)的开头删除需要向下移动数组(列表)后面的所有项。这意味着从前面开始,以这种方式从列表中删除每个元素是一个O(n^2)操作

使用集合可以更高效地执行此操作:

def primes_sieve(limit):
    limitn = limit+1
    not_prime = set()
    primes = []

    for i in range(2, limitn):
        if i in not_prime:
            continue

        for f in range(i*2, limitn, i):
            not_prime.add(f)

        primes.append(i)

    return primes

print primes_sieve(1000000)
。。。或者,避免重新排列列表:

def primes_sieve(limit):
    limitn = limit+1
    not_prime = [False] * limitn
    primes = []

    for i in range(2, limitn):
        if not_prime[i]:
            continue
        for f in xrange(i*2, limitn, i):
            not_prime[f] = True

        primes.append(i)

    return primes

您没有完全实现正确的算法:

在第一个示例中,
primes\u sieve
不维护要删除/取消设置的素性标志列表(如在算法中),而是连续调整整数列表的大小,这非常昂贵:从列表中删除项需要将所有后续项下移一

在第二个示例中,
primes\u sieve1
维护一个素性标志字典,这是正确的步骤,但它以未定义的顺序在字典中迭代,并冗余地删除因子中的因子(而不是像算法中那样仅删除素数的因子)。您可以通过对键进行排序和跳过非素数(这已经使它快了一个数量级)来解决这个问题,但直接使用列表仍然更有效

正确的算法(使用列表而不是字典)如下所示:

def primes_sieve2(limit):
    a = [True] * limit                          # Initialize the primality list
    a[0] = a[1] = False

    for (i, isprime) in enumerate(a):
        if isprime:
            yield i
            for n in range(i*i, limit, i):     # Mark factors non-prime
                a[n] = False

(请注意,这还包括在素数平方(
i*i
)而不是它的双精度处开始非素数标记的算法优化。)

我意识到这并不能真正回答如何快速生成素数的问题,但也许有些人会发现这个替代方案很有趣:因为python通过生成器提供了惰性求值,所以eratosthenes的筛选可以完全按照如下所述实现:

def intsfrom(n):
    while True:
        yield n
        n += 1

def sieve(ilist):
    p = next(ilist)
    yield p
    for q in sieve(n for n in ilist if n%p != 0):
        yield q


try:
    for p in sieve(intsfrom(2)):
        print p,

    print ''
except RuntimeError as e:
    print e
try块就在那里,因为算法会一直运行,直到它吹出堆栈,并且没有
try block将显示回溯,将实际输出推离屏幕。

一个简单的速度破解:定义变量“primes”时,将步骤设置为2以自动跳过所有偶数,并将起点设置为1

然后您可以进一步优化,而不是在素数中使用for i,在素数中使用for i[:round(len(素数)**0.5)]。这将大大提高性能。此外,您可以消除以5结尾的数字以进一步提高速度。

更快:

import time
def get_primes(n):
  m = n+1
  #numbers = [True for i in range(m)]
  numbers = [True] * m #EDIT: faster
  for i in range(2, int(n**0.5 + 1)):
    if numbers[i]:
      for j in range(i*i, m, i):
        numbers[j] = False
  primes = []
  for i in range(2, m):
    if numbers[i]:
      primes.append(i)
  return primes

start = time.time()
primes = get_primes(10000)
print(time.time() - start)
print(get_primes(100))
我的实施:

import math
n = 100
marked = {}
for i in range(2, int(math.sqrt(n))):
    if not marked.get(i):
        for x in range(i * i, n, i):
            marked[x] = True

for i in range(2, n):
    if not marked.get(i):
        print i

通过结合许多爱好者的贡献(包括以上评论中的Glenn Maynard和MrHIDEn),我在python 2中获得了以下代码:

def simpleSieve(sieveSize):
    #creating Sieve.
    sieve = [True] * (sieveSize+1)
    # 0 and 1 are not considered prime.
    sieve[0] = False
    sieve[1] = False
    for i in xrange(2,int(math.sqrt(sieveSize))+1):
        if sieve[i] == False:
            continue
        for pointer in xrange(i**2, sieveSize+1, i):
            sieve[pointer] = False
    # Sieve is left with prime numbers == True
    primes = []
    for i in xrange(sieveSize+1):
        if sieve[i] == True:
            primes.append(i)
    return primes

sieveSize = input()
primes = simpleSieve(sieveSize)
在我的机器上计算10次方的不同输入所需的时间为:

  • 3:0.3毫秒
  • 4:2.4毫秒
  • 5:23毫秒
  • 6:0.26秒
  • 7:3.1秒
  • 8时33分

    • 这是一个内存效率更高的版本(而且是一个合适的筛选,而不是试用版)。基本上,不是保留一个包含所有数字的数组,并划掉那些不是质数的,而是保留一个计数器数组——发现的每一个质数对应一个计数器——并将它们跳到假定质数之前。这样,它使用与素数成比例的存储,而不是最高素数

      import itertools
      
      def primes():
      
          class counter:
              def __init__ (this,  n): this.n, this.current,  this.isVirgin = n, n*n,  True
                  # isVirgin means it's never been incremented
              def advancePast (this,  n): # return true if the counter advanced
                  if this.current > n:
                      if this.isVirgin: raise StopIteration # if this is virgin, then so will be all the subsequent counters.  Don't need to iterate further.
                      return False
                  this.current += this.n # pre: this.current == n; post: this.current > n.
                  this.isVirgin = False # when it's gone, it's gone
                  return True
      
          yield 1
          multiples = []
          for n in itertools.count(2):
              isPrime = True
              for p in (m.advancePast(n) for m in multiples):
                  if p: isPrime = False
              if isPrime:
                  yield n
                  multiples.append (counter (n))
      
      您会注意到,
      primes()
      是一个生成器,因此您可以将结果保存在列表中,也可以直接使用它们。下面是第一个
      n
      素数:

      import itertools
      
      for k in itertools.islice (primes(),  n):
          print (k)
      
      为了完整起见,这里有一个计时器来测量性能:

      import time
      
      def timer ():
          t,  k = time.process_time(),  10
          for p in primes():
              if p>k:
                  print (time.process_time()-t,  " to ",  p,  "\n")
                  k *= 10
                  if k>100000: return
      

      如果你想知道的话,我还编写了
      primes()
      作为一个简单的迭代器(使用
      \uuuu iter\uuuu
      \uuu next\uuuu
      ),它以几乎相同的速度运行。我也很惊讶

      由于速度的原因,我更喜欢NumPy

      import numpy as np
      
      # Find all prime numbers using Sieve of Eratosthenes
      def get_primes1(n):
          m = int(np.sqrt(n))
          is_prime = np.ones(n, dtype=bool)
          is_prime[:2] = False  # 0 and 1 are not primes
      
          for i in range(2, m):
              if is_prime[i] == False:
                  continue
              is_prime[i*i::i] = False
      
          return np.nonzero(is_prime)[0]
      
      # Find all prime numbers using brute-force.
      def isprime(n):
          ''' Check if integer n is a prime '''
          n = abs(int(n))  # n is a positive integer
          if n < 2:  # 0 and 1 are not primes
              return False
          if n == 2:  # 2 is the only even prime number
              return True
          if not n & 1:  # all other even numbers are not primes
              return False
          # Range starts with 3 and only needs to go up the square root
          # of n for all odd numbers
          for x in range(3, int(n**0.5)+1, 2):
              if n % x == 0:
                  return False
          return True
      
      # To apply a function to a numpy array, one have to vectorize the function
      def get_primes2(n):
          vectorized_isprime = np.vectorize(isprime)
          a = np.arange(n)
          return a[vectorized_isprime(a)]
      
      在Jupyter笔记本上比较Eratosthenes的筛子速度和蛮力。用539倍于蛮力的速度筛分埃拉托斯坦(Eratosthenes)中的百万元素

      %timeit get_primes1(1000000)
      %timeit get_primes2(1000000)
      4.79 ms ± 90.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      2.58 s ± 31.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
      

      我认为必须可以简单地使用空列表作为循环的终止条件,并得出以下结论:

      limit = 100
      ints = list(range(2, limit))   # Will end up empty
      
      while len(ints) > 0:
          prime = ints[0]
          print prime
          ints.remove(prime)
          i = 2
          multiple = prime * i
          while multiple <= limit:
              if multiple in ints:
                  ints.remove(multiple)
              i += 1
              multiple = prime * i
      
      limit=100
      ints=列表(范围(2,限制))#将以空结束
      当len(ints)>0时:
      素数=整数[0]
      打印素数
      整数删除(素数)
      i=2
      倍数=素数*i
      当多重
      导入数学时
      def筛(n):
      素数=[True]*n
      素数[0]=假
      素数[1]=假
      对于范围(2,int(数学sqrt(n))+1)内的i:
      j=i*i
      而j
      我能想到的最快实现:

      isprime = [True]*N
      isprime[0] = isprime[1] = False
      for i in range(4, N, 2):
          isprime[i] = False
      for i in range(3, N, 2):
          if isprime[i]:
              for j in range(i*i, N, 2*i):
                  isprime[j] = False
      

      我认为这是用eratosthenes方法寻找素数的最短代码

      def prime(r):
          n = range(2,r)
          while len(n)>0:
              yield n[0]
              n = [x for x in n if x not in range(n[0],r,n[0])]
      
      
      print(list(prime(r)))
      

      使用一点
      numpy
      ,我可以在2秒钟多一点的时间内找到所有低于1亿的素数

      有两个关键特性需要注意

      • 仅对
        i
        n
      • 使用
        x[2*i::i]=False将
        i
        的倍数设置为
        False
        比显式python for循环快得多
      这两种方法大大加快了代码的速度。对于低于一百万的限制,没有明显的运行时间

      import numpy as np
      
      def primes(n):
          x = np.ones((n+1,), dtype=np.bool)
          x[0] = False
          x[1] = False
          for i in range(2, int(n**0.5)+1):
              if x[i]:
                  x[2*i::i] = False
      
          primes = np.where(x == True)[0]
          return primes
      
      print(len(primes(100_000_000)))
      

      不确定我的代码是否有效,有人愿意评论吗

      from math import isqrt
      
      def isPrime(n):
          if n >= 2: # cheating the 2, is 2 even prime?
              for i in range(3, int(n / 2 + 1),2): # dont waste time with even numbers
                  if n % i == 0:
                      return False
          return True
      
      def primesTo(n): 
          x = [2] if n >= 2 else [] # cheat the only even prime
          if n >= 2:
              for i in range(3, n + 1,2): # dont waste time with even numbers
                  if isPrime(i):
                      x.append(i)  
          return x
      
      def primes2(n): # trying to do this using set methods and the "Sieve of Eratosthenes"
          base = {2} # again cheating the 2
          base.update(set(range(3, n + 1, 2))) # build the base of odd numbers
          for i in range(3, isqrt(n) + 1, 2): # apply the sieve
              base.difference_update(set(range(2 * i, n + 1 , i)))
          return list(base)
      
      print(primesTo(10000)) # 2 different methods for comparison
      print(primes2(10000))
      
      我只是
      def prime(r):
          n = range(2,r)
          while len(n)>0:
              yield n[0]
              n = [x for x in n if x not in range(n[0],r,n[0])]
      
      
      print(list(prime(r)))
      
      import numpy as np
      
      def primes(n):
          x = np.ones((n+1,), dtype=np.bool)
          x[0] = False
          x[1] = False
          for i in range(2, int(n**0.5)+1):
              if x[i]:
                  x[2*i::i] = False
      
          primes = np.where(x == True)[0]
          return primes
      
      print(len(primes(100_000_000)))
      
      from math import isqrt
      
      def isPrime(n):
          if n >= 2: # cheating the 2, is 2 even prime?
              for i in range(3, int(n / 2 + 1),2): # dont waste time with even numbers
                  if n % i == 0:
                      return False
          return True
      
      def primesTo(n): 
          x = [2] if n >= 2 else [] # cheat the only even prime
          if n >= 2:
              for i in range(3, n + 1,2): # dont waste time with even numbers
                  if isPrime(i):
                      x.append(i)  
          return x
      
      def primes2(n): # trying to do this using set methods and the "Sieve of Eratosthenes"
          base = {2} # again cheating the 2
          base.update(set(range(3, n + 1, 2))) # build the base of odd numbers
          for i in range(3, isqrt(n) + 1, 2): # apply the sieve
              base.difference_update(set(range(2 * i, n + 1 , i)))
          return list(base)
      
      print(primesTo(10000)) # 2 different methods for comparison
      print(primes2(10000))
      
      def nondivsby2():
          j = 1
          while True:
              j += 2
              yield j
      
      def nondivsbyk(k, nondivs):
          j = 0
          for i in nondivs:
              while j < i:
                  j += k
              if j > i:
                  yield i
      
      def primes():
          nd = nondivsby2()
          while True:
              p = next(nd)
              nd = nondivsbyk(p, nd)
              yield p
      
      def main():
          for p in primes():
              print(p)
      
      import sympy
      list(sympy.primerange(lower, upper+1))
      
      def prime_factors(n):
          for i in range(2, int(n ** 0.5) + 1):
              if (q_r := divmod(n, i))[1] == 0:
                  return [i] + factor_list(q_r[0])
          return [n]
      
      sieve = lambda j: [print(x) for x in filter(lambda n: 0 not in map(lambda i: n % i, range(2, n)) and (n!=1)&(n!=0), range(j + 1))]