【问题标题】:How to make loops iterate faster?如何使循环迭代更快?
【发布时间】:2020-06-12 20:06:24
【问题描述】:

我以前从未遇到过这个问题。
我正在尝试生成非常大的素数。
问题是该程序太慢了,无法使用。
当我修改代码以显示每个 num 时,它通过大数字时仍然显得很慢。
有什么方法可以让 Python(3) 循环更快?
如果没有,有没有办法让我的程序更快?

我的代码

import os, time, random

lower = 100000000000000000
upper = 999999999999999999

fh = open("pit.txt", "w+")

print("Starting...")

x = 0

for num in range(lower, upper + 1):
    x = x + 1
    if num > 1:
       for i in range(2, num):
           if (num % i) == 0:
               break
       else:
           print("KEY_CODE = " + str(x))
           print(num)
           fh.write(str(num) + ",")
print("Done.")
fh.close()

PS:我忘了提到程序将值写入文本文档。
我不怀疑它会减慢程序的速度,因为无论如何都没有打印出来。

【问题讨论】:

  • 不同的解决方案,但有一种更快的素数生成算法,称为 Erastosthenes 筛,您可以使用它来加快速度:en.wikipedia.org/wiki/Sieve_of_Eratosthenes
  • 对于初学者,您可以通过在每一步将num 增加 2 来将时间减半。 2 是唯一的偶数。
  • 这是您的基本但低效的primalty测试的问题。这适用于 1e6 以下的数字,但不适用于您提供的范围。查看高效的 p​​rimalty 测试的实现,例如 Miller-Rabin、Sieve of Erathothenes 或类似的东西。
  • 您正试图遍历几乎是 quintillion 个数字的范围并生成 quadrillions 个素数。即使您可以每纳秒生成一个素数,这也需要数年时间,而且您会在几秒钟内耗尽磁盘空间。
  • 最好的方法往往是实现更好的算法。

标签: python python-3.x loops primes


【解决方案1】:

所有大素数的形式为6n±1。在您需要的范围内生成该表单的随机数。然后使用 Miller-Rabin 测试测试该数字。这将比您当前的方法更快地找到一个大素数。

【讨论】:

    【解决方案2】:

    我在您指定的范围内编写了一个非常快速的素数查找器。如果你想要更好的 isprime 测试,你可以从 sympy 导入 isprime:

    import random
    import math 
    
    def isprime(hm, iterx=150):
       for x in range(iterx):
         if pow(random.randint(2,hm-1), hm-1, hm) != 1:
            return False
       return True
    
    def prime_finder(start, end, primeanswer=False, withstats=True):
        while True:
           randnum = random.randint(start, end*2)
           while math.gcd(randnum, 1<<randnum.bit_length()) == 2 and isprime(randnum//2) == False:
             randnum = random.randint(start, end*2)
           answer = randnum//2
           # This option makes the finding of a prime much longer, i would suggest not using it as 
           # the whole point is a prime result. 
           if primeanswer == True:
              if isprime(answer) == False:
                continue
           powers2find = pow(answer, randnum-1, randnum)
           if powers2find == answer:
              continue
           if powers2find < start or powers2find > end:
              continue
           if isprime(powers2find) == True:
              break
           else:  
              continue
        if withstats == False:
          return powers2find
        elif withstats == True:
          return f"pow({answer}, {randnum}-1, {randnum}) = {powers2find}"
        return powers2find
    

    结果:

    
    In [2]:  prime_finder(100000000000000000,999999999999999999)                                                                                                                      
    Out[2]: 'pow(106974006956583922, 213948013913167845-1, 213948013913167845) = 144873055261278481'
    
    In [3]:  prime_finder(100000000000000000,999999999999999999)                                                                                                                      
    Out[3]: 'pow(428583304152980488, 857166608305960977-1, 857166608305960977) = 527820433483021711'
    
    In [4]:  prime_finder(100000000000000000,999999999999999999)                                                                                                                      
    Out[4]: 'pow(325303586907911770, 650607173815823541-1, 650607173815823541) = 160187520431555971'
    
    

    你可以这样运行它以获得答案:

    In [10]:  prime_finder(100000000000000000,999999999999999999,withstats=False) 
        ...:                                                                                                                                                                          
    Out[10]: 443393963672858509
    

    【讨论】:

    猜你喜欢
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2016-06-03
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多