【问题标题】:Understand fast prime numbers generator [closed]了解快速素数生成器[关闭]
【发布时间】:2017-08-18 07:55:18
【问题描述】:
def sieve_for_primes_to(n):
    size = n//2
    sieve = [1]*size
    limit = int(n**0.5)
    for i in range(1,limit):
        if sieve[i]:
            val = 2*i+1
            tmp = ((size-1) - i)//val
            sieve[i+val::val] = [0]*tmp
    return sieve
print [2] + [i*2+1 for i, v in enumerate(sieve_for_primes_to(10000000)) 
if v and i>0]

有人可以描述一下这段代码是如何工作的吗?

【问题讨论】:

    标签: python primes


    【解决方案1】:

    这被称为Sieve of Eratosthenes,维基页面很好地描述了它。

    它的要点是这样的:

    你选择从 2 开始向上的数字,然后你:

    1. 将所选数字标记为素数。

    2. 从您的集合中删除该数字的所有倍数,以防止它们在未来被选中。

    3. 见 1)

    【讨论】:

      【解决方案2】:

      这实际上是一个压缩 Eratosthenes 筛,它不处理偶数,而是只存储和检查奇数。这就是为什么要从筛子索引到它的数字2 * i + 1。这将存储筛子所需的空间减少了一半。

      它不会选择从 2 开始的数字,而是在之后将 2 添加到素数列表的前面。它从 3 (2 * 1 + 1) 开始,一直到平方根。它没有使用循环来标记组合,而是巧妙地利用了 Python 的切片功能:

      sieve[i + val::val] = [0] * tmp
      

      将倍数设置为 0 (False)。但是,这些行似乎错误地超出了目标:

      limit = int(n**0.5)
      for i in range(1,limit):
      

      limit 是一个未压缩的值,不表示为索引,类似于:

      limit = int(n ** 0.5) // 2 + 1
      

      我的注释版本(更正?)代码:

      def sieve_for_primes_to(n):
          size = n // 2  # allocate storage for odd numbers up to n
          sieve = [True] * size  # mark all odd numbers as prime to start
          limit = int(n ** 0.5) // 2 + 1  # int(sqrt(n)) as an index
      
          for index in range(1, limit):  # ie. number in range(3, int(sqrt(n)))
              if sieve[index]:  # if still marked as prime
                  number = 2 * index + 1  # index to number conversion (1 -> 3)
                  multiples = ((size - 1) - index) // number  # how many multiples from here to end of sieve
                  sieve[index + number::number] = [False] * multiples  # mark odd composites/multiples False
      
          return sieve
      
      print [2] + [2 * index + 1 for index, boolean in enumerate(sieve_for_primes_to(10000000)) if boolean and index > 0]
      

      这里可能还有其他优化:

      sieve[index + number::number] = [False] * multiples
      

      这开始在当前素数的下一个奇数倍数处标记复合倍数。但这意味着 5 从 15 开始标记,它已经被标记为 3。我们实际上可以在当前素数 25 的平方处开始标记复合倍数。对于 OP 的练习,我们将如何修改这个压缩表示代码以结合这种优化?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-26
        • 2013-03-18
        • 2010-10-31
        • 1970-01-01
        • 1970-01-01
        • 2021-02-23
        • 1970-01-01
        相关资源
        最近更新 更多