次は 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 が 1 秒あたり 10 9部門を実行できると仮定すると(そうではない可能性が高く、私の経験では 10 8がより適切な見積もりですがint
、C のマシンの場合でも)、約 560,000 秒かかります。1 日は 86400 秒なので、およそ 6 日半 (10 8の見積もりで 2 か月以上) になります。
あなたのアルゴリズムは遅すぎて、妥当な時間内にそれに到達できません。
数論を使いたくない場合 (完全数でさえ非常に単純な構造を持ち、奇数の完全数が存在する場合、それらは必然的に巨大になります)、平方根までのみ分割することで、より良い結果を得ることができます。約数を見つけ、
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の除数しか必要とせず、数時間で 5 番目の完全数を見つける必要があります。
完全数 (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