1

I am having issues with calculating perfect numbers in python. Apparently the code is working in VBA so I am sure I am making some mistake in syntax / indentation. Please help!

Here is my code:

Mynum=int(input("How many perfect numbers do you want?: "))

counter=0
k=0
j=2
i=1

while counter<Mynum:
    for i in range (1,j-1):
        if (j%i)==0:
            k=k+1
    if k==j:
        counter=counter+1
        print(i)
    k=0
    j=j+1
cdlane
  • 33,404
  • 4
  • 23
  • 63
ps1495
  • 69
  • 6
  • Assuming your cut&paste is accurate, you do have indentation error on `counter=counter+1` – AChampion Oct 05 '16 at 02:44
  • @AChampion, I've made the pasted code match the linked code and dropped the link. This takes care of the indentation issue, at least. – cdlane Oct 05 '16 at 03:14

2 Answers2

1

Your screenshot code, which is the better of the two, is broken in a couple of ways: your k = k + 1 expression should be k = k + i as you want to sum the factors, not count them; you print(i) when your should print j or k:

Mynum = int(input("How many perfect numbers do you want?: "))

counter = 0
j = 2

while counter < Mynum:
    k = 0

    for i in range (1, j):

        if (j % i) == 0:
            k += i

    if k == j:
        counter += 1

        print(j)

    j += 1

However, in the bigger picture, this is the wrong approach for looking for perfect numbers -- using this method you're not likely to find more than the first four:

How many perfect numbers do you want?: 5
6
28
496
8128

so you might as well just go for those and forget about asking how many the user wants.

An example better approach would be to search for Mersenne primes using a Lucas-Lehmer primality test and when you find one, compute the companion perfect number from that. This doesn't take too much code and will leap frog your current approach.

cdlane
  • 33,404
  • 4
  • 23
  • 63
0

Here's another solution to the perfect number:

import itertools as it

def perfect():
    for n in it.count(1):
        if sum(i for i in range(1, n+1) if n%i == 0) == 2*n:
            yield n

>>> list(it.islice(perfect(), 3))
[6, 28, 496]
100 loops, best of 3: 12.6 ms per loop

Or you can use factors (for a slightly faster solution):

def factors(n):
    for a in range(1, int(n**0.5)+1):
        if n % a:
            continue
        x = n // a
        yield a
        if a != x:
            yield x

def perfect():
    for n in it.count(1):
        if sum(factors(n))==2*n:
            yield n

>>> list(it.islice(perfect(), 3))
[6, 28, 496]
1000 loops, best of 3: 1.43 ms per loop

You can improve this even further using a fast prime number version.
Taking a simple prime generator from How to implement an efficient infinite generator of prime numbers in Python?)

import itertools as it
import functools as ft

def primegen():
    yield 2
    D = {}
    for q in it.count(3, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = q + 2*p
            while x in D:
                x += 2*p
            D[x] = p

def ll(p):   # Lucas-Lehmer
    if p == 2:
        return True
    m = 2**p - 1
    return ft.reduce(lambda s, _: (s**2 - 2) % m, range(3, p+1), 4) == 0

def perfect():
    for p in primegen():
        if ll(p):
            yield (2**p-1)*(2**(p-1))

>>> list(it.islice(perfect(), 3))
[6, 28, 496]
100000 loops, best of 3: 7.94 µs per loop
>>> list(it.islice(perfect(), 10))
[6,
 28,
 496,
 8128,
 33550336,
 8589869056,
 137438691328,
 2305843008139952128,
 2658455991569831744654692615953842176,
 191561942608236107294793378084303638130997321548169216]
1000 loops, best of 3: 613 µs per loop

These get very big very quickly, e.g. the 20th perfect number has 2663 digits.

Community
  • 1
  • 1
AChampion
  • 26,341
  • 3
  • 41
  • 64