我编写了以下函数,该函数查找给定自然数的所有除数并将它们作为列表返回:
def FindAllDivisors(x):
divList = []
y = 1
while y <= math.sqrt(x):
if x % y == 0:
divList.append(y)
divList.append(int(x / y))
y += 1
return divList
它的效果非常好,但输入是一个18位数的时候它真的很慢。你对我如何加快它有什么建议吗?
更新:
我有以下方法来检查基于费马小定理的素数:
def CheckIfProbablyPrime(x):
return (2 << x - 2) % x == 1
这种方法在检查单个数字时非常有效,但是我不确定是否应该使用它来编译所有素数直到某个边界。
答案 0 :(得分:23)
您可以通过计算素数因子分解找到数字的所有除数。每个除数必须是因子分解中素数的组合。
如果您有素数列表,这是获得因子分解的简单方法:
def factorize(n, primes):
factors = []
for p in primes:
if p*p > n: break
i = 0
while n % p == 0:
n //= p
i+=1
if i > 0:
factors.append((p, i));
if n > 1: factors.append((n, 1))
return factors
这称为试验分裂。有更有效的方法来做到这一点。有关概述,请参阅here。
现在计算除数非常简单:
def divisors(factors):
div = [1]
for (p, r) in factors:
div = [d * p**e for d in div for e in range(r + 1)]
return div
计算所有除数的效率取决于找到素数(小概述here)和分解算法的算法。对于非常大的数字,后者总是很慢,而且你可以做的不多。
答案 1 :(得分:3)
我建议将math.sqrt(x)
的结果存储在单独的变量中,然后针对它检查y
。否则,它将在while
的每一步重新计算,而math.sqrt
绝对不是轻量级操作。
答案 2 :(得分:1)
我会进行素因子分解,然后计算该结果中的所有除数。
答案 3 :(得分:0)
我不知道是否有很多性能损失,但我很确定转换为int是不必要的。至少在Python 2.7中,int x / int y
返回一个int。