diff options
author | inoas <mail@inoas.com> | 2022-10-14 10:08:18 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-14 11:08:18 +0100 |
commit | 64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef (patch) | |
tree | 45960022ef31c8e02cd9060446dc71ecf8dfdb1c | |
parent | fe6271001fe8d7458a284bfb5cc8ac2cdf6d93b3 (diff) | |
download | gleam_stdlib-64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef.tar.gz gleam_stdlib-64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef.zip |
Add `int.{remainder, modulo}` (#342)
-rw-r--r-- | CHANGELOG.md | 6 | ||||
-rw-r--r-- | src/gleam/int.gleam | 104 | ||||
-rw-r--r-- | test/gleam/int_test.gleam | 54 |
3 files changed, 158 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 079ad6c..5d42ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ ## v0.24.0 - unreleased -- `string.slice` is now tail recursive and will no longer blog the stack on - large inputs when running on JavaScript. +- `string.slice` is now tail recursive and will no longer exceed the stack size + on large inputs on target JavaScript. +- Added `int.remainder` and `int.modulo` functions which allow safe remainder + and modulo operations the way common languages support them. - Added `int.floor_divide` to complement the truncated `int.divide`. ## v0.23.0 - 2022-09-15 diff --git a/src/gleam/int.gleam b/src/gleam/int.gleam index 295381c..66bdf45 100644 --- a/src/gleam/int.gleam +++ b/src/gleam/int.gleam @@ -502,7 +502,10 @@ pub fn random(boundary_a: Int, boundary_b: Int) -> Int { |> float.round() } -/// Returns division of the inputs as a `Result`. +/// Performs a truncated integer division. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. /// /// ## Examples /// @@ -512,12 +515,105 @@ pub fn random(boundary_a: Int, boundary_b: Int) -> Int { /// /// > divide(1, 0) /// Error(Nil) +/// +/// > divide(5, 2) +/// Ok(2) +/// +/// > divide(-99, 2) +/// Ok(-49) /// ``` /// -pub fn divide(a: Int, by b: Int) -> Result(Int, Nil) { - case b { +pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { 0 -> Error(Nil) - b -> Ok(a / b) + divisor -> Ok(dividend / divisor) + } +} + +/// Computes the remainder of an integer division of inputs as a `Result`. +/// +/// This functions mimicks modulo operation of following languages: +/// C, C#, C++, Go, Java, JavaScript, Kotlin, Nim, PHP, Rust, +/// Scala, Swift, Crystal as well as Erlang's and Elixir's rem operator. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// > int.remainder(3, 2) +/// Ok(1) +/// +/// > int.remainder(1, 0) +/// Error(Nil) +/// +/// > int.remainder(10, -1) +/// Ok(0) +/// +/// > int.remainder(13, by: 3) +/// Ok(1) +/// +/// > int.remainder(-13, by: 3) +/// Ok(-1) +/// +/// > int.remainder(13, by: -3) +/// Ok(1) +/// +/// > int.remainder(-13, by: -3) +/// Ok(-1) +/// ``` +/// +pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> Ok(dividend % divisor) + } +} + +/// Computes the modulo of an integer division of inputs as a `Result`. +/// +/// This functions mimicks modulo operation on following languages: +/// Haskell, Lua, Python, Ruby, as well as Elixir's Integer.mod(). +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// > int.modulo(3, 2) +/// Ok(1) +/// +/// > int.modulo(1, 0) +/// Error(Nil) +/// +/// > int.modulo(10, -1) +/// Ok(0) +/// +/// > int.modulo(13, by: 3) +/// Ok(1) +/// +/// > int.modulo(-13, by: 3) +/// Ok(2) +/// +/// > int.modulo(13, by: -3) +/// Ok(-2) +/// +/// > int.modulo(-13, by: -3) +/// Ok(-1) +/// ``` +/// +pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + _ -> { + let remainder = dividend % divisor + case remainder * divisor < 0 { + True -> Ok(remainder + divisor) + False -> Ok(remainder) + } + } } } diff --git a/test/gleam/int_test.gleam b/test/gleam/int_test.gleam index 26e36ba..87de970 100644 --- a/test/gleam/int_test.gleam +++ b/test/gleam/int_test.gleam @@ -415,13 +415,67 @@ pub fn random_test() { pub fn divide_test() { int.divide(1, 1) |> should.equal(Ok(1)) + int.divide(1, 0) |> should.equal(Error(Nil)) int.divide(0, by: 1) |> should.equal(Ok(0)) + int.divide(1, by: 0) |> should.equal(Error(Nil)) + + int.divide(5, by: 2) + |> should.equal(Ok(2)) + + int.divide(-99, by: 2) + |> should.equal(Ok(-49)) +} + +pub fn remainder_test() { + int.remainder(3, 2) + |> should.equal(Ok(1)) + + int.remainder(1, 0) + |> should.equal(Error(Nil)) + + int.remainder(10, -1) + |> should.equal(Ok(0)) + + int.remainder(13, by: 3) + |> should.equal(Ok(1)) + + int.remainder(-13, by: 3) + |> should.equal(Ok(-1)) + + int.remainder(13, by: -3) + |> should.equal(Ok(1)) + + int.remainder(-13, by: -3) + |> should.equal(Ok(-1)) +} + +pub fn modulo_test() { + int.modulo(3, 2) + |> should.equal(Ok(1)) + + int.modulo(1, 0) + |> should.equal(Error(Nil)) + + int.modulo(10, -1) + |> should.equal(Ok(0)) + + int.modulo(13, by: 3) + |> should.equal(Ok(1)) + + int.modulo(-13, by: 3) + |> should.equal(Ok(2)) + + int.modulo(13, by: -3) + |> should.equal(Ok(-2)) + + int.modulo(-13, by: -3) + |> should.equal(Ok(-1)) } pub fn floor_divide_test() { |