patternMinor
Finding next perfect number - brute force
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.
Is this good code? How can I make it better?
[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
Note that
Once we're there, you can write
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
Don't think there's a Scheme equivalent unfortunately, so maybe this is more of a tease than an answer.
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.