aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinoas <mail@inoas.com>2022-10-14 10:08:18 +0000
committerGitHub <noreply@github.com>2022-10-14 11:08:18 +0100
commit64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef (patch)
tree45960022ef31c8e02cd9060446dc71ecf8dfdb1c
parentfe6271001fe8d7458a284bfb5cc8ac2cdf6d93b3 (diff)
downloadgleam_stdlib-64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef.tar.gz
gleam_stdlib-64b810dfd8cc0b9d9dcbbc6919e9f8a5f12a8cef.zip
Add `int.{remainder, modulo}` (#342)
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/gleam/int.gleam104
-rw-r--r--test/gleam/int_test.gleam54
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() {