HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Finding next perfect number - brute force

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numberforceperfectnextfindingbrute

Problem

A “perfect number” is defined as a number equal to the sum of all its factors less than itself. For example, the first perfect number is 6, because its factors are 1, 2, 3, and 6, and 1+2+3=6. The second perfect number is 28, because 1+2+4+7+14=28. What is the third perfect number? Write a procedure (next-perf n) that tests numbers starting with n and continuing with n+1, n+2, etc. until a perfect number is found. Then you can evaluate (next-perf 29) to solve the problem. Hint: you’ll need a sum-of-factors subprocedure.

[Note: If you run this program when the system is heavily loaded, it may take half an hour to compute the answer! Try tracing helper procedures to make sure your program is on track, or start by computing (next-perf 1) and see if you get 6.]

Source

I am aware of Euclid's algorithm for solving this problem, but with the "n+1,n+2" part of the problem statement I think I shouldn't do that. So I did it in a brute force way.

(define (nextPerf n)
    (define (sumOfFactors a)
        (cond ((= n a) 0)
            ((= (remainder n a) 0) (+ a (sumOfFactors (+ a 1))))
        (else (sumOfFactors (+ a 1)))))
    (if (= (sumOfFactors 1) n) n
        (nextPerf (+ n 1))))


Is this good code? How can I make it better?

Solution

You get:


Hint: you’ll need a sum-of-factors subprocedure.

So I would make sum-of-factors a separate procedure. It's a little confusing as is, since sumOfFactors takes a single argument - and that argument isn't the number whose factors you're summing. That is:

(define (sum-of-factors n)
    ...)

(define (next-perf n)
    (if (= (sum-of-factors n) n)
        n
        (next-perf (+ n 1)))


Note that hyphenated-name is the preferred syntax for function names, as opposed to camelCase.

Once we're there, you can write sum-of-factors to do the looping:

(define (sum-of-factors n)
    (define (add-factor fac) (if (= (remainder n fac) 0) fac 0))
    (define (accum fac) (if (= fac n) 0 (+ (add-factor fac) (accum (+ 1 fac)))
    (accum 1))


I split it up into a few more bite-size functions. I find that helps readability.

In Racket (which I guess isn't up for discussion), you can do the latter way better since there's an in-range procedure that gives you want you need:

(define (sum-of-factors n)
    (for/sum ([fac (in-range 1 (- n 1))])
        (if (= (remainder n fac) 0) fac 0))))


Don't think there's a Scheme equivalent unfortunately, so maybe this is more of a tease than an answer.

Code Snippets

(define (sum-of-factors n)
    ...)

(define (next-perf n)
    (if (= (sum-of-factors n) n)
        n
        (next-perf (+ n 1)))
(define (sum-of-factors n)
    (define (add-factor fac) (if (= (remainder n fac) 0) fac 0))
    (define (accum fac) (if (= fac n) 0 (+ (add-factor fac) (accum (+ 1 fac)))
    (accum 1))
(define (sum-of-factors n)
    (for/sum ([fac (in-range 1 (- n 1))])
        (if (= (remainder n fac) 0) fac 0))))

Context

StackExchange Code Review Q#114455, answer score: 4

Revisions (0)

No revisions yet.