Created
May 19, 2023 16:32
-
-
Save somoza/17dbde7b09c95573a1350662fafb7e5d to your computer and use it in GitHub Desktop.
Base number conversion using Elixir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule BaseConverter do | |
def convert(_digits, _input_base, output_base) when output_base < 2, | |
do: {:error, "output base must be >= 2"} | |
def convert(_digits, input_base, _output_base) when input_base < 2, | |
do: {:error, "input base must be >= 2"} | |
def convert(digits, input_base, 10) do | |
maybe_convert_to_base_10(digits, input_base, is_valid_list_of_ints?(digits, input_base)) | |
end | |
def convert(digits, 10, output_base) do | |
maybe_convert_to_base_x(digits, output_base, is_valid_list_of_ints?(digits, 10)) | |
end | |
def convert(digits, input_base, output_base) do | |
with true <- is_valid_list_of_ints?(digits, input_base), | |
base_10_list <- to_base_10(digits, input_base), | |
base_10_string <- Enum.join(base_10_list), | |
base_10_int <- String.to_integer(base_10_string) do | |
{:ok, to_base_x(base_10_int, output_base)} | |
else | |
error -> error | |
end | |
end | |
defp to_base_10(digits, base) do | |
{_, decimal} = | |
Enum.reduce(digits, {length(digits) - 1, 0}, fn digit, {length_digits, result} -> | |
{length_digits - 1, result + digit * :math.pow(base, length_digits)} | |
end) | |
trunc(decimal) |> Integer.digits() | |
end | |
defp to_base_x(number, base, acc \\ []) do | |
division = div(number, base) | |
reminder = rem(number, base) | |
if number >= base do | |
to_base_x(division, base, acc ++ [Kernel.to_string(reminder)]) | |
else | |
(acc ++ [Kernel.to_string(reminder)]) | |
|> Enum.map(fn digit -> | |
{int, _} = Integer.parse(digit) | |
int | |
end) | |
|> Enum.reverse() | |
end | |
end | |
defp is_valid_list_of_ints?(digits, base), | |
do: digits == Enum.filter(digits, &(&1 >= 0 and &1 < base)) | |
defp maybe_convert_to_base_10(digits, input_base, true), | |
do: {:ok, to_base_10(digits, input_base)} | |
defp maybe_convert_to_base_10(_, _, false), | |
do: {:error, "all digits must be >= 0 and < input base"} | |
defp maybe_convert_to_base_x(digits, output_base, true), | |
do: {:ok, to_base_x(digits |> Enum.join() |> String.to_integer(), output_base)} | |
defp maybe_convert_to_base_x(_, _, false), | |
do: {:error, "all digits must be >= 0 and < input base"} | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment