Perfect numbers: Difference between revisions

CoffeeScript
(CoffeeScript)
Line 238:
<lang lisp>(defn perfect? [n]
(= n (reduce + (for [i (range 1 n) :when (= 0 (mod n i))] i))))</lang>
 
=={{header|CoffeeScript}}==
Optimized version, for fun.
<lang coffeescript>
is_perfect_number = (n) ->
do_factors_add_up_to n, 2*n
do_factors_add_up_to = (n, desired_sum) ->
# We mildly optimize here, by taking advantage of
# the fact that the sum_of_factors( (p^m) * x)
# is (1 + ... + p^m-1 + p^m) * sum_factors(x) when
# x is not itself a multiple of p.
 
p = smallest_prime_factor(n)
if p == n
return desired_sum == p + 1
 
# ok, now sum up all powers of p that
# divide n
sum_powers = 1
curr_power = 1
while n % p == 0
curr_power *= p
sum_powers += curr_power
n /= p
# if desired_sum does not divide sum_powers, we
# can short circuit quickly
return false unless desired_sum % sum_powers == 0
# otherwise, recurse
do_factors_add_up_to n, desired_sum / sum_powers
 
smallest_prime_factor = (n) ->
for i in [2..n]
return n if i*i > n
return i if n % i == 0
 
#### tests
do ->
# This is pretty fast...
for n in [2..100000]
console.log n if is_perfect_number n
 
# For big numbers, let's just sanity check the known ones.
known_perfects = [
33550336
8589869056
137438691328
]
for n in known_perfects
throw Error("fail") unless is_perfect_number(n)
throw Error("fail") if is_perfect_number(n+1)
</lang>
output
<lang>
> coffee perfect_numbers.coffee
6
28
496
8128
</lang>
 
 
=={{header|Common Lisp}}==
Anonymous user