Question
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a \neq b, then a and b are an amicable pair and each of a and b are called amicable numbers.
For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.
Evaluate the sum of all the amicable numbers under 10000.
Clojure
#!/usr/bin/env clojure
(defn divisors [n]
(filter #(zero? (mod n %)) (range 1 (+ 1 (/ n 2)))))
(defn d [n]
(reduce + (divisors n)))
(defn amicable? [a b]
(and (not (= a b)) (= (d a) b) (= (d b) a)))
(println (reduce + (filter #(amicable? % (d %)) (range 10000))))$ time clojure amicable.clj
real 0m5.683s
user 0m7.039s
sys 0m0.506sHaskell
divisors :: Integer -> [Integer]
divisors n = [x | x <- [1..(div n 2)], n `mod` x == 0]
d :: Integer -> Integer
d = sum . divisors
isAmicable :: Integer -> Bool
isAmicable n = n /= x && d x == n where x = d n
main :: IO ()
main = print $ sum $ filter isAmicable [1..10000]$ ghc -O2 -o amicable amicable.hs
$ time ./amicable
real 0m1.439s
user 0m1.438s
sys 0m0.000sRuby
#!/usr/bin/env ruby
require 'mathn'
class Integer
def divisors
return [1] if self == 1
primes, powers = self.prime_division.transpose
exponents = powers.map{|i| (0..i).to_a}
divisors = exponents.shift.product(*exponents).map do |powers|
primes.zip(powers).map{|prime, power| prime ** power}.inject(:*)
end
divisors.sort.take divisors.length - 1
end
def amicable?(n=self.divisors.reduce(:+))
n != self && n.divisors.reduce(:+) == self
end
end
puts (1..10000).find_all { |n| n.amicable? }.reduce(:+)$ time ruby amicable.rb
real 0m0.345s
user 0m0.345s
sys 0m0.000sRust
fn sum_divisors(n: u64) -> u64 {
let mut result = 0;
let max = (n as f64).sqrt() as u64;
for i in 2..max {
if n % i == 0 {
let x = n / i;
if x == i {
result += i;
} else {
result += i + x;
}
}
}
1 + result
}
fn main() {
let sum: u64 = (1..10000)
.filter(|&n| {
let x = sum_divisors(n);
(n != x) && (sum_divisors(x) == n)
})
.sum();
println!("{}", sum);
}$ rustc -C target-cpu=native -C opt-level=3 -o amicable amicable.rs
$ time ./amicable
real 0m0.006s
user 0m0.006s
sys 0m0.000s