0

I have this program that is supposed to search for perfect numbers. (X is a perfect number if the sum of all numbers that divide X, divided by 2 is equal to X)
sum/2 = x

Now It has found the first four, which were known in Ancient Greece, so it's not really a anything awesome.

The next one should be 33550336.

I know it is a big number, but the program has been going for about 50 minutes, and still hasn't found 33550336.

Is it because I opened the .txt file where I store all the perfect numbers while the program was running, or is it because I don't have a PC fast enough to run it*, or because I'm using Python?

*NOTE: This same PC factorized 500 000 in 10 minutes (while also running the perfect number program and Google Chrome with 3 YouTube tabs), also using Python.

Here is the code to the program:

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
false
  • 10,264
  • 13
  • 101
  • 209
Gloripaxis
  • 1,026
  • 1
  • 9
  • 9
  • Your question doesn't really have anything to do with your problem. However, no one can help you without seeing some code. – Burhan Khalid Apr 26 '13 at 22:50
  • How do you mean? I opened the file where all the perfect numbers are stored, and I am wondering is that the reason for the app not finding anything else. I had to explain what perfect numbers are, not everyone knows what is a perfect number. I have posted some code to help you. – Gloripaxis Apr 26 '13 at 22:57

3 Answers3

5

The next one should be 33550336.

Your code (I fixed the indentation so that it does in principle what you want):

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

does i divisions to find the divisors of i.

So to find the perfect numbers up to n, it does

2 + 3 + 4 + ... + (n-1) + n = n*(n+1)/2 - 1

divisions in the for loop.

Now, for n = 33550336, that would be

Prelude> 33550336 * (33550336 + 1) `quot` 2 - 1
562812539631615

roughly 5.6 * 1014 divisions.

Assuming your CPU could do 109 divisions per second (it most likely can't, 108 is a better estimate in my experience, but even that is for machine ints in C), that would take about 560,000 seconds. One day has 86400 seconds, so that would be roughly six and a half days (more than two months with the 108 estimate).

Your algorithm is just too slow to reach that in reasonable time.

If you don't want to use number-theory (even perfect numbers have a very simple structure, and if there are any odd perfect numbers, those are necessarily huge), you can still do better by dividing only up to the square root to find the divisors,

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

that only needs about 1.3 * 1011 divisions and should find the fifth perfect number in a couple of hours.

Without resorting to the explicit formula for even perfect numbers (2^(p-1) * (2^p - 1) for primes p such that 2^p - 1 is prime), you can speed it up somewhat by finding the prime factorisation of i and computing the divisor sum from that. That will make the test faster for all composite numbers, and much faster for most,

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

would take an estimated 40 minutes on my machine.

Not a bad estimate:

$ time python fastperf.py 
6
28
496
8128
33550336

real    36m4.595s
user    36m2.001s
sys     0m0.453s
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
0

It is very hard to try and deduce why this has happened. I would suggest that you run your program either under a debugger and test several iteration manually to check if the code is really correct (I know you have already calculated 4 numbers but still). Alternatively it would be good to run your program under a python profiler just to see if it hasn't accidentally blocked on a lock or something.

LordDoskias
  • 3,121
  • 3
  • 30
  • 44
  • I would very gladly say that you are right, however as I am relatively new to programming, more so programming in Python, I have absolutely no idea what you are talking about. What exactly does 'blocked on a lock' mean? – Gloripaxis Apr 26 '13 at 22:58
  • 1
    @user2154354 - Lord is talking about the possibility that your program could be **`stuck`** waiting for access to a file or other resource that is **`locked`** by another program or process. – Kevin Fegan Apr 26 '13 at 23:20
0

It is possible, but not likely that this is an issue related to you opening the file while it is running. If it was an issue, there would have probably been some error message and/or program close/crash.

I would edit the program to write a log-type output to a file every so often. For example, everytime you have processed a target number that is an even multiple of 1-Million, write (open-append-close) the date-time and current-number and last-success-number to a log file.

You could then Type the file once in a while to measure progress.

Kevin Fegan
  • 1,292
  • 1
  • 16
  • 29