【问题标题】:Making my program faster using with compiling使用编译使我的程序更快
【发布时间】:2013-09-20 21:19:39
【问题描述】:

我已经制作了一个用于生成素数的筛子。我正在做一个关于 RSA 的学校项目,其中包括一些编程。我将在 RSA 系统中使用素数,但因为这是我的文章,所以安全性并不重要。然而,大素数更具挑战性,我喜欢这样。 我使用的代码:

def Zeef(a):
    import math
    upperBound = a
    upperBoundSquareRoot = int(math.sqrt(upperBound))
    isPrime = [1 for m in range (0,upperBound+1)]
    for m in range(2,upperBoundSquareRoot+1):
        if (isPrime[m]==1):
            for k in range(m*m,upperBound+1,m):
                isPrime[k] = 0;
    print("Priemgetallen : ")
    numberofPrimes = 0
    for m in range(2,upperBound+1):
        if (isPrime[m] ==1):
            print(m)
            numberofPrimes = numberofPrimes+1
    print("Aantal = " , numberofPrimes);
a=input("Alle priemgetallen tot: ")
aa=int(a)
Priemen = Zeef(aa)

我确信有一种更快的方法来生成素数,但我现在对改进我的代码并不感兴趣。

当我运行这个函数时,它可以很好地生成最多 7 位的素数,但是当我想要更多时,它真的很慢。我的电脑(8gb 内存)提示内存不足。我在另一个工具 Processing 中使用了相同的算法。处理速度非常快,但它不能识别超过 10 位数字。 我还注意到,当我生成我的计算机能够计算的素数时,打印速度很慢。

我开始在互联网上搜索,我发现我编译我的程序会加快进度,但我不确定它是否加快了计算和打印部分或只是解释部分。 我还发现了一些关于 numpy 的东西,它是关于数组的,但我不确定这是否会显着加快我的功能。

我怎样才能更快地找到我的素数?

【问题讨论】:

  • 谷歌翻译给我荷兰语到英语如下: Zeef = Sieve; Priemgetallen = 素数;安塔尔 = 数字; Alle priemgetallen tot = "全部启动";普里门=“刺。”它做得好吗? :)(它纠正了我最初对语言的猜测,即德语。)
  • @Wooble 这就是筛子的想法:从所有数字作为候选素数开始,标记那些你知道的不是。它是算法不可或缺的一部分。
  • 看起来不错,对比stackoverflow.com/questions/1042902/…。尽管对于 RSA,您可能会使用 Miller-Rabin 之类的概率测试,可能是在筛选出几千个候选人之后。小素数。
  • This 是一个很棒的话题,列出了许多计算素数及其速度的方法。它可能值得一读。

标签: python performance numpy primes sieve-of-eratosthenes


【解决方案1】:

您说的是computational complexity 的问题。有一点,有一些问题,无论你的处理器或编译器有多快,你都无法加速你的算法。例如,如果您尝试求解 NP-complete problem,则对于较小的值会很容易,但对于较大的值则很难。

我建议您改进您的代码,即使您不想这样做。或者,找到一个自己处理素数生成的库。这是一个有趣的链接:http://rebrained.com/?p=458

这似乎是生成素数的好代码......但它也不会生成大素数(我在我非常快的 iMac 上尝试过)。它很快就达到了大约 100000。我建议查看this SO 问题,了解如何测试随机生成的大数的素数。

【讨论】:

    【解决方案2】:

    这是您的 Erathostenes 筛的未优化版本,使用 numpy.在我运行 64 位版本的 Python (2.7) 和 Numpy (1.7) 的 8GB 笔记本电脑上,它在一分钟内计算出高达 10^9 的素数:

    import numpy as np
    
    def sieve(a):
        upper_bound = np.int(np.sqrt(a))
        is_prime = np.ones((a+1,), dtype=np.bool)
        for m in xrange(2, upper_bound+1):
            if is_prime[m]:
                is_prime[m*m::m] = False
        return np.where(is_prime)[0][2:]
    
    >>> sieve(100)
    array([ 2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
           61, 67, 71, 73, 79, 83, 89, 97], dtype=int64)
    

    这是我的时间安排:

    %timeit sieve(10**9)
    1 loops, best of 3: 33.4 s per loop
    
    %timeit sieve(10**8)
    1 loops, best of 3: 2.47 s per loop
    
    %timeit sieve(10**7)
    1 loops, best of 3: 207 ms per loop
    
    %timeit sieve(10**6)
    100 loops, best of 3: 7.47 ms per loop
    
    %timeit sieve(10**5)
    1000 loops, best of 3: 716 us per loop
    

    您可以通过从筛子中删除所有偶数使其运行速度提高大约两倍,但即使有了这个和世界上所有的内存,您仍然需要几分钟才能让所有素数达到 10^ 10.

    【讨论】:

      【解决方案3】:

      如果您想生成 RSA 算法所需的各种大素数,您将需要比 Eratosthenes 筛法更好的算法。下面是 Python 的 Miller-Rabin 素数检查器的实现:

      def isPrime(n):
          def isSpsp(n, a):
              d, s = n - 1, 0
              while d % 2 == 0: d, s = d / 2, s + 1
              t = pow(a, d, n)
              if t == 1: return True
              while s > 0:
                  if t == n - 1: return True
                  t, s = (t * t) % n, s - 1
              return False
          ps = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
               43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
          if n in ps: return True
          for p in ps:
              if not isSpsp(n, p): return False
          return True
      

      如果您对使用素数编程感兴趣,我在我的博客中谦虚地推荐essay;您还可以查看我博客中的其他一些页面,包括 this one 关于生成 RSA 半素数。

      【讨论】:

      • 我发现 RAM 限制了我的算法。由于我的数组必须包含 10^8 个值,这是我的计算机无法处理的,因为它只有 8gb 的 RAM。如果我想生成大素数 (10^8+),Erathostenes 的筛子真的只是效率低下。如果我计算该算法应该能够计算的 10^7 以下的所有素数,我可以通过将校验数除以我的筛子找到的所有素数来检查整数是否为素数。使用这种方法,我可以找到高达 10^14 的素数。很难快速找到大于 10^9 的素数,我说得对吗?
      • 没有。要快速找到一个大素数,请在上述 isPrime 函数中输入一个奇数。如果它返回 True,你就完成了。如果返回 False,则将数字加 2,然后重试。找到质数应该不会花太长时间。 Miller-Rabin 算法应该能够每秒检查数百个数字。
      • 对了,10^7以上的可以筛分。诀窍是提前计算筛分素数,然后在适合内存的段中运行筛子。有关说明和代码,请参阅http://stackoverflow.com/questions/10249378/。如果你很聪明,你甚至可以筛出非常大的数字,比如 10^50 或更大;在我的博客上查看post 了解如何操作。
      猜你喜欢
      • 1970-01-01
      • 2014-10-12
      • 2011-01-05
      • 2014-11-25
      • 2010-09-26
      • 2014-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多