diff --git a/lib/elixir/lib/float.ex b/lib/elixir/lib/float.ex index 5bbf4a817a3..69532c3aa9a 100644 --- a/lib/elixir/lib/float.ex +++ b/lib/elixir/lib/float.ex @@ -125,4 +125,29 @@ defmodule Float do end end + @doc """ + Rounds a floating point value to an arbitrary number of fractional digits + (between 0 and 15) with an optional midpoint rounding mode (:up or :down, + defaults to :up). + + ## Examples + + iex> Float.round(5.5675, 3) + 5.568 + iex> Float.round(5.5675, 3, :down) + 5.567 + iex> Float.round(-5.5675, 3) + -5.567 + iex> Float.round(-5.5675, 3, :down) + -5.568 + """ + @spec round(float, integer, atom | nil) :: float + def round(number, precision, midpoint_rounding // :up) when is_float(number) and is_integer(precision) and precision in 0..15 do + # Default to :up if anything but :down is provided for midpoint rounding mode + case midpoint_rounding do + :down -> Kernel.round(Float.floor(number * :math.pow(10, precision))) / :math.pow(10, precision) + _ -> Kernel.round(Float.ceil(number * :math.pow(10, precision))) / :math.pow(10, precision) + end + end + end diff --git a/lib/elixir/test/elixir/float_test.exs b/lib/elixir/test/elixir/float_test.exs index 8d100757284..c42393b0cba 100644 --- a/lib/elixir/test/elixir/float_test.exs +++ b/lib/elixir/test/elixir/float_test.exs @@ -57,4 +57,17 @@ defmodule FloatTest do assert Float.ceil(-0.32453e-10) === 0 assert Float.ceil(1.32453e-10) === 1 end + + test :round do + assert Float.round(5.5675, 3) === 5.568 + assert Float.round(5.5675, 3, :down) === 5.567 + assert Float.round(5.5, 3) === 5.5 + assert Float.round(5.5e-10, 10) === 6.0e-10 + assert Float.round(5.5e-10, 10, :down) === 5.0e-10 + assert Float.round(5.5e-10, 8) === 1.0e-8 + assert Float.round(5.5e-10, 8, :down) === 0.0 + assert Float.round(5.0, 0) === 5.0 + assert Float.round(-1.3456, 3) === -1.345 + assert Float.round(-1.3456, 3, :down) === -1.346 + end end