我写了这个素数因子化函数:
def prime_factorization(n):
prime_factors = {}
for i in _prime_candidates(n):
if n % i == 0:
prime_factors[i] = 0
while n % i == 0:
n /= i
prime_factors[i] += 1
if n != 1: prime_factors[int(n)] = 1
return prime_factors
def _prime_candidates(n):
yield 2
for i in range(3, int(n**.5)+1, 2):
yield i
我的机器需要大约0.387秒,n = 10 ^ 13。但是如果我复制for循环的内容并在运行实际的for循环之前运行它的数字2,我得到相同的正确结果,但是对于n = 10 ^ 13,运行时间约为0.003秒。您可以在下面看到以下代码:
def prime_factorization(n):
prime_factors = {}
if n % 2 == 0:
prime_factors[2] = 0
while n % 2 == 0:
n /= 2
prime_factors[2] += 1
for i in _prime_candidates(n):
if n % i == 0:
prime_factors[i] = 0
while n % i == 0:
n /= i
prime_factors[i] += 1
if n != 1: prime_factors[int(n)] = 1
return prime_factors
def _prime_candidates(n):
yield 2
for i in range(3, int(n**.5)+1, 2):
yield i
为什么这会带来如此巨大的性能提升?
编辑:我使用的是Python 3.5,并且我使用clock()
模块的time
函数进行基准测试。
答案 0 :(得分:4)
在您的初始版本中,_prime_candidates
传递10 ^ 13,因此它会生成最多为其平方根的候选项。
在你的第二个版本中,_prime_candidates
通过了5 ^ 13,因为2的所有因子都被分开了。它产生的候选人数要少得多。
通过将_prime_candidates
逻辑折叠到prime_factorization
并在找到因子时重新计算上限,您可以获得更好,更全面的改进:
def prime_factorization(n):
prime_factors = {}
factor_multiplicity = 0
while n % 2 == 0:
n //= 2
factor_multiplicity += 1
if factor_multiplicity:
prime_factors[2] = factor_multiplicity
factor_bound = n**.5
candidate = 3
while candidate <= factor_bound:
factor_multiplicity = 0
while n % i == 0:
n //= i
factor_multiplicity += 1
if factor_multiplicity:
prime_factors[candidate] = factor_multiplicity
factor_bound = n**.5
candidate += 2
if n != 1:
prime_factors[n] = 1
return prime_factors
请注意,对于足够大的n
,由于浮点精度的限制,n**.5
的计算最终会生成错误的边界。您可以通过比较candidate * candidate <= n
或使用decimal
模块之类的东西来计算绑定到足够的精度来解决这个问题。
答案 1 :(得分:1)
原因是_prime_candidates
函数内部。
在您的第一个示例中,它会生成所有数字3,5,...,3162277
,并且您尝试将所有这些候选项划分为n
。
在您的第二个示例中,您首先大大减少了n
,因此_prime_candidates
生成了数字3,5,...,34939
。它的数字要少得多。