Skip to content

Instantly share code, notes, and snippets.

@nwjlyons
Last active June 12, 2023 19:47
Show Gist options
  • Save nwjlyons/e6c2e9ff6835f582f448e9059813b93c to your computer and use it in GitHub Desktop.
Save nwjlyons/e6c2e9ff6835f582f448e9059813b93c to your computer and use it in GitHub Desktop.
Converts a number to a roman numeral.
defmodule RomanNumeral do
@min_number 1
@max_number 3999
@type to_roman_error() :: :less_than_min_number | :greater_than_max_number
@spec to_roman(pos_integer()) :: {:ok, String.t()} | {:error, to_roman_error()}
@doc """
Converts a number to a roman numeral.
## Examples
iex> RomanNumeral.to_roman(1987)
{:ok, "MCMLXXXVII"}
iex> RomanNumeral.to_roman(0)
{:error, :less_than_min_number}
iex> RomanNumeral.to_roman(4000)
{:error, :greater_than_max_number}
"""
def to_roman(number) when number < @min_number, do: {:error, :less_than_min_number}
def to_roman(number) when number > @max_number, do: {:error, :greater_than_max_number}
def to_roman(number) when is_integer(number) do
{[], number}
|> digit("M", 1000)
|> digit("CM", 900)
|> digit("D", 500)
|> digit("CD", 400)
|> digit("C", 100)
|> digit("XC", 90)
|> digit("L", 50)
|> digit("XL", 40)
|> digit("X", 10)
|> digit("IX", 9)
|> digit("V", 5)
|> digit("IV", 4)
|> digit("I", 1)
|> result()
end
defp digit({acc, number}, roman, value) do
q = div(number, value)
r = rem(number, value)
{acc ++ List.duplicate(roman, q), r}
end
defp result({acc, _}), do: {:ok, Enum.join(acc)}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment