RosettaCodeData/Task/Aliquot-sequence-classifica.../Elixir/aliquot-sequence-classifica...

51 lines
1.6 KiB
Plaintext

defmodule Proper do
def divisors(1), do: []
def divisors(n), do: [1 | divisors(2,n,:math.sqrt(n))] |> Enum.sort
defp divisors(k,_n,q) when k>q, do: []
defp divisors(k,n,q) when rem(n,k)>0, do: divisors(k+1,n,q)
defp divisors(k,n,q) when k * k == n, do: [k | divisors(k+1,n,q)]
defp divisors(k,n,q) , do: [k,div(n,k) | divisors(k+1,n,q)]
end
defmodule Aliquot do
def sequence(n, maxlen\\16, maxterm\\140737488355328)
def sequence(0, _maxlen, _maxterm), do: "terminating"
def sequence(n, maxlen, maxterm) do
{msg, s} = sequence(n, maxlen, maxterm, [n])
{msg, Enum.reverse(s)}
end
defp sequence(n, maxlen, maxterm, s) when length(s) < maxlen and n < maxterm do
m = Proper.divisors(n) |> Enum.sum
cond do
m in s ->
case {m, List.last(s), hd(s)} do
{x,x,_} ->
case length(s) do
1 -> {"perfect", s}
2 -> {"amicable", s}
_ -> {"sociable of length #{length(s)}", s}
end
{x,_,x} -> {"aspiring", [m | s]}
_ -> {"cyclic back to #{m}", [m | s]}
end
m == 0 -> {"terminating", [0 | s]}
true -> sequence(m, maxlen, maxterm, [m | s])
end
end
defp sequence(_, _, _, s), do: {"non-terminating", s}
end
Enum.each(1..10, fn n ->
{msg, s} = Aliquot.sequence(n)
:io.fwrite("~7w:~21s: ~p~n", [n, msg, s])
end)
IO.puts ""
[11, 12, 28, 496, 220, 1184, 12496, 1264460, 790, 909, 562, 1064, 1488, 15355717786080]
|> Enum.each(fn n ->
{msg, s} = Aliquot.sequence(n)
if n<10000000, do: :io.fwrite("~7w:~21s: ~p~n", [n, msg, s]),
else: :io.fwrite("~w: ~s: ~p~n", [n, msg, s])
end)