defmodule PerfectNumbers do @doc """ Determine the aliquot sum of the given `number`, by summing all the factors of `number`, aside from `number` itself. Based on this sum, classify the number as: :perfect if the aliquot sum is equal to `number` :abundant if the aliquot sum is greater than `number` :deficient if the aliquot sum is less than `number` """ @spec classify(number :: integer) :: {:ok, atom} | {:error, String.t()} def classify(number) when number <= 0, do: {:error, "Classification is only possible for natural numbers."} def classify(1), do: {:ok, :deficient} def classify(number) do sum = number |> divisors() |> Enum.sum() cond do sum == number -> {:ok, :perfect} sum > number -> {:ok, :abundant} sum < number -> {:ok, :deficient} end end defp divisors(number) do for i <- 1..round(number ** 0.5), reduce: [] do acc -> if rem(number, i) == 0, do: [i, div(number, i) | acc], else: acc end |> Enum.uniq() |> Enum.sort() |> Enum.drop(-1) end end