diff --git a/src/gleam/float.gleam b/src/gleam/float.gleam index 8ca382ee..d72982fc 100644 --- a/src/gleam/float.gleam +++ b/src/gleam/float.gleam @@ -433,6 +433,40 @@ fn do_product(numbers: List(Float), initial: Float) -> Float { @external(javascript, "../gleam_stdlib.mjs", "random_uniform") pub fn random() -> Float +/// Computes the modulo of an float division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// modulo(13.3, by: 3.3) +/// // -> Ok(0.1) +/// ``` +/// +/// ```gleam +/// modulo(-13.3, by: 3.3) +/// // -> Ok(3.2) +/// ``` +/// +/// ```gleam +/// modulo(13.3, by: -3.3) +/// // -> Ok(-3.2) +/// ``` +/// +/// ```gleam +/// modulo(-13.3, by: -3.3) +/// // -> Ok(-0.1) +/// ``` +/// +pub fn modulo(dividend: Float, by divisor: Float) -> Result(Float, Nil) { + case divisor { + 0.0 -> Error(Nil) + _ -> Ok(dividend -. floor(dividend /. divisor) *. divisor) + } +} + /// Returns division of the inputs as a `Result`. /// /// ## Examples diff --git a/test/gleam/float_test.gleam b/test/gleam/float_test.gleam index 4e881f1d..f3d39027 100644 --- a/test/gleam/float_test.gleam +++ b/test/gleam/float_test.gleam @@ -3,6 +3,7 @@ import gleam/int import gleam/iterator import gleam/list import gleam/order +import gleam/result import gleam/should pub fn parse_test() { @@ -371,6 +372,31 @@ pub fn random_test() { |> should.be_true } +pub fn modulo_test() { + float.modulo(13.3, by: 0.0) + |> should.equal(Error(Nil)) + + float.modulo(13.3, by: 3.3) + |> result.unwrap(or: 0.0) + |> float.loosely_equals(with: 0.1, tolerating: 0.001) + |> should.be_true + + float.modulo(-13.3, by: 3.3) + |> result.unwrap(or: 0.0) + |> float.loosely_equals(with: 3.2, tolerating: 0.001) + |> should.be_true + + float.modulo(13.3, by: -3.3) + |> result.unwrap(or: 0.0) + |> float.loosely_equals(with: -3.2, tolerating: 0.001) + |> should.be_true + + float.modulo(-13.3, by: -3.3) + |> result.unwrap(or: 0.0) + |> float.loosely_equals(with: -0.1, tolerating: 0.001) + |> should.be_true +} + pub fn divide_test() { float.divide(1.0, 1.0) |> should.equal(Ok(1.0))