Clojure: Perfect Language for Perfect Numbers

In number theory, a perfect number is a positive integer that is equal to the sum of its proper positive divisors, that is, the sum of its positive divisors excluding the number itself (also known as its aliquot sum). Equivalently, a perfect number is a number that is half the sum of all of its positive divisors (including itself) i.e. σ1(n) = 2n.

After watching a Functional Thinking talk by Neal Ford, needed to give it some clojure…

(ns perfect-numbers.core)
 
(defn is-factor? [divident divisor] 
   (zero? (mod divident divisor)))
 
(defn factors [number] 
   (distinct                                      ; no dups for perfect squares (e.g. 16, 64, 49)
      (mapcat #(when (is-factor? number %)        ; when a factor is found
         [(/ number %) %])                        ; return a pair of [number/factor, factor]
         (range 1 (inc (Math/sqrt number)) 1))))  ; go upto a (sqrt number) inclusively
 
(defn perfect? [number]
   (= (reduce + (factors number)) (* 2 number)))  ; check if sum of factors = 2*N
 
(def perfect-numbers
   (filter perfect? (nnext (range))))

Let’s give it a spin:

$ lein repl
REPL started; server listening on localhost port 61776
user=> (use 'perfect-numbers.core)
nil
user=> (take 4 perfect-numbers)
(6 28 496 8128)
user=>

Let’s time it:

user=> (time (doall (take 4 perfect-numbers)))
(6 28 496 8128)
"Elapsed time: 0.123 msecs"
user=> 
user=> (time (doall (take 5 perfect-numbers)))
(6 28 496 8128 33550336)
"Elapsed time: 1.8967263496E7 msecs" ( 5 hours 16 minutes )