【问题标题】:Optimizing Prime Number Python Code优化素数 Python 代码
【发布时间】:2014-01-02 06:34:39
【问题描述】:

我对 python 世界和一般的编码世界都比较陌生,所以我不太确定如何优化我的 python 脚本。我的脚本如下:

import math
z = 1
x = 0
while z != 0:
    x = x+1
    if x == 500:
        z = 0
    calculated = open('Prime_Numbers.txt', 'r')
    readlines = calculated.readlines()
    calculated.close()
    a = len(readlines)
    b = readlines[(a-1)]

    b = int(b) + 1
    for num in range(b, (b+1000)):
        prime = True
        calculated = open('Prime_Numbers.txt', 'r')
        for i in calculated:
            i = int(i)
            q = math.ceil(num/2)
            if (q%i==0):
                prime = False
        if prime:
            calculated.close()
            writeto = open('Prime_Numbers.txt', 'a')
            num = str(num)
            writeto.write("\n" + num)
            writeto.close()
            print(num)

你们中的一些人可能会猜到我在计算素数。它调用的外部文件包含 2 到 20 之间的所有质数。 我有 while 循环的原因是我希望能够控制它运行多长时间。

如果您有任何建议可以消除其中的任何混乱,请回复并告诉我,谢谢。

【问题讨论】:

  • 如果您想对您的代码进行全面审查,您可能需要考虑在 codereview.stackexchange.com 上发帖。
  • 为一个糟糕的算法优化代码不会大大加快它的速度。做更多的研究并找到更好的算法。
  • This 可能感兴趣...
  • 或更一般的this。
  • 这已经在 Python 中解决了很多次。我自己计算素数的解决方案可以在 stackoverflow.com/questions/9301781/… 找到,我并不认为它是最好的。

标签: python primes


【解决方案1】:

与使用整数的操作相比,读取和写入文件非常非常慢。只需删除所有文件 I/O,您的算法就可以加速 100 倍:

import itertools

primes = {2}  # A set containing only 2

for n in itertools.count(3):  # Start counting from 3, by 1
    for prime in primes:      # For every prime less than n
        if n % prime == 0:    # If it divides n
            break             # Then n is composite
    else:
        primes.add(n)         # Otherwise, it is prime
        print(n)

一个更快的生成素数的算法是筛子。这是 Python 3 中的 Eratosthenes 筛:

end = int(input('Generate primes up to: '))
numbers = {n: True for n in range(2, end)}  # Assume every number is prime, and then

for n, is_prime in numbers.items():         # (Python 3 only)
    if not is_prime:
        continue                            # For every prime number

    for i in range(n ** 2, end, n):         # Cross off its multiples
        numbers[i] = False

    print(n)

【讨论】:

  • 你使用集合而不是列表或双端队列有什么原因吗?
  • @Nabla:为了简单起见,我只是放弃了数学算法。
  • 我只是注意到,您的实现可能并不是真正的埃拉托色尼筛法,因为您划掉了所有数字的倍数,而不仅仅是素数。这是多余的。另请参阅 Mark Ransom 的实现。
  • @Nabla:谢谢,已修复。
  • 将您的第二个代码标记为 Python 3。在 Python 2.7 中,它只生成从 2 到结尾的所有数字。 -- 我喜欢你在代码cmets中对筛子的描述,非常简洁。
【解决方案2】:

继续存储和加载文件中的所有素数是非常低效的。一般来说,文件访问很慢。而是将素数保存到列表或双端队列中。为此初始化calculated = deque(),然后简单地使用calculated.append(num) 添加新素数。同时使用print(num) 输出您的素数并将结果通过管道传输到文件中。

当您发现num 不是素数时,您不必继续检查所有其他除数。所以打破内部循环:

if q%i == 0:
    prime = False
    break

您不需要检查所有先前的素数来检查新的素数。由于每个非素数都需要分解为两个整数,因此至少有一个因数必须小于或等于sqrt(num)。因此,请将您的搜索限制在这些除数上。

你的代码的第一部分也让我很生气。

z = 1
x = 0
while z != 0:
    x = x+1
    if x == 500:
        z = 0

这部分似乎与以下内容相同:

for x in range(500):

您还限制x 到 500 个素数,为什么不简单地使用计数器来代替,如果找到素数并同时检查,则增加,如果达到限制则中断?在我看来,这将更具可读性。

一般来说,您不需要引入限制。您可以随时通过点击Ctrl+C 简单地中止程序。

但是,正如其他人已经指出的那样,您选择的算法对于中等或大素数的性能会很差。有更有效的算法可以找到素数:https://en.wikipedia.org/wiki/Generating_primes,尤其是https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes。

【讨论】:

    【解决方案3】:

    您正在向文件中写入一个空行,这正在进行 int() 回溯。另外,我猜你需要 rstrip() 去掉你的换行符。

    我建议使用两个不同的文件 - 一个用于初始值,一个用于所有值 - 初始值和最近计算的值。

    如果您可以将您的值保存在内存中一段时间​​,那将比反复浏览文件快得多。但是当然,这会限制您可以计算的素数的大小,因此对于较大的值,您可以根据需要返回到 iterate-through-the-file 方法。

    对于计算大小适中的素数,筛子实际上相当不错,值得谷歌搜索。

    当你进入更大的素数时,前 n 个素数的试除是好的,然后是 m 轮米勒拉宾。如果 Miller-Rabin 概率地表明该数字可能是质数,那么您将完成试除法或 AKS 或类似操作。 Miller Rabin 可以说“这可能是素数”或“这绝对是合数”。 AKS 给出了明确的答案,但速度较慢。

    FWIW,我在http://stromberg.dnsalias.org/~dstromberg/primes/ 收集了一堆与主要相关的代码

    【讨论】:

    • 没有空行。 write 本身不写换行符,并且初始文件已经根据提问者的陈述填充,可能最后没有换行符。
    • 实际检查是否有任何从 3 到 floor(sqrt(n)) 的素数,但我不敢在搜索素数的主题上添加更多内容:P
    • 每行的尾随换行符也会被自动剥离。
    • @dstromberg 什么空行?没有任何空行。这是我昨晚将其设置为通宵运行时的输出。 link
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 2017-09-03
    • 1970-01-01
    • 2017-11-02
    • 2014-06-24
    相关资源
    最近更新 更多