diff --git a/lib/elixir/lib/integer.ex b/lib/elixir/lib/integer.ex index 11baf4985a..25b658cd54 100644 --- a/lib/elixir/lib/integer.ex +++ b/lib/elixir/lib/integer.ex @@ -172,6 +172,35 @@ defmodule Integer do end end + @doc """ + Performs a ceiled integer division. + + Raises an `ArithmeticError` exception if one of the arguments is not an + integer, or when the `divisor` is `0`. + + This function performs a *ceiled* integer division, which means that + the result will always be rounded towards positive infinity. + + ## Examples + + iex> Integer.ceil_div(5, 2) + 3 + iex> Integer.ceil_div(6, -4) + -1 + iex> Integer.ceil_div(-99, 2) + -49 + + """ + @doc since: "1.20.0" + @spec ceil_div(integer, neg_integer | pos_integer) :: integer + def ceil_div(dividend, divisor) do + if not :erlang.xor(dividend < 0, divisor < 0) and rem(dividend, divisor) != 0 do + div(dividend, divisor) + 1 + else + div(dividend, divisor) + end + end + @doc """ Returns the ordered digits for the given `integer`. diff --git a/lib/elixir/test/elixir/integer_test.exs b/lib/elixir/test/elixir/integer_test.exs index bc52243c27..5069eb58da 100644 --- a/lib/elixir/test/elixir/integer_test.exs +++ b/lib/elixir/test/elixir/integer_test.exs @@ -44,10 +44,14 @@ defmodule IntegerTest do end test "mod/2" do + assert Integer.mod(10, -5) == 0 assert Integer.mod(3, 2) == 1 assert Integer.mod(0, 10) == 0 + assert Integer.mod(0, -5) == 0 assert Integer.mod(30000, 2001) == 1986 + assert Integer.mod(30000, -2001) == -15 assert Integer.mod(-20, 11) == 2 + assert Integer.mod(-55, -22) == -11 end test "mod/2 raises ArithmeticError when divisor is 0" do @@ -56,10 +60,14 @@ defmodule IntegerTest do end test "floor_div/2" do + assert Integer.floor_div(10, -5) == -2 assert Integer.floor_div(3, 2) == 1 assert Integer.floor_div(0, 10) == 0 + assert Integer.floor_div(0, -5) == 0 assert Integer.floor_div(30000, 2001) == 14 + assert Integer.floor_div(30000, -2001) == -15 assert Integer.floor_div(-20, 11) == -2 + assert Integer.floor_div(-55, -22) == 2 end test "floor_div/2 raises ArithmeticError when divisor is 0" do @@ -72,6 +80,26 @@ defmodule IntegerTest do assert_raise ArithmeticError, fn -> Integer.floor_div(20, 1.2) end end + test "ceil_div/2" do + assert Integer.ceil_div(10, -5) == -2 + assert Integer.ceil_div(3, 2) == 2 + assert Integer.ceil_div(0, 10) == 0 + assert Integer.ceil_div(0, -10) == 0 + assert Integer.ceil_div(30000, -2001) == -14 + assert Integer.ceil_div(-20, 11) == -1 + assert Integer.ceil_div(-55, -22) == 3 + end + + test "ceil_div/2 raises ArithmeticError when divisor is 0" do + assert_raise ArithmeticError, fn -> Integer.ceil_div(3, 0) end + assert_raise ArithmeticError, fn -> Integer.ceil_div(-50, 0) end + end + + test "ceil_div/2 raises ArithmeticError when non-integers used as arguments" do + assert_raise ArithmeticError, fn -> Integer.ceil_div(3.0, 2) end + assert_raise ArithmeticError, fn -> Integer.ceil_div(20, 1.2) end + end + test "digits/2" do assert Integer.digits(0) == [0] assert Integer.digits(0, 2) == [0]