views:

395

answers:

12

The algorithm should check a given number and return 'true' if it is a perfect number or 'false' if it is not.

The wikipedia definition of a perfect number:

In mathematics, a perfect number is a positive integer that is the sum of its proper positive divisors, that is, the sum of the positive divisors excluding the number itself. Equivalently, a perfect number is a number that is half the sum of all of its positive divisors (including itself), or σ(n) = 2n.itself), or σ(n) = 2n.

The task is to solve this in the least amount of characters. Bonus points if it can check an arbitrarily high number.

+1  A: 

Clojure - 304 characters

My attempt in clojure, it can go as high as 1.44115188*10^17. I'm new to lisp so certainly someone can do better :)

(defn pow [n p] (loop [cnt 1 base n] (if (= cnt p) base (recur (inc cnt) (* base n)))))
(defn perfect [p] (* (pow 2 (dec p)) (dec (pow 2 p))))
(defn perfect? [n] (reduce (fn [a b] (or a b)) (map (fn [p] (= n (perfect p))) [2 3 5 7 11 13 17 19 23 29])))
Swizec Teller
You should be able to do better by just shortening the variable names, at the cost of readability. For example, "perfect" is a seven-letter word you use three times. Change it to a single letter and you're 18 characters better.
David Thornley
+1  A: 

Python - 48 characters

lambda n:n==sum(i for i in range(1,n) if n%i<1)

relet
ooh just beat me :pok down to 45 :)
gnibbler
+3  A: 

Python - 45 chars

lambda n:n==sum(i*(n%i<1)for i in range(1,n))
gnibbler
No, you just beat me. I had that same idea before the refresh. :D
relet
+5  A: 

Golfscript - 17 chars

~.:@,{.@\%1<*+}*=

explanation

~  evals the input, turning it into an int
.  pushes another copy of the input onto the stack
:@ store it in a variable called @
,  push a list from 0...@-1 onto the stack
{  loop through the list of factors (the 0 isn't part of the loop see here)
.  duplicate the list index                                             \
@  push the number onto the stack                                        \
\  swap the top two items                                                 \
%  take mod of those two items and push back onto the stack                \
1< less than one? (zero?) push onto the stack                               \
*  multiply, so we have zero or the factor depending whether it divides      \
+  add to the previous item (for the first loop, this is the previous item is 0 )
}  end of the loop
*  this is a fold or reduce across the loop
=  does the sum equal the original number?
gnibbler
A: 

PHP5.3 89 characters

function($n){return $n==array_reduce(range(1,$n),function($a,$b) use($n){$a+=$n%$b?0:$b;});}
Mike Sherov
A: 

C# 45 characters.

Enumerable.Range(1,x-1).Sum(n=>x%n==0?n:0)==x;
Jon Hanna
I'm tempted to do a really perverse XSLT too.
Jon Hanna
A: 

F# 50 chars

Too bad F# doesn't have a ternary conditional operator. The shortest solution I found is to filter the proper divisors first and then sum them.

let s n=n=Seq.sum(Seq.filter((=)0<<(%)n){1..n-1})

//long version
let IsPerfect n =
    let properDivisors = 
        {1..n-1} |> Seq.filter (fun d -> n%d = 0)
    n = Seq.sum properDivisors 

//For 3 more characters you can use bigints (suffix I)    
let t n=n=Seq.sum(Seq.filter((=)0I<<(%)n){1I..n-1I})

Example in F# interactive:

> [1..10000] |> List.filter s;;
val it : int list = [6; 28; 496; 8128]
cfern
A: 

Ruby - 48 chars

def f(n)n==(1...n).inject{|s,i|s+(n%i<1?i:0)}end

Ruby - 49 chars

def f(n)n==(1...n).select{|i|n%i<1}.inject(:+)end

Ruby - 50 chars

def f(n)n==(1...n).map{|i|n%i<1?i:0}.inject(:+)end
gnibbler
A: 

Perl 49 51 75 characters

Last edit: Of course I can just use pop instead of shift for a one-argument @_ list...

sub r{$a=pop;$a%$_ or$t+=$_ for(1..$a-1);$t==$a}

Explanation:

$a=pop;

Extracts the sole argument.

for(1..$a-1)

(This is further down) The second statement applies over this range, from 1 to one less than the input.

$a%$_ or

Takes the mod of $a and $_ (the loop counter alias). If that is 0 (meaning $_ is a factor of $a)...

$t+=$_

...then the total is incremented by that amount.

$t==$a

If the total is the input, it's a perfect number. A true or false value is returned.

Platinum Azure
A: 

Mathematica 20 chars

Total@Divisors@#=2#&

Note > I am having trouble to get SO editor to accept the \Equal Unicode from Mathematica. If anyone knows how to do it, please edit.

belisarius
+1  A: 

Perl - 45 chars

sub p{map$s+=$n%$_?0:$_,1..($n=pop)-1;$s==$n}
M42
A: 

Haskell - 40 chars

(==)n$sum$filter(\x->n`mod`x==0)[1..n-1]
stusmith