diff --git a/src/gleam_community/maths/float.gleam b/src/gleam_community/maths/float.gleam
index 8ffc1bc..479ad82 100644
--- a/src/gleam_community/maths/float.gleam
+++ b/src/gleam_community/maths/float.gleam
@@ -19,8 +19,7 @@
//// .katex { font-size: 1.1em; }
////
////
-//// A module containing several different kinds of mathematical functions and constants
-//// that apply to real numbers (floats).
+//// A module containing mathematical functions and constants that apply to real numbers (floats).
////
//// ---
////
@@ -92,35 +91,42 @@ import gleam/option
///
///
/// The ceiling function rounds a given input value $$x \in \mathbb{R}$$ towards $$+\infty$$ at a specified number of digits.
-/// For example, $$12.0654$$ is rounded to:
-/// - $$1000.0$$ at the 3rd digit before the decimal point (`digit = -3`)
-/// - $$100.0$$ at the 2nd digit before the decimal point (`digit = -2`)
-/// - $$20.0$$ the 1st digit before the decimal point (`digit = -1`)
-/// - $$13.0$ at the 0th digit before the decimal point (`digit = 0`)
-/// - $$12.1$$ at the 1st digit after the decimal point (`digit = 1`)
-/// - $$12.07$$ at the 2nd digit after the decimal point (`digit = 2`)
-/// - $$12.066$$ at the 3rd digit after the decimal point (`digit = 3`)
///
-/// See also the concrete code example below.
-///
-/// Note: The ceiling function is used as an alias for the rounding function `round` with rounding mode `"Up"`.
+/// Note: The ceiling function is used as an alias for the rounding function [`round`](#round) with rounding mode `"Up"`.
///
///
-/// Example:
+/// Details
+///
+/// For example, $$12.0654$$ is rounded to:
+/// - $$13.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.1$$ for 1 digit after the decimal point (`digits = 1`)
+/// - $$12.07$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.066$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// For example, $$12.0654$$ is rounded to:
+/// - $$20.0$$ for 1 digit places before the decimal point (`digit = -1`)
+/// - $$100.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$1000.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+///
+///
+///
+/// Example
///
/// import gleeunit/should
/// import gleam/option
/// import gleam_community/maths/float as floatx
///
/// pub fn example() {
-/// floatx.ceiling(12.0654, option.Some(3))
-/// |> should.equal(12.066)
+/// floatx.ceiling(12.0654, option.Some(1))
+/// |> should.equal(Ok(12.1))
///
/// floatx.ceiling(12.0654, option.Some(2))
-/// |> should.equal(12.07)
+/// |> should.equal(Ok(12.07))
///
-/// floatx.ceiling(12.0654, option.Some(1))
-/// |> should.equal(12.1)
+/// floatx.ceiling(12.0654, option.Some(3))
+/// |> should.equal(Ok(12.066))
/// }
///
///
@@ -141,35 +147,41 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
///
/// The floor function rounds a given input value $$x \in \mathbb{R}$$ towards $$-\infty$$ at a specified number of digits.
-/// For example, $$12.0654$$ is rounded to:
-/// - $$0.0$$ at the 3rd digit before the decimal point (`digit = -3`)
-/// - $$0.0$$ at the 2nd digit before the decimal point (`digit = -2`)
-/// - $$10.0$$ the 1st digit before the decimal point (`digit = -1`)
-/// - $$12.0$ at the 0th digit before the decimal point (`digit = 0`)
-/// - $$12.0$$ at the 1st digit after the decimal point (`digit = 1`)
-/// - $$12.06$$ at the 2nd digit after the decimal point (`digit = 2`)
-/// - $$12.065$$ at the 3rd digit after the decimal point (`digit = 3`)
///
-/// See also the concrete code example below.
-///
-/// Note: The floor function is used as an alias for the rounding function `round` with rounding mode `"Down"`.
+/// Note: The floor function is used as an alias for the rounding function [`round`](#round) with rounding mode `"Down"`.
///
///
-/// Example:
+/// Details
+///
+/// For example, $$12.0654$$ is rounded to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.0$$ for 1 digits after the decimal point (`digits = 1`)
+/// - $$12.06$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+///
+///
+///
+/// Example
///
/// import gleeunit/should
/// import gleam/option
/// import gleam_community/maths/float as floatx
///
/// pub fn example() {
-/// floatx.ceiling(12.0654, option.Some(3))
-/// |> should.equal(12.065)
+/// floatx.floor(12.0654, option.Some(1))
+/// |> should.equal(Ok(12.0))
///
-/// floatx.ceiling(12.0654, option.Some(2))
-/// |> should.equal(12.06)
+/// floatx.floor(12.0654, option.Some(2))
+/// |> should.equal(Ok(12.06))
///
-/// floatx.ceiling(12.0654, option.Some(1))
-/// |> should.equal(12.0)
+/// floatx.floor(12.0654, option.Some(3))
+/// |> should.equal(Ok(12.065))
/// }
///
///
@@ -189,26 +201,42 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
///
///
+/// The truncate function rounds a given input value $$x \in \mathbb{R}$$ towards $$0$$ at a specified number of digits.
///
+/// Note: The truncate function is used as an alias for the rounding function [`round`](#round) with rounding mode `"ToZero"`.
///
///
-/// Example:
+/// Details
+///
+/// For example, $$12.0654$$ is rounded to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.0$$ for 1 digits after the decimal point (`digits = 1`)
+/// - $$12.06$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+///
+///
+///
+/// Example
///
/// import gleeunit/should
+/// import gleam/option
/// import gleam_community/maths/float as floatx
///
/// pub fn example() {
-/// floatx.round(0.4444, 2)
-/// |> should.equal(0.44)
+/// floatx.truncate(12.0654, option.Some(1))
+/// |> should.equal(Ok(12.0))
///
-/// floatx.round(0.4445, 2)
-/// |> should.equal(0.44)
+/// floatx.truncate(12.0654, option.Some(2))
+/// |> should.equal(Ok(12.0))
///
-/// floatx.round(0.4455, 2)
-/// |> should.equal(0.45)
-///
-/// floatx.round(0.4555, 2)
-/// |> should.equal(0.46)
+/// floatx.truncate(12.0654, option.Some(3))
+/// |> should.equal(Ok(12.0))
/// }
///
///
@@ -218,8 +246,8 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
///
///
-pub fn truncate(x: Float, digits: Int) -> Result(Float, String) {
- round(x, option.Some(digits), option.Some("ToZero"))
+pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
+ round(x, digits, option.Some("ToZero"))
}
///
@@ -228,49 +256,125 @@ pub fn truncate(x: Float, digits: Int) -> Result(Float, String) {
///
///
///
-/// The function rounds a floating point number to a specific number of digits using a given rounding mode.
+/// The function rounds a float to a specific number of digits (after the decimal place or before if negative) using a specified rounding mode.
///
/// Valid rounding modes include:
-/// - `Nearest` (default): If the last digit is equal to 5, then the previous digit is rounded to nearest even integer value.
-/// - `TiesAway`: If the last digit is equal to 5, then the previous digit is rounded away from zero (C/C++ rounding behavior).
-/// - `TiesUp`: If the last digit is equal to 5, then the previous digit is rounded towards $$+\infty$$ (Java/JavaScript rounding behaviour).
-/// - `ToZero`: The last digit is rounded towards $$0$$.
-/// - An alias for this rounding mode is [`truncate`](#truncate)
-/// - `Down`: If the last digit larger than 0, then the previous digit is rounded towards $$-\infty$$.
-/// - An alias for this rounding mode is [`floor`](#floor)
-/// - `Up`: If the last digit is larger than 0, then the previous digit is rounded towards $$+\infty$$.
-/// - An alias for this rounding mode is [`ceiling`](#ceiling)
-///
-/// Valid rounding modes include:
-/// - `Nearest` (default): The specified digit is rounded to nearest even integer value if the following digit + 1 is equal to 5.
-/// - `TiesAway`: The specified digit is rounded away from zero (C/C++ rounding behavior) if the following digit + 1 is equal to 5.
-/// - `TiesUp`: The specified digit is rounded towards $$+\infty$$ (Java/JavaScript rounding behaviour) if the following digit + 1 is equal to 5.
-/// - `ToZero`: The input value is truncated at the specified digit.
-/// - An alias for this rounding mode is [`truncate`](#truncate)
-/// - `Down`: The specified digit is rounded towards $$-\infty$$ if the following digit + 1 is larger than 0.
-/// - An alias for this rounding mode is [`floor`](#floor)
-/// - `Up`: The specified digit is rounded towards $$+\infty$$ if the following digit + 1 is larger than 0.
-/// - An alias for this rounding mode is [`ceiling`](#ceiling)
+/// - `"Nearest"` (default): The input $$x$$ is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded to the nearest even integer.
+/// - `"TiesAway"`: The input $$x$$ is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded away from zero (C/C++ rounding behavior).
+/// - `"TiesUp"`: The input $$x$$ is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded towards $$+\infty$$ (Java/JavaScript rounding behaviour).
+/// - `"ToZero"`: The input $$x$$ is rounded to the nearest integer value (at the specified digit) that is less than or equal to the absolute value of the input $$x$$. An alias for this rounding mode is [`truncate`](#truncate).
+/// - `"Down"`: The input $$x$$ is rounded to the nearest integer value (at the specified digit) that is less than or equal to the input $$x$$. An alias for this rounding mode is [`floor`](#floor).
+/// - `"Up"`: The input $$x$$ is rounded to the nearest integer value (at the specified digit) that is larger than or equal to the input $$x$$. An alias for this rounding mode is [`ceiling`](#ceiling).
///
///
-/// Example:
+/// Details
+///
+/// The `"Nearest"` rounding mode, rounds $$12.0654$$ to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.1$$ for 1 digit after the decimal point (`digits = 1`)
+/// - $$12.07$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+/// The `"TiesAway"` rounding mode, rounds $$12.0654$$ to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.1$$ for 1 digit after the decimal point (`digits = 1`)
+/// - $$12.07$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+/// The `"TiesUp"` rounding mode, rounds $$12.0654$$ to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.1$$ for 1 digits after the decimal point (`digits = 1`)
+/// - $$12.07$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+/// The `"ToZero"` rounding mode, rounds $$12.0654$$ to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.0$$ for 1 digit after the decimal point (`digits = 1`)
+/// - $$12.06$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+/// The `"Down"` rounding mode, rounds $$12.0654$$ to:
+/// - $$12.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.0$$ for 1 digits after the decimal point (`digits = 1`)
+/// - $$12.06$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.065$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$10.0$$ for 1 digit before the decimal point (`digits = -1`)
+/// - $$0.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$0.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+/// The `"Up"` rounding mode, rounds $$12.0654$$ to:
+/// - $$13.0$$ for 0 digits after the decimal point (`digits = 0`)
+/// - $$12.1$$ for 1 digit after the decimal point (`digits = 1`)
+/// - $$12.07$$ for 2 digits after the decimal point (`digits = 2`)
+/// - $$12.066$$ for 3 digits after the decimal point (`digits = 3`)
+///
+/// It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.
+/// - $$20.0$$ for 1 digit places before the decimal point (`digit = -1`)
+/// - $$100.0$$ for 2 digits before the decimal point (`digits = -2`)
+/// - $$1000.0$$ for 3 digits before the decimal point (`digits = -3`)
+///
+///
+///
+///
+/// Example
///
/// import gleeunit/should
/// import gleam/option
/// import gleam_community/maths/float as floatx
///
/// pub fn example() {
-/// floatx.round(0.4444, 2)
-/// |> should.equal(0.44)
+/// // The default number of digits is 0 if None is provided
+/// floatx.round(12.0654, option.None, option.Some("Nearest"))
+/// |> should.equal(Ok(12.0))
///
-/// floatx.round(0.4445, 2)
-/// |> should.equal(0.44)
+/// // The default rounding mode is "Nearest" if None is provided
+/// floatx.round(12.0654, option.None, option.None)
+/// |> should.equal(Ok(12.0))
///
-/// floatx.round(0.4455, 2)
-/// |> should.equal(0.45)
+/// // We get an error if an invalid rounding mode is provided
+/// floatx.round(12.0654, option.None, option.Some("XYZ"))
+/// |> should.be_error()
///
-/// floatx.round(0.4555, 2)
-/// |> should.equal(0.46)
+/// // Try different rounding modes
+/// floatx.round(12.0654, option.Some(2), option.Some("Nearest"))
+/// |> should.equal(Ok(12.07))
+///
+/// floatx.round(12.0654, option.Some(2), option.Some("TiesAway"))
+/// |> should.equal(Ok(12.07))
+///
+/// floatx.round(12.0654, option.Some(2), option.Some("TiesUp"))
+/// |> should.equal(Ok(12.07)
+///
+/// floatx.round(12.0654, option.Some(2), option.Some("ToZero"))
+/// |> should.equal(Ok(12.06))
+///
+/// floatx.round(12.0654, option.Some(2), option.Some("Down"))
+/// |> should.equal(Ok(12.06))
+///
+/// floatx.round(12.0654, option.Some(2), option.Some("Up"))
+/// |> should.equal(Ok(12.07))
/// }
///
///
@@ -288,82 +392,78 @@ pub fn round(
case digits {
option.Some(a) -> {
assert Ok(p) = power(10.0, int.to_float(a))
- case mode {
- // Rounding mode choices
- option.Some("Nearest") ->
- round_nearest(p, x)
- |> Ok
- option.Some("TiesAway") ->
- round_ties_away(p, x)
- |> Ok
- option.Some("TiesUp") ->
- round_ties_up(p, x)
- |> Ok
- option.Some("ToZero") ->
- round_to_zero(p, x)
- |> Ok
- option.Some("Down") ->
- round_down(p, x)
- |> Ok
- option.Some("Up") ->
- round_up(p, x)
- |> Ok
- // Default rounding mode
- option.None ->
- round_nearest(p, x)
- |> Ok
- _ ->
- "Invalid Rounding Mode!"
- |> Error
- }
+ do_round(p, x, mode)
}
+ option.None -> do_round(1.0, x, mode)
+ }
+}
+
+fn do_round(
+ p: Float,
+ x: Float,
+ mode: option.Option(String),
+) -> Result(Float, String) {
+ case mode {
+ // Rounding mode choices
+ option.Some("Nearest") ->
+ round_nearest(p, x)
+ |> Ok
+ option.Some("TiesAway") ->
+ round_ties_away(p, x)
+ |> Ok
+ option.Some("TiesUp") ->
+ round_ties_up(p, x)
+ |> Ok
+ option.Some("ToZero") ->
+ round_to_zero(p, x)
+ |> Ok
+ option.Some("Down") ->
+ round_down(p, x)
+ |> Ok
+ option.Some("Up") ->
+ round_up(p, x)
+ |> Ok
+ // Default rounding mode. The default is "Nearest"
+ option.None ->
+ round_nearest(p, x)
+ |> Ok
_ ->
- "Invalid!"
+ "Invalid rounding mode. Valid input is 'Nearest', 'TiesAway', 'TiesUp', 'ToZero', 'Down', 'Up'."
|> Error
}
}
fn round_nearest(p: Float, x: Float) -> Float {
- let positive = x >. 0.0
- let xabs = float.absolute_value(x)
- let geq_tie = xabs -. truncate_float(xabs) >=. 0.5
- assert Ok(is_even) = int.modulo(to_int(xabs), 2)
- io.debug(is_even)
- case geq_tie {
- True ->
+ let xabs = float.absolute_value(x) *. p
+ let rem = xabs -. truncate_float(xabs)
+ case rem {
+ _ if rem >. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p
+ _ if rem == 0.5 -> {
+ assert Ok(is_even) = int.modulo(to_int(xabs), 2)
case is_even == 0 {
- True -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p
- False -> sign(x) *. truncate_float({ xabs +. 1.0 } *. p) /. p
+ True -> sign(x) *. truncate_float(xabs) /. p
+ False -> sign(x) *. truncate_float(xabs +. 1.0) /. p
}
- False -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p
+ }
+ _ -> sign(x) *. truncate_float(xabs) /. p
}
}
fn round_ties_away(p: Float, x: Float) -> Float {
- let positive = x >. 0.0
- let xabs = float.absolute_value(x)
- let g_tie = xabs -. truncate_float(xabs) >=. 0.5
- case g_tie {
- True -> sign(x) *. truncate_float({ xabs +. 1.0 } *. p) /. p
- False -> truncate_float(x *. p) /. p
+ let xabs = float.absolute_value(x) *. p
+ let rem = xabs -. truncate_float(xabs)
+ case rem {
+ _ if rem >=. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p
+ _ -> sign(x) *. truncate_float(xabs) /. p
}
}
fn round_ties_up(p: Float, x: Float) -> Float {
- let positive = x >. 0.0
- let xabs = float.absolute_value(x)
- let geq_tie = xabs -. truncate_float(xabs) >=. 0.5
- case geq_tie {
- True ->
- case positive {
- True -> sign(x) *. truncate_float({ xabs +. 1.0 } *. p) /. p
- False -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p
- }
- False ->
- case positive {
- True -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p
- False -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p
- }
+ let xabs = float.absolute_value(x) *. p
+ let rem = xabs -. truncate_float(xabs)
+ case rem {
+ _ if rem >=. 0.5 && x >=. 0.0 -> sign(x) *. truncate_float(xabs +. 1.0) /. p
+ _ -> sign(x) *. truncate_float(xabs) /. p
}
}
@@ -434,7 +534,7 @@ if erlang {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -495,7 +595,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -553,7 +653,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -613,7 +713,7 @@ if javascript {
/// a numeric value $$y$$ that lies in the range $$\(-\infty, +\infty\)$$ (an angle in radians).
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -660,7 +760,7 @@ if javascript {
/// a numeric value $$y$$ that lies in the range $$\[-\frac{\pi}{2}, \frac{\pi}{2}\]$$ (an angle in radians).
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -716,7 +816,7 @@ if javascript {
/// returned by $$\text{atan2}(y, x)$$ is in the range $$\[-\pi, \pi\]$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -764,7 +864,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -824,7 +924,7 @@ if javascript {
/// as input and returns a numeric value $$y$$ that lies in the range $$\[-1, 1\]$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -875,7 +975,7 @@ if javascript {
/// If the input value is too large an overflow error might occur.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -923,7 +1023,7 @@ if javascript {
/// Note: If the input value $$x$$ is too large an overflow error might occur.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -971,7 +1071,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam/option
@@ -1040,7 +1140,7 @@ pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String)
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1102,7 +1202,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1163,7 +1263,7 @@ if javascript {
/// If the input value is outside the domain of the function an error is returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1207,61 +1307,6 @@ if javascript {
"../floatx.mjs" "log2"
}
-// pub fn logb(x: Float, b: Float) -> Result(Float, String) {
-// case x >. 0.0 {
-// True ->
-// case b >. 0.0 && b != 1.0 {
-// True -> {
-// // Apply the change of base formula
-// assert Ok(numerator) = log10(x)
-// assert Ok(denominator) = log10(b)
-// numerator /. denominator
-// |> Ok
-// }
-// False ->
-// "Invalid input argument: b <= 0 or b == 1. Valid input is b > 0 and b != 1."
-// |> Error
-// }
-// False ->
-// "Invalid input argument: x <= 0. Valid input is x > 0."
-// |> Error
-// }
-// }
-
-///
-///
-/// The The base-2 logarithm function:
-///
-/// \\[
-/// \forall x \in \(0, \infty), \\; \log_{2}{(x)} = y \in \(-\infty, +\infty\)
-/// \\]
-///
-/// The function takes a number $$x$$ in its domain $$\(0, \infty\)$$ as input and returns
-/// a numeric value $$y$$ that lies in the range $$\(-\infty, \infty\)$$.
-/// If the input value is outside the domain of the function an error is returned.
-///
-///
-/// Example:
-///
-/// import gleeunit/should
-/// import gleam_community/maths/float as floatx
-///
-/// pub fn example () {
-/// floatx.logarithm_2(1.0)
-/// |> should.equal(Ok(0.0))
-///
-/// floatx.logarithm_2(2.0)
-/// |> should.equal(Ok(1.0))
-///
-/// floatx.logarithm_2(-1.0)
-/// |> should.be_error()
-/// }
-///
-///
///
///
pub fn power(x: Float, y: Float) -> Result(Float, String) {
- // assert Ok(y_ceiling) = ceiling(y, option.Some(0))
- // io.debug(y_ceiling)
- // let fractional: Bool = y_ceiling -. y >. 0.0
let fractional: Bool = do_ceiling(y) -. y >. 0.0
// In the following check:
// 1. If the base (x) is negative and the exponent (y) is fractional
@@ -1352,7 +1394,7 @@ if javascript {
/// as an imaginary number will otherwise have to be returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1404,7 +1446,7 @@ pub fn square_root(x: Float) -> Result(Float, String) {
/// as an imaginary number will otherwise have to be returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1456,7 +1498,7 @@ pub fn cube_root(x: Float) -> Result(Float, String) {
/// as an imaginary number will otherwise have to be returned.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1517,7 +1559,7 @@ pub fn nth_root(x: Float, n: Int) -> Result(Float, String) {
/// Naive (unfused) and corrected (unfused) in [https://arxiv.org/pdf/1904.09481.pdf]("An Improved Algorithm for Hypot(A, B)" by Borges, C. F)
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1556,7 +1598,7 @@ pub fn hypotenuse(x: Float, y: Float) -> Float {
/// as input and returns a numeric value $$y$$ that lies in the range $$\[-1, 1\]$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1608,7 +1650,7 @@ if javascript {
/// occur.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1656,7 +1698,7 @@ if javascript {
/// $$\(-\infty, +\infty\)$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1703,7 +1745,7 @@ if javascript {
/// and returns a numeric value $$y$$ that lies in the range $$\[-1, 1\]$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1750,7 +1792,7 @@ if javascript {
/// That is, $$1 \text{ radians } = \frac{180}{\pi} \text{ degrees }$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1784,7 +1826,7 @@ pub fn to_degree(x: Float) -> Float {
/// That is, $$1 \text{ degrees } = \frac{\pi}{180} \text{ radians }$$.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1814,7 +1856,7 @@ pub fn to_radian(x: Float) -> Float {
/// The min function.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1850,7 +1892,7 @@ pub fn minimum(x: Float, y: Float) -> Float {
/// The min function.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1886,7 +1928,7 @@ pub fn maximum(x: Float, y: Float) -> Float {
/// The minmax function.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -1916,8 +1958,7 @@ pub fn minmax(x: Float, y: Float) -> #(Float, Float) {
///
///
///
-/// The sign function which returns the sign of the input, indicating
-/// whether it is positive, negative, or zero.
+/// The sign function which returns the sign of the input, indicating whether it is positive, negative, or zero.
///
///
///
-/// The function returns $$x$$ such that it has the same sign as $$y$$.
+/// The function takes two arguments $$x$$ and $$y$$ and returns $$x$$ such that it has the same sign as $$y$$.
///
///
///
pub fn copy_sign(x: Float, y: Float) -> Float {
- // let signx: Float = sign(x)
- // let signy: Float = sign(y)
- // case signx == signy {
- // True -> y
- // False -> {
- // case signx >. signy {
- // True ->
- // }
-
- // }
- // }
- todo
+ case sign(x) == sign(y) {
+ // x and y have the same sign, just return x
+ True -> x
+ // x and y have different signs:
+ // - x is positive and y is negative, then flip sign of x
+ // - x is negative and y is positive, then flip sign of x
+ False -> flip_sign(x)
+ }
}
///
@@ -1982,6 +2019,7 @@ pub fn copy_sign(x: Float, y: Float) -> Float {
///
///
///
+/// The function flips the sign of a given input value.
///
///
///
@@ -2212,7 +2250,7 @@ pub fn tau() -> Float {
/// Note: If the input value $$x$$ is too large an overflow error might occur.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -2250,7 +2288,7 @@ pub fn e() -> Float {
/// value which is the the absolute difference of the inputs.
///
///
-/// Example:
+/// Example
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@@ -2291,10 +2329,10 @@ pub fn absolute_difference(a: Float, b: Float) -> Float {
///
/// `True` is returned if statement holds, otherwise `False` is returned.
///
-/// Example:
+/// Example
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/float as floatx
///
/// pub fn example () {
/// let val: Float = 99.
@@ -2303,7 +2341,7 @@ pub fn absolute_difference(a: Float, b: Float) -> Float {
/// // if 'val' is within 1 percent of 'ref_val' +/- 0.1
/// let rtol: Float = 0.01
/// let atol: Float = 0.10
-/// stats.is_close(val, ref_val, rtol, atol)
+/// floatx.is_close(val, ref_val, rtol, atol)
/// |> should.be_true()
/// }
///
diff --git a/src/gleam_community/maths/float_list.gleam b/src/gleam_community/maths/float_list.gleam
index f835b5e..e8334e5 100644
--- a/src/gleam_community/maths/float_list.gleam
+++ b/src/gleam_community/maths/float_list.gleam
@@ -40,12 +40,10 @@
//// * [`maximum`](#maximum)
//// * [`minimum`](#minimum)
//// * [`extrema`](#extrema)
-//// * [`argmax`](#arg_maximum)
-//// * [`argmin`](#arg_minimum)
+//// * [`arg_maximum`](#arg_maximum)
+//// * [`arg_minimum`](#arg_minimum)
//// * **Tests**
//// * [`all_close`](#all_close)
-//// * **Misc. functions**
-//// * [`trim`](#trim)
import gleam/list
import gleam/int
@@ -173,8 +171,7 @@ pub fn geometric_space(
/// \sum_{i=1}^n x_i
/// \\]
///
-/// In the formula, $$n$$ is the length of the list and
-/// $$x_i$$ is the value in the input list indexed by $$i$$.
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
///
/// Example:
@@ -222,8 +219,7 @@ pub fn sum(arr: List(Float)) -> Float {
/// \prod_{i=1}^n x_i
/// \\]
///
-/// In the formula, $$n$$ is the length of the list and
-/// $$x_i$$ is the value in the input list indexed by $$i$$.
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
///
/// Example:
@@ -271,8 +267,7 @@ pub fn product(arr: List(Float)) -> Float {
/// \sum_{i=1}^n x_i
/// \\]
///
-/// In the formula, $$n$$ is the length of the list and
-/// $$x_i$$ is the value in the input list indexed by $$i$$.
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
///
/// Example:
@@ -314,8 +309,7 @@ pub fn cumulative_sum(arr: List(Float)) -> List(Float) {
/// \prod_{i=1}^n x_i
/// \\]
///
-/// In the formula, $$n$$ is the length of the list and
-/// $$x_i$$ is the value in the input list indexed by $$i$$.
+/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
///
/// Example:
@@ -395,9 +389,9 @@ pub fn norm(xarr: List(Float), yarr: List(Float), p: Int) -> List(Float) {
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
+/// [4.0, 4.0, 3.0, 2.0, 1.0]
/// |> float_list.maximum()
-/// |> should.equal(Ok(4.))
+/// |> should.equal(Ok(4.0))
/// }
///
///
@@ -450,9 +444,9 @@ pub fn maximum(arr: List(Float)) -> Result(Float, String) {
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
+/// [4.0, 4.0, 3.0, 2.0, 1.0]
/// |> float_list.minimum()
-/// |> should.equal(Ok(1.))
+/// |> should.equal(Ok(1.0))
/// }
///
///
@@ -505,7 +499,7 @@ pub fn minimum(arr: List(Float)) -> Result(Float, String) {
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
+/// [4.0, 4.0, 3.0, 2.0, 1.0]
/// |> float_list.arg_maximum()
/// |> should.equal(Ok([0, 1]))
/// }
@@ -565,7 +559,7 @@ pub fn arg_maximum(arr: List(Float)) -> Result(List(Int), String) {
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
+/// [4.0, 4.0, 3.0, 2.0, 1.0]
/// |> float_list.arg_minimum()
/// |> should.equal(Ok([4]))
/// }
@@ -577,7 +571,7 @@ pub fn arg_maximum(arr: List(Float)) -> Result(List(Int), String) {
///
///
///
-pub fn arg_mininmum(arr: List(Float)) -> Result(List(Int), String) {
+pub fn arg_minimum(arr: List(Float)) -> Result(List(Int), String) {
case arr {
[] ->
"Invalid input argument: The list is empty."
@@ -625,9 +619,9 @@ pub fn arg_mininmum(arr: List(Float)) -> Result(List(Int), String) {
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
+/// [4.0, 4.0, 3.0, 2.0, 1.0]
/// |> float_list.extrema()
-/// |> should.equal(Ok(1.))
+/// |> should.equal(Ok(#(1.0, 4.0)))
/// }
///
///
@@ -638,7 +632,30 @@ pub fn arg_mininmum(arr: List(Float)) -> Result(List(Int), String) {
///
///
pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) {
- todo
+ case arr {
+ [] ->
+ "Invalid input argument: The list is empty."
+ |> Error
+ _ -> {
+ assert Ok(val_max) = list.at(arr, 0)
+ assert Ok(val_min) = list.at(arr, 0)
+ arr
+ |> list.fold(
+ #(val_min, val_max),
+ fn(acc: #(Float, Float), a: Float) {
+ let first: Float = pair.first(acc)
+ let second: Float = pair.second(acc)
+ case a <. first, a >. second {
+ True, True -> #(a, a)
+ True, False -> #(a, second)
+ False, True -> #(first, a)
+ False, False -> #(first, second)
+ }
+ },
+ )
+ |> Ok
+ }
+ }
}
///
diff --git a/src/gleam_community/maths/int.gleam b/src/gleam_community/maths/int.gleam
index 438e04b..05c396e 100644
--- a/src/gleam_community/maths/int.gleam
+++ b/src/gleam_community/maths/int.gleam
@@ -19,8 +19,7 @@
//// .katex { font-size: 1.1em; }
////
////
-//// A module containing several different kinds of mathematical functions
-//// applying to integer numbers.
+//// A module containing mathematical functions applying to integer (int) numbers.
////
//// ---
////
@@ -77,13 +76,13 @@ import gleam_community/maths/float as floatx
///
Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
-/// math.minimum(2.0, 1.5)
+/// intx.minimum(2.0, 1.5)
/// |> should.equal(1.5)
///
-/// math.minimum(1.5, 2.0)
+/// intx.minimum(1.5, 2.0)
/// |> should.equal(1.5)
/// }
///
@@ -113,13 +112,13 @@ pub fn minimum(x: Int, y: Int) -> Int {
///
Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
-/// math.maximum(2.0, 1.5)
+/// intx.maximum(2.0, 1.5)
/// |> should.equal(1.5)
///
-/// math.maximum(1.5, 2.0)
+/// intx.maximum(1.5, 2.0)
/// |> should.equal(1.5)
/// }
///
@@ -149,13 +148,13 @@ pub fn maximum(x: Int, y: Int) -> Int {
///
Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
-/// math.minmax(2.0, 1.5)
+/// intx.minmax(2.0, 1.5)
/// |> should.equal(#(1.5, 2.0))
///
-/// math.minmax(1.5, 2.0)
+/// intx.minmax(1.5, 2.0)
/// |> should.equal(#(1.5, 2.0))
/// }
///
@@ -204,7 +203,7 @@ if erlang {
if javascript {
external fn do_sign(Int) -> Int =
- "../math.mjs" "sign"
+ "../intx.mjs" "sign"
}
///
@@ -224,6 +223,31 @@ pub fn flip_sign(x: Int) -> Int {
-1 * x
}
+///
+///
+/// The function takes two arguments $$x$$ and $$y$$ and returns $$x$$ such that it has the same sign as $$y$$.
+///
+///
+///
+pub fn copy_sign(x: Int, y: Int) -> Int {
+ case sign(x) == sign(y) {
+ // x and y have the same sign, just return x
+ True -> x
+ // x and y have different signs:
+ // - x is positive and y is negative, then flip sign of x
+ // - x is negative and y is positive, then flip sign of x
+ False -> flip_sign(x)
+ }
+}
+
///
///
/// Spot a typo? Open an issue!
@@ -243,22 +267,22 @@ pub fn flip_sign(x: Int) -> Int {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
/// // Invalid input gives an error
/// // Error on: n = -1 < 0
-/// math.combination(-1, 1)
+/// intx.combination(-1, 1)
/// |> should.be_error()
///
/// // Valid input returns a result
-/// math.combination(4, 0)
+/// intx.combination(4, 0)
/// |> should.equal(Ok(1))
///
-/// math.combination(4, 4)
+/// intx.combination(4, 4)
/// |> should.equal(Ok(1))
///
-/// math.combination(4, 2)
+/// intx.combination(4, 2)
/// |> should.equal(Ok(6))
/// }
///
@@ -314,23 +338,23 @@ pub fn combination(n: Int, k: Int) -> Result(Int, String) {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
/// // Invalid input gives an error
-/// math.factorial(-1)
+/// intx.factorial(-1)
/// |> should.be_error()
///
/// // Valid input returns a result
-/// math.factorial(0)
+/// intx.factorial(0)
/// |> should.equal(Ok(1))
-/// math.factorial(1)
+/// intx.factorial(1)
/// |> should.equal(Ok(1))
-/// math.factorial(2)
+/// intx.factorial(2)
/// |> should.equal(Ok(2))
-/// math.factorial(3)
+/// intx.factorial(3)
/// |> should.equal(Ok(6))
-/// math.factorial(4)
+/// intx.factorial(4)
/// |> should.equal(Ok(24))
/// }
///
@@ -379,22 +403,22 @@ pub fn factorial(n) -> Result(Int, String) {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
/// // Invalid input gives an error
/// // Error on: n = -1 < 0
-/// math.permutation(-1, 1)
+/// intx.permutation(-1, 1)
/// |> should.be_error()
///
/// // Valid input returns a result
-/// math.permutation(4, 0)
+/// intx.permutation(4, 0)
/// |> should.equal(Ok(1))
///
-/// math.permutation(4, 4)
+/// intx.permutation(4, 4)
/// |> should.equal(Ok(1))
///
-/// math.permutation(4, 2)
+/// intx.permutation(4, 2)
/// |> should.equal(Ok(12))
/// }
///
@@ -450,13 +474,13 @@ pub fn permutation(n: Int, k: Int) -> Result(Int, String) {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
-/// math.absolute_difference(-10.0, 10.0)
+/// intx.absolute_difference(-10.0, 10.0)
/// |> should.equal(20.0)
///
-/// math.absolute_difference(0.0, -2.0)
+/// intx.absolute_difference(0.0, -2.0)
/// |> should.equal(2.0)
/// }
///
@@ -482,7 +506,7 @@ pub fn absolute_difference(a: Int, b: Int) -> Int {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/math
+/// import gleam_community/maths/int as intx
///
/// pub fn example() {
///
@@ -498,7 +522,7 @@ pub fn absolute_difference(a: Int, b: Int) -> Int {
pub fn is_power(x: Int, y: Int) -> Bool {
assert Ok(value) =
floatx.logarithm(int.to_float(x), option.Some(int.to_float(y)))
- assert Ok(truncated) = floatx.truncate(value, 0)
+ assert Ok(truncated) = floatx.truncate(value, option.Some(0))
let rem = value -. truncated
rem == 0.0
}
diff --git a/src/gleam_community/maths/int_list.gleam b/src/gleam_community/maths/int_list.gleam
index 0b928d0..1033f52 100644
--- a/src/gleam_community/maths/int_list.gleam
+++ b/src/gleam_community/maths/int_list.gleam
@@ -26,11 +26,18 @@
////
//// ---
////
-//// * **Miscellaneous functions**
-//// * [`amax`](#amax)
-//// * [`amin`](#amin)
-//// * [`argmax`](#argmax)
-//// * [`argmin`](#argmin)
+//// * **Distances, sums and products**
+//// * [`sum`](#sum)
+//// * [`product`](#product)
+//// * [`norm`](#norm)
+//// * [`cumulative_sum`](#cumulative_sum)
+//// * [`cumulative_product`](#cumulative_product)
+//// * **Misc. mathematical functions**
+//// * [`maximum`](#maximum)
+//// * [`minimum`](#minimum)
+//// * [`extrema`](#extrema)
+//// * [`arg_maximum`](#arg_maximum)
+//// * [`arg_minimum`](#arg_minimum)
import gleam/list
import gleam/int
@@ -50,17 +57,17 @@ import gleam_community/maths/int as intx
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/int_list
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.argmin()
+/// |> int_list.arg_minimum()
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
-/// |> stats.argmin()
+/// [4, 4, 3, 2, 1]
+/// |> stats.arg_minimum()
/// |> should.equal(Ok([4]))
/// }
///
@@ -71,7 +78,7 @@ import gleam_community/maths/int as intx
///
///
///
-pub fn argmin(arr: List(Float)) -> Result(List(Int), String) {
+pub fn arg_minimum(arr: List(Int)) -> Result(List(Int), String) {
case arr {
[] ->
"Invalid input argument: The list is empty."
@@ -79,11 +86,11 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) {
_ -> {
assert Ok(min) =
arr
- |> amin()
+ |> minimum()
arr
- |> list.index_map(fn(index: Int, a: Float) -> Int {
- case a -. min {
- 0. -> index
+ |> list.index_map(fn(index: Int, a: Int) -> Int {
+ case a - min {
+ 0 -> index
_ -> -1
}
})
@@ -110,17 +117,17 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) {
///
Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/int_list
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.argmax()
+/// |> int_list.arg_maximum()
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
-/// |> stats.argmax()
+/// [4, 4, 3, 2, 1]
+/// |> int_list.arg_maximum()
/// |> should.equal(Ok([0, 1]))
/// }
///
@@ -131,7 +138,7 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) {
///
///
///
-pub fn argmax(arr: List(Float)) -> Result(List(Int), String) {
+pub fn arg_maximum(arr: List(Int)) -> Result(List(Int), String) {
case arr {
[] ->
"Invalid input argument: The list is empty."
@@ -139,11 +146,11 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) {
_ -> {
assert Ok(max) =
arr
- |> amax()
+ |> maximum()
arr
- |> list.index_map(fn(index: Int, a: Float) -> Int {
- case a -. max {
- 0. -> index
+ |> list.index_map(fn(index: Int, a: Int) -> Int {
+ case a - max {
+ 0 -> index
_ -> -1
}
})
@@ -170,18 +177,18 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) {
///
Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/int_list
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.amax()
+/// |> int_list.maximum()
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
-/// |> stats.amax()
-/// |> should.equal(Ok(4.))
+/// [4, 4, 3, 2, 1]
+/// |> int_list.maximum()
+/// |> should.equal(Ok(4))
/// }
///
///
@@ -191,7 +198,7 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) {
///
///
///
-pub fn amax(arr: List(Float)) -> Result(Float, String) {
+pub fn maximum(arr: List(Int)) -> Result(Int, String) {
case arr {
[] ->
"Invalid input argument: The list is empty."
@@ -201,8 +208,8 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) {
arr
|> list.fold(
val0,
- fn(acc: Float, a: Float) {
- case a >. acc {
+ fn(acc: Int, a: Int) {
+ case a > acc {
True -> a
False -> acc
}
@@ -225,18 +232,18 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/int_list
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.amin()
+/// |> int_list.minimum()
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
-/// |> stats.amin()
-/// |> should.equal(Ok(1.))
+/// [4, 4, 3, 2, 1]
+/// |> int_list.minimum()
+/// |> should.equal(Ok(1))
/// }
///
///
@@ -246,7 +253,7 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) {
///
///
///
-pub fn amin(arr: List(Float)) -> Result(Float, String) {
+pub fn minimum(arr: List(Int)) -> Result(Int, String) {
case arr {
[] ->
"Invalid input argument: The list is empty."
@@ -256,8 +263,8 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) {
arr
|> list.fold(
val0,
- fn(acc: Float, a: Float) {
- case a <. acc {
+ fn(acc: Int, a: Int) {
+ case a < acc {
True -> a
False -> acc
}
@@ -279,18 +286,18 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) {
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/int_list
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.amin()
+/// |> int_list.extrema()
/// |> should.be_error()
///
/// // Valid input returns a result
-/// [4., 4., 3., 2., 1.]
-/// |> stats.amin()
-/// |> should.equal(Ok(1.))
+/// [4, 4, 3, 2, 1]
+/// |> int_list.extrema()
+/// |> should.equal(Ok(#(1, 4)))
/// }
///
///
@@ -300,6 +307,29 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) {
///
///
///
-pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) {
- todo
+pub fn extrema(arr: List(Int)) -> Result(#(Int, Int), String) {
+ case arr {
+ [] ->
+ "Invalid input argument: The list is empty."
+ |> Error
+ _ -> {
+ assert Ok(val_max) = list.at(arr, 0)
+ assert Ok(val_min) = list.at(arr, 0)
+ arr
+ |> list.fold(
+ #(val_min, val_max),
+ fn(acc: #(Int, Int), a: Int) {
+ let first: Int = pair.first(acc)
+ let second: Int = pair.second(acc)
+ case a < first, a > second {
+ True, True -> #(a, a)
+ True, False -> #(a, second)
+ False, True -> #(first, a)
+ False, False -> #(first, second)
+ }
+ },
+ )
+ |> Ok
+ }
+ }
}
diff --git a/src/gleam_community/maths/list.gleam b/src/gleam_community/maths/list.gleam
index 634ac83..257fa12 100644
--- a/src/gleam_community/maths/list.gleam
+++ b/src/gleam_community/maths/list.gleam
@@ -19,11 +19,8 @@
//// .katex { font-size: 1.1em; }
////
////
-//// A module containing several different kinds of mathematical functions
-//// applying to lists of real numbers.
+//// A module containing general utility functions applying to lists.
////
-//// Function naming has been adopted from C mathematical function.
-////
//// ---
////
//// * **Miscellaneous functions**
@@ -39,24 +36,23 @@ import gleam/float
///
///
///
-/// Trim a list to a certain size given min/max indices. The min/max indices
-/// are inclusive.
+/// Trim a list to a certain size given min/max indices. The min/max indices are inclusive.
///
///
/// Example:
///
/// import gleeunit/should
-/// import gleam_stats/stats
+/// import gleam_community/maths/list as listx
///
/// pub fn example () {
/// // An empty lists returns an error
/// []
-/// |> stats.trim(0, 0)
+/// |> listx.trim(0, 0)
/// |> should.be_error()
///
/// // Trim the list to only the middle part of list
/// [1., 2., 3., 4., 5., 6.]
-/// |> stats.trim(1, 4)
+/// |> listx.trim(1, 4)
/// |> should.equal(Ok([2., 3., 4., 5.]))
/// }
///
diff --git a/temp.gleam b/temp.gleam
deleted file mode 100644
index aabf936..0000000
--- a/temp.gleam
+++ /dev/null
@@ -1,410 +0,0 @@
-//// Small examples ALSO used in the docs...
-
-import gleam/int
-import gleam/list
-import gleam/pair
-import gleam_stats/stats
-import gleeunit
-import gleeunit/should
-
-pub fn main() {
- gleeunit.main()
-}
-
-pub fn example_sum_test() {
- // An empty list returns an error
- []
- |> stats.sum()
- |> should.equal(0.)
-
- // Valid input returns a result
- [1., 2., 3.]
- |> stats.sum()
- |> should.equal(6.)
-}
-
-pub fn example_mean_test() {
- // An empty list returns an error
- []
- |> stats.mean()
- |> should.be_error()
-
- // Valid input returns a result
- [1., 2., 3.]
- |> stats.mean()
- |> should.equal(Ok(2.))
-}
-
-pub fn example_median_test() {
- // An empty list returns an error
- []
- |> stats.median()
- |> should.be_error()
-
- // Valid input returns a result
- [1., 2., 3.]
- |> stats.median()
- |> should.equal(Ok(2.))
-
- [1., 2., 3., 4.]
- |> stats.median()
- |> should.equal(Ok(2.5))
-}
-
-pub fn example_hmean_test() {
- // An empty list returns an error
- []
- |> stats.hmean()
- |> should.be_error()
-
- // List with negative numbers returns an error
- [-1., -3., -6.]
- |> stats.hmean()
- |> should.be_error()
-
- // Valid input returns a result
- [1., 3., 6.]
- |> stats.hmean()
- |> should.equal(Ok(2.))
-}
-
-pub fn example_gmean_test() {
- // An empty list returns an error
- []
- |> stats.gmean()
- |> should.be_error()
- // List with negative numbers returns an error
- [-1., -3., -6.]
- |> stats.gmean()
- |> should.be_error()
- // Valid input returns a result
- [1., 3., 9.]
- |> stats.gmean()
- |> should.equal(Ok(3.))
-}
-
-pub fn example_var_test() {
- // Degrees of freedom
- let ddof: Int = 1
-
- // An empty list returns an error
- []
- |> stats.var(ddof)
- |> should.be_error()
-
- // Valid input returns a result
- [1., 2., 3.]
- |> stats.var(ddof)
- |> should.equal(Ok(1.))
-}
-
-pub fn example_std_test() {
- // Degrees of freedom
- let ddof: Int = 1
-
- // An empty list returns an error
- []
- |> stats.std(ddof)
- |> should.be_error()
-
- // Valid input returns a result
- [1., 2., 3.]
- |> stats.std(ddof)
- |> should.equal(Ok(1.))
-}
-
-pub fn example_moment_test() {
- // An empty list returns an error
- []
- |> stats.moment(0)
- |> should.be_error()
-
- // 0th moment about the mean is 1. per definition
- [0., 1., 2., 3., 4.]
- |> stats.moment(0)
- |> should.equal(Ok(1.))
-
- // 1st moment about the mean is 0. per definition
- [0., 1., 2., 3., 4.]
- |> stats.moment(1)
- |> should.equal(Ok(0.))
-
- // 2nd moment about the mean
- [0., 1., 2., 3., 4.]
- |> stats.moment(2)
- |> should.equal(Ok(2.))
-}
-
-pub fn example_skewness_test() {
- // An empty list returns an error
- []
- |> stats.skewness()
- |> should.be_error()
-
- // No skewness
- // -> Zero skewness
- [1., 2., 3., 4.]
- |> stats.skewness()
- |> should.equal(Ok(0.))
-
- // Right-skewed distribution
- // -> Positive skewness
- [1., 1., 1., 2.]
- |> stats.skewness()
- |> fn(x: Result(Float, String)) -> Bool {
- case x {
- Ok(x) -> x >. 0.
- _ -> False
- }
- }
- |> should.be_true()
-}
-
-pub fn example_kurtosis_test() {
- // An empty list returns an error
- []
- |> stats.skewness()
- |> should.be_error()
-
- // No tail
- // -> Fisher's definition gives kurtosis -3
- [1., 1., 1., 1.]
- |> stats.kurtosis()
- |> should.equal(Ok(-3.))
-
- // Distribution with a tail
- // -> Higher kurtosis
- [1., 1., 1., 2.]
- |> stats.kurtosis()
- |> fn(x: Result(Float, String)) -> Bool {
- case x {
- Ok(x) -> x >. -3.
- _ -> False
- }
- }
- |> should.be_true()
-}
-
-pub fn example_zscore_test() {
- // An empty list returns an error
- []
- // Use degrees of freedom = 1
- |> stats.zscore(1)
- |> should.be_error()
-
- [1., 2., 3.]
- // Use degrees of freedom = 1
- |> stats.zscore(1)
- |> should.equal(Ok([-1., 0., 1.]))
-}
-
-pub fn example_percentile_test() {
- // An empty list returns an error
- []
- |> stats.percentile(40)
- |> should.be_error()
-
- // Calculate 40th percentile
- [15., 20., 35., 40., 50.]
- |> stats.percentile(40)
- |> should.equal(Ok(29.))
-}
-
-pub fn example_iqr_test() {
- // An empty list returns an error
- []
- |> stats.iqr()
- |> should.be_error()
-
- // Valid input returns a result
- [1., 2., 3., 4., 5.]
- |> stats.iqr()
- |> should.equal(Ok(3.))
-}
-
-pub fn example_freedman_diaconis_rule_test() {
- // An empty list returns an error
- []
- |> stats.freedman_diaconis_rule()
- |> should.be_error()
-
- // Calculate histogram bin widths
- list.range(0, 1000)
- |> list.map(fn(x: Int) -> Float { int.to_float(x) })
- |> stats.freedman_diaconis_rule()
- |> should.equal(Ok(10.))
-}
-
-pub fn example_range_test() {
- // Create a range
- let range = stats.Range(0., 1.)
- // Retrieve min and max values
- let stats.Range(min, max) = range
- min
- |> should.equal(0.)
- max
- |> should.equal(1.)
-}
-
-pub fn example_bin_test() {
- // Create a bin
- let bin: stats.Bin = #(stats.Range(0., 1.), 999)
- // Retrieve min and max values
- let stats.Range(min, max) = pair.first(bin)
- min
- |> should.equal(0.)
- max
- |> should.equal(1.)
- // Retrieve count
- let count = pair.second(bin)
- count
- |> should.equal(999)
-}
-
-pub fn example_histogram_test() {
- // An empty lists returns an error
- []
- |> stats.histogram(1.)
- |> should.be_error()
- // Create the bins of a histogram given a list of values
- list.range(0, 100)
- |> list.map(fn(x: Int) -> Float { int.to_float(x) })
- // Below 25. is the bin width
- // The Freedman-Diaconis’s Rule can be used to determine a decent value
- |> stats.histogram(25.)
- |> should.equal(Ok([
- #(stats.Range(0., 25.), 25),
- #(stats.Range(25., 50.), 25),
- #(stats.Range(50., 75.), 25),
- #(stats.Range(75., 100.), 25),
- ]))
-}
-
-pub fn example_correlation_test() {
- // An empty lists returns an error
- stats.correlation([], [])
- |> should.be_error()
-
- // Lists with fewer than 2 elements return an error
- stats.correlation([1.0], [1.0])
- |> should.be_error()
-
- // Lists of uneqal length return an error
- stats.correlation([1.0, 2.0, 3.0], [1.0, 2.0])
- |> should.be_error()
-
- // Perfect positive correlation
- let xarr0: List(Float) =
- list.range(0, 100)
- |> list.map(fn(x: Int) -> Float { int.to_float(x) })
- let yarr0: List(Float) =
- list.range(0, 100)
- |> list.map(fn(x: Int) -> Float { int.to_float(x) })
- stats.correlation(xarr0, yarr0)
- |> should.equal(Ok(1.))
-
- // Perfect negative correlation
- let xarr0: List(Float) =
- list.range(0, 100)
- |> list.map(fn(x: Int) -> Float { -1. *. int.to_float(x) })
- let yarr0: List(Float) =
- list.range(0, 100)
- |> list.map(fn(x: Int) -> Float { int.to_float(x) })
- stats.correlation(xarr0, yarr0)
- |> should.equal(Ok(-1.))
-}
-
-pub fn example_trim_test() {
- // An empty lists returns an error
- []
- |> stats.trim(0, 0)
- |> should.be_error()
-
- // Trim the list to only the middle part of list
- [1., 2., 3., 4., 5., 6.]
- |> stats.trim(1, 4)
- |> should.equal(Ok([2., 3., 4., 5.]))
-}
-
-pub fn example_isclose_test() {
- let val: Float = 99.
- let ref_val: Float = 100.
- // We set 'atol' and 'rtol' such that the values are equivalent
- // if 'val' is within 1 percent of 'ref_val' +/- 0.1
- let rtol: Float = 0.01
- let atol: Float = 0.10
- stats.isclose(val, ref_val, rtol, atol)
- |> should.be_true()
-}
-
-pub fn example_allclose_test() {
- let val: Float = 99.
- let ref_val: Float = 100.
- let xarr: List(Float) = list.repeat(val, 42)
- let yarr: List(Float) = list.repeat(ref_val, 42)
- // We set 'atol' and 'rtol' such that the values are equivalent
- // if 'val' is within 1 percent of 'ref_val' +/- 0.1
- let rtol: Float = 0.01
- let atol: Float = 0.10
- stats.allclose(xarr, yarr, rtol, atol)
- |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) {
- case zarr {
- Ok(arr) ->
- arr
- |> list.all(fn(a: Bool) -> Bool { a })
- |> Ok
- _ ->
- Nil
- |> Error
- }
- }
- |> should.equal(Ok(True))
-}
-
-pub fn example_amax_test() {
- // An empty lists returns an error
- []
- |> stats.amax()
- |> should.be_error()
-
- // Valid input returns a result
- [4., 4., 3., 2., 1.]
- |> stats.amax()
- |> should.equal(Ok(4.))
-}
-
-pub fn example_amin_test() {
- // An empty lists returns an error
- []
- |> stats.amin()
- |> should.be_error()
-
- // Valid input returns a result
- [4., 4., 3., 2., 1.]
- |> stats.amin()
- |> should.equal(Ok(1.))
-}
-
-pub fn example_argmax_test() {
- // An empty lists returns an error
- []
- |> stats.argmax()
- |> should.be_error()
-
- // Valid input returns a result
- [4., 4., 3., 2., 1.]
- |> stats.argmax()
- |> should.equal(Ok([0, 1]))
-}
-
-pub fn example_argmin_test() {
- // An empty lists returns an error
- []
- |> stats.argmin()
- |> should.be_error()
-
- // Valid input returns a result
- [4., 4., 3., 2., 1.]
- |> stats.argmin()
- |> should.equal(Ok([4]))
-}
diff --git a/test/gleam/gleam_community_maths_float_list_test.gleam b/test/gleam/gleam_community_maths_float_list_test.gleam
new file mode 100644
index 0000000..aea7158
--- /dev/null
+++ b/test/gleam/gleam_community_maths_float_list_test.gleam
@@ -0,0 +1,94 @@
+import gleam/int
+import gleam/list
+import gleam/pair
+import gleam_community/maths/float_list
+import gleeunit
+import gleeunit/should
+
+pub fn main() {
+ gleeunit.main()
+}
+
+pub fn float_list_all_close_test() {
+ let val: Float = 99.0
+ let ref_val: Float = 100.0
+ let xarr: List(Float) = list.repeat(val, 42)
+ let yarr: List(Float) = list.repeat(ref_val, 42)
+ // We set 'atol' and 'rtol' such that the values are equivalent
+ // if 'val' is within 1 percent of 'ref_val' +/- 0.1
+ let rtol: Float = 0.01
+ let atol: Float = 0.10
+ float_list.all_close(xarr, yarr, rtol, atol)
+ |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) {
+ case zarr {
+ Ok(arr) ->
+ arr
+ |> list.all(fn(a: Bool) -> Bool { a })
+ |> Ok
+ _ ->
+ Nil
+ |> Error
+ }
+ }
+ |> should.equal(Ok(True))
+}
+
+pub fn float_list_maximum_test() {
+ // An empty lists returns an error
+ []
+ |> float_list.maximum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4.0, 4.0, 3.0, 2.0, 1.0]
+ |> float_list.maximum()
+ |> should.equal(Ok(4.0))
+}
+
+pub fn float_list_minimum_test() {
+ // An empty lists returns an error
+ []
+ |> float_list.minimum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4.0, 4.0, 3.0, 2.0, 1.0]
+ |> float_list.minimum()
+ |> should.equal(Ok(1.0))
+}
+
+pub fn float_list_arg_maximum_test() {
+ // An empty lists returns an error
+ []
+ |> float_list.arg_maximum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4.0, 4.0, 3.0, 2.0, 1.0]
+ |> float_list.arg_maximum()
+ |> should.equal(Ok([0, 1]))
+}
+
+pub fn float_list_arg_minimum_test() {
+ // An empty lists returns an error
+ []
+ |> float_list.arg_minimum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4.0, 4.0, 3.0, 2.0, 1.0]
+ |> float_list.arg_minimum()
+ |> should.equal(Ok([4]))
+}
+
+pub fn float_list_extrema_test() {
+ // An empty lists returns an error
+ []
+ |> float_list.extrema()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4.0, 4.0, 3.0, 2.0, 1.0]
+ |> float_list.extrema()
+ |> should.equal(Ok(#(1.0, 4.0)))
+}
diff --git a/test/gleam/gleam_community_maths_float_test.gleam b/test/gleam/gleam_community_maths_float_test.gleam
index 07a628e..a144b64 100644
--- a/test/gleam/gleam_community_maths_float_test.gleam
+++ b/test/gleam/gleam_community_maths_float_test.gleam
@@ -513,65 +513,95 @@ pub fn float_to_radian_test() {
}
pub fn float_ceiling_test() {
- // Round based on 3. digit AFTER decimal point
+ // Round 3. digit AFTER decimal point
floatx.ceiling(12.0654, option.Some(3))
|> should.equal(Ok(12.066))
- // Round based on 2. digit AFTER decimal point
+ // Round 2. digit AFTER decimal point
floatx.ceiling(12.0654, option.Some(2))
|> should.equal(Ok(12.07))
- // Round based on 1. digit AFTER decimal point
+ // Round 1. digit AFTER decimal point
floatx.ceiling(12.0654, option.Some(1))
|> should.equal(Ok(12.1))
- // Round based on 0. digit BEFORE decimal point
+ // Round 0. digit BEFORE decimal point
floatx.ceiling(12.0654, option.Some(0))
|> should.equal(Ok(13.0))
- // Round based on 1. digit BEFORE decimal point
+ // Round 1. digit BEFORE decimal point
floatx.ceiling(12.0654, option.Some(-1))
|> should.equal(Ok(20.0))
- // Round based on 2. digit BEFORE decimal point
+ // Round 2. digit BEFORE decimal point
floatx.ceiling(12.0654, option.Some(-2))
|> should.equal(Ok(100.0))
- // Round based on 3. digit BEFORE decimal point
+ // Round 3. digit BEFORE decimal point
floatx.ceiling(12.0654, option.Some(-3))
|> should.equal(Ok(1000.0))
}
pub fn float_floor_test() {
- // Round based on 3. digit AFTER decimal point
+ // Round 3. digit AFTER decimal point
floatx.floor(12.0654, option.Some(3))
|> should.equal(Ok(12.065))
- // Round based on 2. digit AFTER decimal point
+ // Round 2. digit AFTER decimal point
floatx.floor(12.0654, option.Some(2))
|> should.equal(Ok(12.06))
- // Round based on 1. digit AFTER decimal point
+ // Round 1. digit AFTER decimal point
floatx.floor(12.0654, option.Some(1))
|> should.equal(Ok(12.0))
- // Round based on 0. digit BEFORE decimal point
+ // Round 0. digit BEFORE decimal point
floatx.floor(12.0654, option.Some(0))
|> should.equal(Ok(12.0))
- // Round based on 1. digit BEFORE decimal point
+ // Round 1. digit BEFORE decimal point
floatx.floor(12.0654, option.Some(-1))
|> should.equal(Ok(10.0))
- // Round based on 2. digit BEFORE decimal point
+ // Round 2. digit BEFORE decimal point
floatx.floor(12.0654, option.Some(-2))
|> should.equal(Ok(0.0))
- // Round based on 2. digit BEFORE decimal point
+ // Round 2. digit BEFORE decimal point
floatx.floor(12.0654, option.Some(-3))
|> should.equal(Ok(0.0))
}
+pub fn float_truncate_test() {
+ // Round 3. digit AFTER decimal point
+ floatx.truncate(12.0654, option.Some(3))
+ |> should.equal(Ok(12.065))
+
+ // Round 2. digit AFTER decimal point
+ floatx.truncate(12.0654, option.Some(2))
+ |> should.equal(Ok(12.06))
+
+ // Round 1. digit AFTER decimal point
+ floatx.truncate(12.0654, option.Some(1))
+ |> should.equal(Ok(12.0))
+
+ // Round 0. digit BEFORE decimal point
+ floatx.truncate(12.0654, option.Some(0))
+ |> should.equal(Ok(12.0))
+
+ // Round 1. digit BEFORE decimal point
+ floatx.truncate(12.0654, option.Some(-1))
+ |> should.equal(Ok(10.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.truncate(12.0654, option.Some(-2))
+ |> should.equal(Ok(0.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.truncate(12.0654, option.Some(-3))
+ |> should.equal(Ok(0.0))
+}
+
pub fn float_minimum_test() {
floatx.minimum(0.75, 0.5)
|> should.equal(0.5)
@@ -636,6 +666,20 @@ pub fn float_flip_sign_test() {
|> should.equal(100.0)
}
+pub fn float_copy_sign_test() {
+ floatx.copy_sign(100.0, 10.0)
+ |> should.equal(100.0)
+
+ floatx.copy_sign(-100.0, 10.0)
+ |> should.equal(100.0)
+
+ floatx.copy_sign(100.0, -10.0)
+ |> should.equal(-100.0)
+
+ floatx.copy_sign(-100.0, -10.0)
+ |> should.equal(-100.0)
+}
+
pub fn float_beta_function_test() {
io.debug("TODO: Implement tests for 'float.beta'.")
}
@@ -649,6 +693,7 @@ pub fn float_gamma_function_test() {
}
pub fn math_round_to_nearest_test() {
+ // Try with positive values
floatx.round(1.50, option.Some(0), option.Some("Nearest"))
|> should.equal(Ok(2.0))
@@ -664,14 +709,45 @@ pub fn math_round_to_nearest_test() {
floatx.round(4.50, option.Some(0), option.Some("Nearest"))
|> should.equal(Ok(4.0))
+ // Try with negative values
floatx.round(-3.50, option.Some(0), option.Some("Nearest"))
|> should.equal(Ok(-4.0))
floatx.round(-4.50, option.Some(0), option.Some("Nearest"))
|> should.equal(Ok(-4.0))
+
+ // Round 3. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(3), option.Some("Nearest"))
+ |> should.equal(Ok(12.065))
+
+ // Round 2. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(2), option.Some("Nearest"))
+ |> should.equal(Ok(12.07))
+
+ // Round 1. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(1), option.Some("Nearest"))
+ |> should.equal(Ok(12.1))
+
+ // Round 0. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(0), option.Some("Nearest"))
+ |> should.equal(Ok(12.0))
+
+ // Round 1. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-1), option.Some("Nearest"))
+ |> should.equal(Ok(10.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-2), option.Some("Nearest"))
+ |> should.equal(Ok(0.0))
+
+ // Round 3. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-3), option.Some("Nearest"))
+ |> should.equal(Ok(0.0))
}
pub fn math_round_up_test() {
+ // Note: Rounding mode "Up" is an alias for the ceiling function
+ // Try with positive values
floatx.round(0.45, option.Some(0), option.Some("Up"))
|> should.equal(Ok(1.0))
@@ -689,9 +765,29 @@ pub fn math_round_up_test() {
floatx.round(0.505, option.Some(2), option.Some("Up"))
|> should.equal(Ok(0.51))
+
+ // Try with negative values
+ floatx.round(-0.45, option.Some(0), option.Some("Up"))
+ |> should.equal(Ok(-0.0))
+
+ floatx.round(-0.50, option.Some(0), option.Some("Up"))
+ |> should.equal(Ok(-0.0))
+
+ floatx.round(-0.45, option.Some(1), option.Some("Up"))
+ |> should.equal(Ok(-0.4))
+
+ floatx.round(-0.50, option.Some(1), option.Some("Up"))
+ |> should.equal(Ok(-0.5))
+
+ floatx.round(-0.4550, option.Some(2), option.Some("Up"))
+ |> should.equal(Ok(-0.45))
+
+ floatx.round(-0.5050, option.Some(2), option.Some("Up"))
+ |> should.equal(Ok(-0.5))
}
pub fn math_round_down_test() {
+ // Note: Rounding mode "Down" is an alias for the floor function
// Try with positive values
floatx.round(0.45, option.Some(0), option.Some("Down"))
|> should.equal(Ok(0.0))
@@ -732,6 +828,8 @@ pub fn math_round_down_test() {
}
pub fn math_round_to_zero_test() {
+ // Note: Rounding mode "ToZero" is an alias for the truncate function
+ // Try with positive values
floatx.round(0.50, option.Some(0), option.Some("ToZero"))
|> should.equal(Ok(0.0))
@@ -749,9 +847,39 @@ pub fn math_round_to_zero_test() {
floatx.round(0.5075, option.Some(2), option.Some("ToZero"))
|> should.equal(Ok(0.50))
+
+ // Try with negative values
+ floatx.round(-0.50, option.Some(0), option.Some("ToZero"))
+ |> should.equal(Ok(0.0))
+
+ floatx.round(-0.75, option.Some(0), option.Some("ToZero"))
+ |> should.equal(Ok(0.0))
+
+ floatx.round(-0.45, option.Some(1), option.Some("ToZero"))
+ |> should.equal(Ok(-0.4))
+
+ floatx.round(-0.57, option.Some(1), option.Some("ToZero"))
+ |> should.equal(Ok(-0.50))
+
+ floatx.round(-0.4575, option.Some(2), option.Some("ToZero"))
+ |> should.equal(Ok(-0.45))
+
+ floatx.round(-0.5075, option.Some(2), option.Some("ToZero"))
+ |> should.equal(Ok(-0.50))
}
pub fn math_round_ties_away_test() {
+ // Try with positive values
+ floatx.round(1.40, option.Some(0), option.Some("TiesAway"))
+ |> should.equal(Ok(1.0))
+
+ floatx.round(1.50, option.Some(0), option.Some("TiesAway"))
+ |> should.equal(Ok(2.0))
+
+ floatx.round(2.50, option.Some(0), option.Some("TiesAway"))
+ |> should.equal(Ok(3.0))
+
+ // Try with negative values
floatx.round(-1.40, option.Some(0), option.Some("TiesAway"))
|> should.equal(Ok(-1.0))
@@ -764,17 +892,47 @@ pub fn math_round_ties_away_test() {
floatx.round(-2.50, option.Some(0), option.Some("TiesAway"))
|> should.equal(Ok(-3.0))
- floatx.round(1.40, option.Some(0), option.Some("TiesAway"))
- |> should.equal(Ok(1.0))
+ // Round 3. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(3), option.Some("TiesAway"))
+ |> should.equal(Ok(12.065))
- floatx.round(1.50, option.Some(0), option.Some("TiesAway"))
- |> should.equal(Ok(2.0))
+ // Round 2. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(2), option.Some("TiesAway"))
+ |> should.equal(Ok(12.07))
- floatx.round(2.50, option.Some(0), option.Some("TiesAway"))
- |> should.equal(Ok(3.0))
+ // Round 1. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(1), option.Some("TiesAway"))
+ |> should.equal(Ok(12.1))
+
+ // Round 0. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(0), option.Some("TiesAway"))
+ |> should.equal(Ok(12.0))
+
+ // Round 1. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-1), option.Some("TiesAway"))
+ |> should.equal(Ok(10.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-2), option.Some("TiesAway"))
+ |> should.equal(Ok(0.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-3), option.Some("TiesAway"))
+ |> should.equal(Ok(0.0))
}
pub fn math_round_ties_up_test() {
+ // Try with positive values
+ floatx.round(1.40, option.Some(0), option.Some("TiesUp"))
+ |> should.equal(Ok(1.0))
+
+ floatx.round(1.50, option.Some(0), option.Some("TiesUp"))
+ |> should.equal(Ok(2.0))
+
+ floatx.round(2.50, option.Some(0), option.Some("TiesUp"))
+ |> should.equal(Ok(3.0))
+
+ // Try with negative values
floatx.round(-1.40, option.Some(0), option.Some("TiesUp"))
|> should.equal(Ok(-1.0))
@@ -787,14 +945,56 @@ pub fn math_round_ties_up_test() {
floatx.round(-2.50, option.Some(0), option.Some("TiesUp"))
|> should.equal(Ok(-2.0))
- floatx.round(1.40, option.Some(0), option.Some("TiesUp"))
- |> should.equal(Ok(1.0))
+ // Round 3. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(3), option.Some("TiesUp"))
+ |> should.equal(Ok(12.065))
- floatx.round(1.50, option.Some(0), option.Some("TiesUp"))
- |> should.equal(Ok(2.0))
+ // Round 2. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(2), option.Some("TiesUp"))
+ |> should.equal(Ok(12.07))
- floatx.round(2.50, option.Some(0), option.Some("TiesUp"))
- |> should.equal(Ok(3.0))
+ // Round 1. digit AFTER decimal point
+ floatx.round(12.0654, option.Some(1), option.Some("TiesUp"))
+ |> should.equal(Ok(12.1))
+
+ // Round 0. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(0), option.Some("TiesUp"))
+ |> should.equal(Ok(12.0))
+
+ // Round 1. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-1), option.Some("TiesUp"))
+ |> should.equal(Ok(10.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-2), option.Some("TiesUp"))
+ |> should.equal(Ok(0.0))
+
+ // Round 2. digit BEFORE decimal point
+ floatx.round(12.0654, option.Some(-3), option.Some("TiesUp"))
+ |> should.equal(Ok(0.0))
+}
+
+pub fn math_round_error_test() {
+ // Test invalid rounding mode
+ floatx.round(-1.50, option.Some(0), option.Some("XYZ"))
+ |> should.be_error()
+}
+
+pub fn math_round_edge_cases_test() {
+ // The default number of digits is 0 if None is provided
+ floatx.round(12.0654, option.None, option.Some("Nearest"))
+ |> should.equal(Ok(12.0))
+
+ // The default rounding mode is "Nearest" if None is provided
+ floatx.round(12.0654, option.None, option.None)
+ |> should.equal(Ok(12.0))
+
+ // Test invalid rounding mode
+ floatx.round(12.0654, option.None, option.Some("XYZ"))
+ |> should.be_error()
+
+ floatx.round(-1.50, option.Some(0), option.Some("XYZ"))
+ |> should.be_error()
}
pub fn float_incomplete_gamma_function_test() {
@@ -865,3 +1065,14 @@ pub fn float_constants_test() {
|> floatx.is_close(3.14159, 0.0, 0.00001)
|> should.be_true()
}
+
+pub fn float_is_close_test() {
+ let val: Float = 99.0
+ let ref_val: Float = 100.0
+ // We set 'atol' and 'rtol' such that the values are equivalent
+ // if 'val' is within 1 percent of 'ref_val' +/- 0.1
+ let rtol: Float = 0.01
+ let atol: Float = 0.10
+ floatx.is_close(val, ref_val, rtol, atol)
+ |> should.be_true()
+}
diff --git a/test/gleam/gleam_community_maths_int_list_test.gleam b/test/gleam/gleam_community_maths_int_list_test.gleam
new file mode 100644
index 0000000..8dfcdba
--- /dev/null
+++ b/test/gleam/gleam_community_maths_int_list_test.gleam
@@ -0,0 +1,70 @@
+import gleam/int
+import gleam/list
+import gleam/pair
+import gleam_community/maths/int_list
+import gleeunit
+import gleeunit/should
+
+pub fn main() {
+ gleeunit.main()
+}
+
+pub fn int_list_maximum_test() {
+ // An empty lists returns an error
+ []
+ |> int_list.maximum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4, 4, 3, 2, 1]
+ |> int_list.maximum()
+ |> should.equal(Ok(4))
+}
+
+pub fn int_list_minimum_test() {
+ // An empty lists returns an error
+ []
+ |> int_list.minimum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4, 4, 3, 2, 1]
+ |> int_list.minimum()
+ |> should.equal(Ok(1))
+}
+
+pub fn int_list_arg_maximum_test() {
+ // An empty lists returns an error
+ []
+ |> int_list.arg_maximum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4, 4, 3, 2, 1]
+ |> int_list.arg_maximum()
+ |> should.equal(Ok([0, 1]))
+}
+
+pub fn int_list_arg_minimum_test() {
+ // An empty lists returns an error
+ []
+ |> int_list.arg_minimum()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4, 4, 3, 2, 1]
+ |> int_list.arg_minimum()
+ |> should.equal(Ok([4]))
+}
+
+pub fn int_list_extrema_test() {
+ // An empty lists returns an error
+ []
+ |> int_list.extrema()
+ |> should.be_error()
+
+ // Valid input returns a result
+ [4, 4, 3, 2, 1]
+ |> int_list.extrema()
+ |> should.equal(Ok(#(1, 4)))
+}
diff --git a/test/gleam/gleam_community_maths_int_test.gleam b/test/gleam/gleam_community_maths_int_test.gleam
index 2a74ef4..771f4cf 100644
--- a/test/gleam/gleam_community_maths_int_test.gleam
+++ b/test/gleam/gleam_community_maths_int_test.gleam
@@ -156,6 +156,20 @@ pub fn int_flip_sign_test() {
|> should.equal(100)
}
+pub fn int_copy_sign_test() {
+ intx.copy_sign(100, 10)
+ |> should.equal(100)
+
+ intx.copy_sign(-100, 10)
+ |> should.equal(100)
+
+ intx.copy_sign(100, -10)
+ |> should.equal(-100)
+
+ intx.copy_sign(-100, -10)
+ |> should.equal(-100)
+}
+
pub fn int_is_power_test() {
intx.is_power(10, 10)
|> should.equal(True)