下一个应该是 33550336。
您的代码(我修复了缩进,以便它原则上可以执行您想要的操作):
i = 2
a = open("perfect.txt", 'w')
a.close()
while True:
sum = 0
for x in range(1, i+1):
if i%x == 0:
sum += x
if sum / 2 == i:
a = open("perfect.txt", 'a')
a.write(str(i) + "\n")
a.close()
i += 1
做i
除法以找到 的除数i
。
所以要找到完美的数字n
,它确实
2 + 3 + 4 + ... + (n-1) + n = n*(n+1)/2 - 1
for
循环中的分裂。
现在,对于n = 33550336
,那将是
Prelude> 33550336 * (33550336 + 1) `quot` 2 - 1
562812539631615
大约 5.6 * 10 14 个分区。
假设您的 CPU每秒可以进行 10 9分区(很可能不能,根据我的经验,10 8是一个更好的估计,但即使是对于int
C 中的机器 s),这将需要大约 560,000 秒。一天有 86400 秒,所以大约是六天半(10 8估计超过两个月)。
你的算法太慢了,无法在合理的时间内达到。
如果您不想使用数论(即使是完美的数字也有一个非常简单的结构,如果有任何奇完美的数字,它们一定是巨大的),您仍然可以通过只除以平方根来做得更好找到除数,
i = 2
a = open("perfect.txt", 'w')
a.close()
while True:
sum = 1
root = int(i**0.5)
for x in range(2, root+1):
if i%x == 0:
sum += x + i/x
if i == root*root:
sum -= x # if i is a square, we have counted the square root twice
if sum == i:
a = open("perfect.txt", 'a')
a.write(str(i) + "\n")
a.close()
i += 1
这只需要大约 1.3 * 10 11 个除法,并且应该在几个小时内找到第五个完美数字。
无需求助于甚至完美数的显式公式(2^(p-1) * (2^p - 1)
对于素数p
这样的素数),您可以通过找到素数分解并从中计算除数2^p - 1
来加快速度。i
这将使所有合数的测试更快,对大多数人来说更快,
def factorisation(n):
facts = []
multiplicity = 0
while n%2 == 0:
multiplicity += 1
n = n // 2
if multiplicity > 0:
facts.append((2,multiplicity))
d = 3
while d*d <= n:
if n % d == 0:
multiplicity = 0
while n % d == 0:
multiplicity += 1
n = n // d
facts.append((d,multiplicity))
d += 2
if n > 1:
facts.append((n,1))
return facts
def divisorSum(n):
f = factorisation(n)
sum = 1
for (p,e) in f:
sum *= (p**(e+1) - 1)/(p-1)
return sum
def isPerfect(n):
return divisorSum(n) == 2*n
i = 2
count = 0
out = 10000
while count < 5:
if isPerfect(i):
print i
count += 1
if i == out:
print "At",i
out *= 5
i += 1
在我的机器上大约需要 40 分钟。
不错的估计:
$ time python fastperf.py
6
28
496
8128
33550336
real 36m4.595s
user 36m2.001s
sys 0m0.453s