【问题标题】:Print all twin prime pairs below 100 in Python在 Python 中打印所有小于 100 的孪生素数对
【发布时间】:2016-03-24 00:29:02
【问题描述】:

编写一个程序来确定 100 以下的孪生素数对的数量

n = 100 # upper limit number
k = range(3, int((n+1)**0.5) + 1, 2)


def is_prime_pair(i, i2):
if i <= 2 or i2 <= 2:
    return False
max_div = (i2 ** 0.5) + 1
for x in k:
    if (x > max_div or x == i or x == i2):
        break
    if (i % x == 0) or (i2 % x == 0):
        return False
return True
for i in range(1, n+1, 2):
    if is_prime_pair(i, i+2):
        print "(" + str(i) + ", " + str(i+2) + ")" # Print pairs if prime pair

如何优化我的代码以使其更短、更快?

【问题讨论】:

  • 它有没有更短的更快?它可以更短,但更慢吗?它可以更快,但更长吗?
  • 变量k 仅使用一次,因此可以在for 循环中仅使用定义的范围替换它。另外,我相信break 可以完全替换为return Truereturn 1
  • 对于优化,您会在codereview.stackexchange.com获得更好的运气(或至少减少反对票)

标签: python python-3.x primes


【解决方案1】:

如何优化我的代码以使其更短、更快?

以下是一种更短、更快的基于筛子的方法:

def find_prime_pairs(n):

    sieve = [True] * n

    if n > 0:
        sieve[0] = False
        if n > 1:
            sieve[1] = False

    for number in range(2, int(n ** 0.5) + 1):
        if sieve[number]:
            for index in range(number * number, n, number):
                sieve[index] = False

    return [(a, b) for b, a in enumerate(range(0, n - 2), start=2) if sieve[a] and sieve[b]]

print(*find_prime_pairs(100), sep='\n')

用法

> python3 test.py
(3, 5)
(5, 7)
(11, 13)
(17, 19)
(29, 31)
(41, 43)
(59, 61)
(71, 73)
>

当使用高达 100 的素数时,任何代码都可以,因为它的范围太小而无法对性能征税。让我们考虑 1000000(一百万)。出于计时目的,我们将计数,而不是打印成对。

@AlexHall 提供的第一个答案需要两倍于您原始代码的时间来计算多达 100 万对。他的第二个答案比您的原始代码花费了三倍的时间。更短并不总是意味着更快。在完全测试之前不要相信任何答案。

我上面的基于筛子的代码比你的原始代码快四倍,而且小了 15%。

【讨论】:

    【解决方案2】:

    首先建立一个素数列表,然后搜索双胞胎 这样你就不会两次检查同一个数字是否是素数。

    primes = [2]
    for candidate in xrange(3, 100, 2):
        # Secondly don't try dividing potential primes by every odd number
        # Just try dividing by the primes you already know!
        for prime in primes:
            if prime ** 2 > candidate:
                primes.append(candidate)
                break
            if candidate % prime == 0:
                break
    
    # Iterate through all positions in the list except the last to avoid an IndexError
    for i in xrange(len(primes) - 1):
        if primes[i + 1] - primes[i] == 2:
            print (primes[i], primes[i + 1])
    

    元组已按照您想要的方式格式化。

    【讨论】:

      【解决方案3】:

      如果您想主要坚持当前的代码但改进细节:

      1. 使用 for i in range(3, ...,因为您知道素数对不能以 1 或 2 开头。然后您可以删除 if i &lt;= 2...,因为这永远不会发生。
      2. 拥有一个同时测试两个数字的素数的is_prime_pair 函数让事情变得更加困难。而是有一个 is_prime 函数来测试一个数字,然后调用 is_prime(i) and is_prime(i+2)
      3. 很明显,如果x 不大于max_div,那么它小于ii2,所以删除or x == i or x == i2。顺便说一句,if (x &gt; max_div or x == i or x == i2): 不需要那些额外的括号:if x &gt; max_div or x == i or x == i2: 是有效的。
      4. 如果x == max_div,那么您已经可以break,因为max_div 大于x 的平方根。
      5. ** 优先于 +,因此简化为 max_div = i2 ** 0.5 + 1

      所以现在我们有:

      def is_prime(i):
          max_div = i ** 0.5 + 1
          for x in k:
              if x >= max_div:
                  break
          ...
      

      这是一种愚蠢的做事方式:只需遍历max_div 为上限的范围!您只需将 max_div 转换为 int 即可在 range 函数中使用。说服自己,无论i 是否是一个完美的正方形,这都是正确的,并且没有一个错误的错误。然后我们有:

      def is_prime(i):
          max_div = int(i ** 0.5 + 1)
          for x in range(3, max_div, 2):
              if i % x == 0:
                  return False
          return True
      

      这是一种可以在 Python 中方便地重构的常见模式:

      def is_prime(i):
          max_div = int(i ** 0.5 + 1)
          return not any(i % x == 0 for x in range(3, max_div, 2))
      

      (如果您不熟悉,我使用了generator expression

      您可以通过两个技巧使其更简洁,尽管可能更难阅读。首先内联max_div,因为它只使用过一次。然后,您可以使用all 代替any,并将整数视为布尔值:

      def is_prime(i):
          return all(i % x for x in range(3, int(i ** 0.5 + 1), 2))
      

      这里我们说一个数是素数,如果它除以x 时留下一些非零余数对于所有x(因此all 函数)值得检查。这是因为在 Python 中0 类似于False 而所有其他数字都类似于True

      正如我在其他答案中提到的,无需手动格式化该对。

      由于您使用print 作为语句,因此您必须使用 Python 2,而不是标签上所说的 3。在这种情况下,将所有 range 实例替换为 xrange 以提高效率。

      所以最后就是:

      n = 100  # upper limit number
      
      def is_prime(i):
          return all(i % x for x in xrange(3, int(i ** 0.5 + 1), 2))
      
      for i in xrange(3, n + 1, 2):
          if is_prime(i) and is_prime(i + 2):
              print (i, i + 2)
      

      但是我相信我的其他答案会更快,尽管这可能不会仅针对 n = 100 显示。最明显的问题是,只要i 是素数,那么is_prime(i + 2) 将被调用,然后在循环的下一次迭代中is_prime(i) 将是多余的,因为这是刚刚计算的。您可以通过使用集合记住 is_prime 来改进这一点。

      【讨论】:

        【解决方案4】:
        def prime(i):
        """ This function finds whether a number is prime or not?"""
        val=False
        for n in range(2,i):
            if i%n==0:
                    break;
        else:
            val=True
        return val
        for x in range(2,1000):
        if prime(x)==True & prime(x+2)==True:
            print("{} and {} are prime twins".format(x,x+2))
        

        这应该会有所帮助。首先我定义一个函数,不管它是否是素数。接下来,我使用该函数通过比较 x 和 x+2 来找到一个范围内的孪生素数。 x 是该范围内的每个数字。

        【讨论】:

        • 这有什么帮助? OP 希望优化他的解决方案,使其更短、更快。虽然你的更短,但在我的系统上,OP 的代码需要几分之一秒来处理多达 100,000 个,但你的需要一分半钟!您是否花时间了解 OP 的问题、代码和任何现有答案?谁赞成这个,为什么?
        猜你喜欢
        • 1970-01-01
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-23
        • 1970-01-01
        • 1970-01-01
        • 2017-07-15
        相关资源
        最近更新 更多