Current section
Files
Jump to
Current section
Files
lib/integer.ex
defmodule A.Integer do
@moduledoc ~S"""
Some extra helper functions for working with integers,
that are not in the core `Integer` module.
"""
@thousand_decimals 3
@compile {:inline, div_rem: 2, decimal_format: 2, do_format: 2, format_loop: 3}
@doc """
Returns both the result of `div/2` and `rem/2` at once.
## Examples
iex> A.Integer.div_rem(7, 3)
{2, 1}
iex> A.Integer.div_rem(-99, 2)
{-49, -1}
iex> A.Integer.div_rem(100, 0)
** (ArithmeticError) bad argument in arithmetic expression
"""
@spec div_rem(integer, pos_integer | neg_integer) :: {integer, integer}
def div_rem(dividend, divisor) do
{div(dividend, divisor), rem(dividend, divisor)}
end
@doc """
Format integers for humans, with thousand separators.
## Examples
iex> A.Integer.decimal_format(1_234_567)
"1,234,567"
iex> A.Integer.decimal_format(-123)
"-123"
iex> A.Integer.decimal_format(-1_234, separator: ?_)
"-1_234"
"""
def decimal_format(integer, opts \\ []) when is_integer(integer) and is_list(opts) do
separator = Keyword.get(opts, :separator, ?,)
integer
|> do_format(separator)
|> IO.iodata_to_binary()
end
defp do_format(integer, separator) when integer < 0 do
[?- | do_format(-integer, separator)]
end
defp do_format(integer, separator) do
integer
|> Integer.to_string()
|> format_loop([], separator)
end
defp format_loop(integer_string, acc, separator) do
case byte_size(integer_string) - @thousand_decimals do
offset when offset > 0 ->
{rest, chunk} = String.split_at(integer_string, offset)
format_loop(rest, [separator, chunk | acc], separator)
_ ->
[integer_string | acc]
end
end
end