【问题标题】:Trying to make a Python 3 prime number generator尝试制作 Python 3 素数生成器
【发布时间】:2014-05-12 20:28:53
【问题描述】:

正如标题所示,我正在尝试制作一个基于 Python 3 的素数生成器,但我无法让它工作。

代码如下:

import random
def main():
    d=1
    x=random.randint
    while True:
        d=d+1
        if isinstance(x/d, int)==True:
            print (x)
        else: main()
main()

和错误:

Traceback (most recent call last):
  File "/media/mint/casper-rw/ProjectsOrWork/Python/PrimeIdle.py", line 10, in <module>
    main()
  File "/media/mint/casper-rw/ProjectsOrWork/Python/PrimeIdle.py", line 7, in main
    if isinstance(x/d, int)==True:
TypeError: unsupported operand type(s) for /: 'method' and 'int'

【问题讨论】:

  • 所以我向您发布了代码以及建议/批评。

标签: python python-3.x primes


【解决方案1】:

代码在底部,但请尝试根据以下建议编写自己的代码,这对您更有教育意义:

  1. x = random.randint 实际上并没有调用 randint()
  2. 您希望继续生成整数候选并测试素数。您应该在 while 循环中执行此操作,而不是在每次候选测试复合时递归到 main()。这将导致无限的堆栈增长并最终溢出。 (如果你知道你不会从中返回,就永远不要进行递归调用)。此外,你不能轻易地从一个非常深的递归链中return...你正在通过使用print(x) 来回避它。
  3. 出于所有这些原因和良好的分解,将其划分为一个名为 generate_divisor() 的生成器和一个谓词函数 is_prime()(返回 True/False)。
  4. 您的主循环:这里是如何使它成为非递归的,并将它变成一个while循环。对于任何整数 x,您只需要测试直到 floor(sqrt(x)) 的(素数)除数的可除性。如果它不能被这些除数中的任何一个整除,则它是素数,因此 is_prime() 会通过并返回 True。
  5. 您的可除性测试:if (isinstance(x/d, int)==True) 不好,请注意大 x/d 上的截断错误,请改用 if (x%d == 0) 来测试可除性。
  6. 次要:通过观察 d>5 时,素数只能以 1、3、7 或 9 结尾,您可以轻松地在素数筛上获得 60% 的性能提升。因此不要这样做 d = d+1(或 @987654332 @),你生成了很多复合除数并减少了几个素数。 (实际上,您正在生成大量的复合除数,例如 27 或 51,然后测试这些除数,这完全是浪费时间,因为您已经测试了 3 和 17 的可除性。)

.

import random
from math import sqrt, floor

def generate_prime_candidate():
    """Generator to generate random prime candidate"""
    yield random.randint() # probably do randint(2, 2**32 -1). You decide.

def find_random_prime():
    x = generate_prime_candidate()
    while not is_prime(x):
        x = generate_prime_candidate()
    # Found one!
    print(x)
    return x

def is_prime(x):  # normally we call integers n, floats x, but whatever...
    for d in generate_divisors(floor(sqrt(x))): # only search up to sqrt(x)
        if x%d == 0:
            return False # x is composite - d is a divisor
        return True  # x is prime

def generate_divisors(dmax):
    """Generate divisors, up to a limit. We exclude numbers easily known to be composite: residue 0,2,4,5,6,8 modulo 10"""
    yield 2
    yield 3
    yield 5 # now for d>5, exclude them by residue
    d = 7
    while d<dmax:
      while (d%10) == 5: # d easily known to be composite
        d += 2 # in fact we only need to test [0,2,4,6,8] not 5, since d+=2 is skipping residue 5 anyway
      yield d

【讨论】:

  • #4:不只是糟糕;它行不通。在 Python 2.x 中始终为 True,在 3.x 中始终为 False
  • @jonrsharpe 啊,2 到 3 的版本差异,谢谢。那么测试可分性的正确 3.x 习语是什么?
  • x % d 很好——我的观点是 Python 2.x 中的整数除法意味着对于 xd 的所有值以及 3 中的所有值,isinstance(x/d, int)True。 x 例如4 / 2 == 2.0(不是2)所以它总是False
  • 哦,对了。测试余数 x%d == 0 比测试商 x/d -is-an-integer 更容易。
  • 在您的generate_divisorswhile (d%10) in [0,2,4,5,6,8] === while (d%2 != 0) &amp;&amp; d%5 != 0)。但是对于d=7 ... d+=2d%2 != 0 总是正确的。然后,测试d%5 != 0 以备用x%d == 0 根本没有收获......
【解决方案2】:
x=random.randint

不会为x 分配随机整数,它会分配randint 函数。你应该这样做:

x = random.randint(min, max)

但是,这是您的问题中最少的一个 - 您的主要测试不起作用,这实际上不是生成器函数,并且您在每次递归调用时选择一个新的随机数。

【讨论】:

  • 0 和 1 对于素数来说都是“未定义的”。你想从 2 点开始。
  • @chicken4thewin 你不能做无穷大,你也不想。试试 232 或 264。使用此算法,大 x 的运行时间将是无限的(天),同样对于非常大的 x,您对 main() 的递归将导致堆栈溢出,如下所述。此外,由于您的可分性测试isinstance(x/d, int)==True,您会得到假阴性,这不起作用。请参阅我的 cmets 以提高正确性和性能。
  • @chicken4thewin 你到底想达到什么目的?它可能有助于指导我们找到最适合您的解决方案。
  • 他(/她)正在尝试一个非常粗糙的初筛。参见埃拉托色尼筛。除了他尝试每一个除数 d=1,2,3,4,5,6,7,8,9... ,而不仅仅是素数。
  • @smci 你确定吗?那么random 元素是干什么用的呢?
猜你喜欢
  • 2013-07-24
  • 1970-01-01
  • 2020-10-27
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 2013-03-20
  • 2019-09-06
相关资源
最近更新 更多