From cbcee32f22285f2e294a7d69b013d62d4eb15523 Mon Sep 17 00:00:00 2001 From: NicklasXYZ Date: Mon, 11 Mar 2024 23:59:07 +0100 Subject: [PATCH] Add extra tests. Improve Euclidean modulo description. --- gleam.toml | 2 +- manifest.toml | 4 +-- src/gleam_community/maths/arithmetics.gleam | 33 ++++++++++++------- src/gleam_community/maths/combinatorics.gleam | 24 +++++++------- src/gleam_community/maths/elementary.gleam | 3 +- src/gleam_community/maths/piecewise.gleam | 9 ++--- src/gleam_community/maths/predicates.gleam | 3 +- .../maths/arithmetics_test.gleam | 25 +++++++++++--- .../maths/piecewise_test.gleam | 15 +++++++-- 9 files changed, 75 insertions(+), 43 deletions(-) diff --git a/gleam.toml b/gleam.toml index a849b65..a6583ad 100644 --- a/gleam.toml +++ b/gleam.toml @@ -4,7 +4,7 @@ version = "1.0.2" licences = ["Apache-2.0"] description = "A basic maths library" repository = { type = "github", user = "gleam-community", repo = "maths" } -gleam = ">= 0.33.0" +gleam = ">= 0.32.0" [dependencies] gleam_stdlib = "~> 0.34" diff --git a/manifest.toml b/manifest.toml index 7445d63..6c5a157 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,8 +2,8 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" }, - { name = "gleeunit", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "4E75DCF846D653848094169304743DFFB386E3AECCCF611F99ADB735FF4D4DD9" }, + { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, + { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, ] [requirements] diff --git a/src/gleam_community/maths/arithmetics.gleam b/src/gleam_community/maths/arithmetics.gleam index acb0fd1..a238abc 100644 --- a/src/gleam_community/maths/arithmetics.gleam +++ b/src/gleam_community/maths/arithmetics.gleam @@ -30,6 +30,7 @@ //// * [`lcm`](#lcm) //// * [`divisors`](#divisors) //// * [`proper_divisors`](#proper_divisors) +//// * [`int_euclidean_modulo`](#int_euclidean_modulo) //// * **Sums and products** //// * [`float_sum`](#float_sum) //// * [`int_sum`](#int_sum) @@ -102,15 +103,23 @@ fn do_gcd(x: Int, y: Int) -> Int { /// /// /// -/// The function calculates the Euclidian modulo of two numbers -/// The Euclidian_modulo is the modulo that most often is used in maths -/// rather than the normal truncating modulo operation that is used most -/// often in programming through the % operator -/// In contrast to the % operator this function will always return a positive -/// result +/// +/// Given two integers, $$x$$ (dividend) and $$y$$ (divisor), the Euclidean modulo of $$x$$ by $$y$$, +/// denoted as $$x \mod y$$, is the remainder $$r$$ of the division of $$x$$ by $$y$$, such that: +/// +/// \\[ +/// x = q \cdot y + r \quad \text{and} \quad 0 \leq r < |y|, +/// \\] +/// +/// where $$q$$ is an integer that represents the quotient of the division. /// -/// Like the gleam division operator / this will return 0 if one of the -/// parameters are 0 as this is not defined in mathematics +/// The Euclidean modulo function of two numbers, is the remainder operation most commonly utilized in +/// mathematics. This differs from the standard truncating modulo operation frequently employed in +/// programming via the `%` operator. Unlike the `%` operator, which may return negative results +/// depending on the divisor's sign, the Euclidean modulo function is designed to +/// always yield a positive outcome, ensuring consistency with mathematical conventions. +/// +/// Note that like the Gleam division operator `/` this will return `0` if one of the arguments is `0`. /// /// ///
@@ -120,13 +129,13 @@ fn do_gcd(x: Int, y: Int) -> Int { /// import gleam_community/maths/arithmetics /// /// pub fn example() { -/// arithmetics.euclidian_modulo(15, 4) +/// arithmetics.euclidean_modulo(15, 4) /// |> should.equal(3) /// -/// arithmetics.euclidian_modulo(-3, -2) +/// arithmetics.euclidean_modulo(-3, -2) /// |> should.equal(1) /// -/// arithmetics.euclidian_modulo(5, 0) +/// arithmetics.euclidean_modulo(5, 0) /// |> should.equal(0) /// } ///
@@ -137,7 +146,7 @@ fn do_gcd(x: Int, y: Int) -> Int { /// /// /// -pub fn euclidian_modulo(x: Int, y: Int) -> Int { +pub fn int_euclidean_modulo(x: Int, y: Int) -> Int { case x % y, x, y { _, 0, _ -> 0 _, _, 0 -> 0 diff --git a/src/gleam_community/maths/combinatorics.gleam b/src/gleam_community/maths/combinatorics.gleam index dcdeab1..b16d0ad 100644 --- a/src/gleam_community/maths/combinatorics.gleam +++ b/src/gleam_community/maths/combinatorics.gleam @@ -239,8 +239,7 @@ pub fn permutation(n: Int, k: Int) -> Result(Int, String) { False -> { let assert Ok(v1) = factorial(n) let assert Ok(v2) = factorial(n - k) - v1 - / v2 + v1 / v2 |> Ok } } @@ -416,14 +415,17 @@ pub fn cartesian_product(xarr: List(a), yarr: List(a)) -> List(#(a, a)) { yarr |> set.from_list() xset - |> set.fold(set.new(), fn(accumulator0: set.Set(#(a, a)), member0: a) -> set.Set( - #(a, a), - ) { - set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, a)), member1: a) -> set.Set( - #(a, a), - ) { - set.insert(accumulator1, #(member0, member1)) - }) - }) + |> set.fold( + set.new(), + fn(accumulator0: set.Set(#(a, a)), member0: a) -> set.Set(#(a, a)) { + set.fold( + yset, + accumulator0, + fn(accumulator1: set.Set(#(a, a)), member1: a) -> set.Set(#(a, a)) { + set.insert(accumulator1, #(member0, member1)) + }, + ) + }, + ) |> set.to_list() } diff --git a/src/gleam_community/maths/elementary.gleam b/src/gleam_community/maths/elementary.gleam index 673cd23..1b518a4 100644 --- a/src/gleam_community/maths/elementary.gleam +++ b/src/gleam_community/maths/elementary.gleam @@ -819,8 +819,7 @@ pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String) // Apply the "change of base formula" let assert Ok(numerator) = logarithm_10(x) let assert Ok(denominator) = logarithm_10(a) - numerator - /. denominator + numerator /. denominator |> Ok } False -> diff --git a/src/gleam_community/maths/piecewise.gleam b/src/gleam_community/maths/piecewise.gleam index 6299489..c8492da 100644 --- a/src/gleam_community/maths/piecewise.gleam +++ b/src/gleam_community/maths/piecewise.gleam @@ -445,8 +445,7 @@ fn round_ties_up(p: Float, x: Float) -> Float { let remainder: Float = xabs -. xabs_truncated case remainder { _ if remainder >=. 0.5 && x >=. 0.0 -> - float_sign(x) *. truncate_float(xabs +. 1.0) - /. p + float_sign(x) *. truncate_float(xabs +. 1.0) /. p _ -> float_sign(x) *. xabs_truncated /. p } } @@ -577,8 +576,7 @@ pub fn int_absolute_value(x: Int) -> Int { /// /// pub fn float_absolute_difference(a: Float, b: Float) -> Float { - a - -. b + a -. b |> float_absolute_value() } @@ -618,8 +616,7 @@ pub fn float_absolute_difference(a: Float, b: Float) -> Float { /// /// pub fn int_absolute_difference(a: Int, b: Int) -> Int { - a - - b + a - b |> int_absolute_value() } diff --git a/src/gleam_community/maths/predicates.gleam b/src/gleam_community/maths/predicates.gleam index 8348e9c..f8d357c 100644 --- a/src/gleam_community/maths/predicates.gleam +++ b/src/gleam_community/maths/predicates.gleam @@ -98,8 +98,7 @@ fn float_absolute_value(x: Float) -> Float { } fn float_absolute_difference(a: Float, b: Float) -> Float { - a - -. b + a -. b |> float_absolute_value() } diff --git a/test/gleam_community/maths/arithmetics_test.gleam b/test/gleam_community/maths/arithmetics_test.gleam index 104cb4d..aa694b7 100644 --- a/test/gleam_community/maths/arithmetics_test.gleam +++ b/test/gleam_community/maths/arithmetics_test.gleam @@ -21,14 +21,31 @@ pub fn int_gcd_test() { |> should.equal(6) } -pub fn euclidian_modulo_test() { - arithmetics.euclidian_modulo(15, 4) +pub fn int_euclidean_modulo_test() { + // Base Case: Positive x, Positive y + // Note that the truncated, floored, and euclidean + // definitions should agree for this base case + arithmetics.int_euclidean_modulo(15, 4) |> should.equal(3) - arithmetics.euclidian_modulo(-3, -2) + // Case: Positive x, Negative y + arithmetics.int_euclidean_modulo(15, -4) + |> should.equal(3) + + // Case: Negative x, Positive y + arithmetics.int_euclidean_modulo(-15, 4) |> should.equal(1) - arithmetics.euclidian_modulo(5, 0) + // Case: Negative x, Negative y + arithmetics.int_euclidean_modulo(-15, -4) + |> should.equal(1) + + // Case: Positive x, Zero y + arithmetics.int_euclidean_modulo(5, 0) + |> should.equal(0) + + // Case: Zero x, Negative y + arithmetics.int_euclidean_modulo(0, 5) |> should.equal(0) } diff --git a/test/gleam_community/maths/piecewise_test.gleam b/test/gleam_community/maths/piecewise_test.gleam index 46d97a4..de1df0e 100644 --- a/test/gleam_community/maths/piecewise_test.gleam +++ b/test/gleam_community/maths/piecewise_test.gleam @@ -311,17 +311,26 @@ pub fn math_round_ties_away_test() { |> should.equal(Ok(12.0)) // Round 1. digit BEFORE decimal point - piecewise.round(12.0654, option.Some(-1), option.Some(piecewise.RoundTiesAway), + piecewise.round( + 12.0654, + option.Some(-1), + option.Some(piecewise.RoundTiesAway), ) |> should.equal(Ok(10.0)) // Round 2. digit BEFORE decimal point - piecewise.round(12.0654, option.Some(-2), option.Some(piecewise.RoundTiesAway), + piecewise.round( + 12.0654, + option.Some(-2), + option.Some(piecewise.RoundTiesAway), ) |> should.equal(Ok(0.0)) // Round 2. digit BEFORE decimal point - piecewise.round(12.0654, option.Some(-3), option.Some(piecewise.RoundTiesAway), + piecewise.round( + 12.0654, + option.Some(-3), + option.Some(piecewise.RoundTiesAway), ) |> should.equal(Ok(0.0)) }