优化Prime数字Python代码

时间:2014-01-02 06:34:39

标签: python primes

我对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循环的原因是我希望能够控制它的运行时间。

如果您有任何关于消除任何混乱的建议,请回复并告诉我,谢谢。

3 个答案:

答案 0 :(得分:3)

与使用整数的操作相比,读取和写入文件非常非常慢。只需删除所有文件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)

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

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)

答案 1 :(得分:1)

继续存储和加载文件中的所有素数是非常低效的。通常,文件访问速度非常慢。而是将素数保存到列表或双端队列中。对于此初始化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

答案 2 :(得分:0)

你正在为你的文件写一个空白行,这是一个int()追溯。另外,我猜你需要从你的新行中删除rstrip()。

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

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

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

当你进入更大的素数时,前n个素数的试验划分是好的,接着是m轮的米勒 - 拉宾。如果Miller-Rabin概率性地表明这个数字可能是一个素数,那么你就完成了试验分裂或AKS或类似的。米勒拉宾可以说“这可能是一个素数”或“这绝对是复合”。 AKS给出了明确的答案,但速度较慢。

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