0

How can I generate all perfect numbers between 1 and 100?

A perfect number is a positive integer that is equal to the sum of its proper divisors. For example, 6(=1+2+3) is a perfect number.

Tung
  • 5,334
  • 1
  • 34
  • 41
FRANK
  • 1
  • 1
  • 2

3 Answers3

3

So I suspect Frank is looking for an answer in Prolog, and yes it does smell rather homeworky...

For fun I decided to write up my answer. It took me about 50 lines.

So here is the outline of what my predicates look like. Maybe it will help get you thinking the Prolog way.

  is_divisor(+Num,+Factor)

  divisors(+Num,-Factors)
  divisors(+Num,+N,-Factors)

  sum(+List,-Total)
  sum(+List,+Sofar,-Total)

  is_perfect(+N)

  perfect(+N,-List)

The + and - are not really part of the parameter names. They are a documentation clue about what the author expects to be instantiated.(NB) "+Foo" means you expect Foo to have a value when the predicate is called. "-Foo" means you expect to Foo to be a variable when the predicate is called, and give it a value by the time it finishes. (kind of like input and output, if it helps to think that way)

Whenever you see a pair of predicates like sum/2 and sum/3, odds are the sum/2 one is like a wrapper to the sum/3 one which is doing something like an accumulator.

I didn't bother to make it print them out nicely. You can just query it directly in the Prolog command line:

?- perfect(100,L).
L = [28, 6] ;
fail.

Another thing that might be helpful, that I find with Prolog predicates, is that there are generally two kinds. One is one that simply checks if something is true. For this kind of predicate, you want everything else to fail. These don't tend to need to be recursive.

Others will want to go through a range (of numbers or a list) and always return a result, even if it is 0 or []. For these types of predicates you need to use recursion and think about your base case.

HTH.

NB: This is called "mode", and you can actually specify them and the compiler/interpreter will enforce them, but I personally just use them in documentation. Also tried to find a page with info about Prolog mode, but I can't find a good link. :(

Community
  • 1
  • 1
pfctdayelise
  • 5,115
  • 3
  • 32
  • 52
1

I'm not sure if this is what you were looking for, but you could always just print out "6, 28"...

Clueless
  • 3,984
  • 1
  • 20
  • 27
  • Oh come on, I always use the preprocessor in my head to do my programming whenever I can. I rather like the elegance of this one. :) – Clueless Oct 12 '09 at 16:09
  • In TDD, this would be great. Dev1: You need to find all perfect numbers up to 100. Dev2: Codes return "6, 28, ..." Dev2: Better change the test to "Find all perfect numbers between numbers n and m" – cjk Oct 12 '09 at 16:58
  • In spite of the "elegance" proposed here, at least there are not that many perfect numbers..at least that's what we may think considering that numbers just dont end :). – JonH Oct 12 '09 at 16:59
  • 1
    6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128 would cover all integers through 64 bits, and run in O(1) time. I think thats a pretty fair program :) http://www.research.att.com/~njas/sequences/A000396 – Clueless Oct 12 '09 at 17:13
  • It's still not a program, its an output. I could cout the first 5000 prime numbers when asked for 1000 and still fail as it is not a solution to the problem. It is more of a problem then a solution. – JonH Oct 12 '09 at 17:26
1

Well looks like you need to loop up until n/2 that is 1/2 of n. Divide the number and if there is no remainder then you can include it in the total, once you have exhausted 1/2 of n then you check if your total added = the number you are testing.

For instance:

#include "stdafx.h"
#include "iostream"
#include "math.h"
using namespace std;

int main(void)
{
    int total=0;

    for(int i = 1; i<=100; i++)
    {
        for( int j=1; j<=i/2; j++)
        {
            if (!(i%j))
            {
                total+=j;
            }
        }
        if (i==total)
        {
            cout << i << " is perfect";
        }
        //it works
        total=0;
    }

    return 0;
}
raven
  • 18,004
  • 16
  • 81
  • 112
JonH
  • 32,732
  • 12
  • 87
  • 145
  • By the way it could be optimized folks I know, but it does the job in readable code :) – JonH Oct 12 '09 at 15:55
  • BTW this was done in C++, you could do it in C#, VB.net or any other language just follow the logic behind it. First loop up until and including 100 because you stated you are looking for any perfect number up till 100. Then the second loop is used as a divisor and reaches up till i/2 that is 1/2 of your n. If there is no remainder !(i%j) that means it divides evenly and you can include it in your sum. Otherwise keep looping. Once you kick out of the loop, that is j=i/2 then you simply check if your accumulated total = your original n (i). If they are equal its a perfect number! – JonH Oct 12 '09 at 15:57