【问题标题】:python prime factorization performancepython素数分解性能
【发布时间】:2013-10-19 01:21:59
【问题描述】:

我对 python 比较陌生,我对两个相对简单的代码块的性能感到困惑。第一个函数在给定素数列表的情况下生成数字 n 的素数分解。第二个生成 n 的所有因子的列表。尽管prime_factor 会比factors 快(对于相同的n),但我会认为情况并非如此。我不是在寻找更好的算法,而是想了解为什么prime_factorfactors 慢得多。

def prime_factor(n, primes):
  prime_factors = []
  i = 0
  while n != 1:
      if n % primes[i] == 0:
          factor = primes[i]
          prime_factors.append(factor)
          n = n // factor
      else: i += 1
  return prime_factors

import math
def factors(n):
  if n == 0: return []
  factors = {1, n}
  for i in range(2, math.floor(n ** (1/2)) + 1):
      if n % i == 0:
          factors.add(i)
          factors.add(n // i)
  return list(factors)

使用timeit模块,

{ i:factors(i) for i in range(1, 10000) } 需要 2.5 秒

{ i:prime_factor(i, primes) for i in range(1, 10000) } 需要 17 秒

这让我很惊讶。 factors 检查从 1 到 sqrt(n) 的每个数字,而 prime_factor 只检查素数。如果能帮助我理解这两个函数的性能特征,我将不胜感激。

谢谢

编辑:(对 roliu 的回应) 这是我生成从 2 到 up_to 的素数列表的代码:

def primes_up_to(up_to):
  marked = [0] * up_to
  value = 3
  s = 2
  primes = [2]
  while value < up_to:
      if marked[value] == 0:
          primes.append(value)
          i = value
          while i < up_to:
              marked[i] = 1
              i += value
      value += 2
  return primes

【问题讨论】:

标签: python performance algorithm prime-factoring


【解决方案1】:

在没有看到您用于 primes 的情况下,我们不得不猜测(我们无法运行您的代码)。

但其中很大一部分只是数学:(非常粗略地说)n/log(n) 的质数小于n,并且比sqrt(n) 大得多。所以当你传递一个素数时,prime_factor(n) 会做更多的工作:它在找到第一个素数因子之前会经过O(n/log(n)) 操作(n 本身!),而factors(n)O(sqrt(n)) 操作之后会放弃。

这可能非常重要。例如,sqrt(10000) 只是 100,但有 1229 个质数小于 10000。所以prime_factor(n) 可以需要做 10 倍以上的工作来处理你范围内的大质数。

【讨论】:

  • +1。当然,prime_factor 也可以在达到 sqrt(n) 时停止,因为只能有一个 n 大于其平方根的素数。
  • 是的,事实上,如果提供给 prime_factor 的列表确实只包含按升序列出的素数,它会在终止前检查比因数少的数字;它可以跳过所有的合数!
  • 对某人有帮助 ;-),但原发帖人说他们不是在寻找更好的算法 - 他们只是想知道为什么 给定的代码 表现得如此做。我认为这很清楚;-)
  • @Tim Peters 也许我应该澄清一下,因为我并没有不同意你的回答,只是确保 OP 看到了这个问题。对于像 m=2p 这样的值,其中 p 是素数,prime_factor(n) 首先除以 2,扫描 [3,p] 中的每个素数,直到得出 p 是素数的结论。一旦达到 sqrt(p),他就可以停下来。如果他这样做了,prime_factor(n) 应该与 factor(n) 一样快或快。如果他从小于 sqrt(n) 的最大素数开始,他可以做得更好。
  • 非常感谢,这很有帮助。添加计数器验证了您的预期。 prime_factor 循环了大约 87M 次,factors 只循环了 20M 次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
相关资源
最近更新 更多