Work on all modules

This commit is contained in:
NicklasXYZ 2023-01-22 00:13:58 +01:00
parent 0358fd0b92
commit 35863afec3
10 changed files with 875 additions and 791 deletions

View file

@ -19,8 +19,7 @@
//// .katex { font-size: 1.1em; }
////</style>
////
//// 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
/// </div>
///
/// 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"`.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Details</summary>
///
/// 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`)
///
/// </details>
///
/// <details>
/// <summary>Example</summary>
///
/// 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))
/// }
/// </details>
///
@ -141,35 +147,41 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// </div>
///
/// 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"`.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Details</summary>
///
/// 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`)
///
/// </details>
///
/// <details>
/// <summary>Example</summary>
///
/// 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))
/// }
/// </details>
///
@ -189,26 +201,42 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// </a>
/// </div>
///
/// 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"`.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Details</summary>
///
/// 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`)
///
/// </details>
///
/// <details>
/// <summary>Example</summary>
///
/// 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))
/// }
/// </details>
///
@ -218,8 +246,8 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// </a>
/// </div>
///
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"))
}
/// <div style="text-align: right;">
@ -228,49 +256,125 @@ pub fn truncate(x: Float, digits: Int) -> Result(Float, String) {
/// </a>
/// </div>
///
/// 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).
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Details</summary>
///
/// 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`)
///
/// </details>
///
/// <details>
/// <summary>Example</summary>
///
/// 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))
/// }
/// </details>
///
@ -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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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).
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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).
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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\]$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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\]$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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
// }
// }
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
/// </a>
/// </div>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
///
/// 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()
/// }
/// </details>
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
@ -1285,7 +1330,7 @@ if javascript {
/// error will have to be returned as the expression is otherwise undefined.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@ -1309,9 +1354,6 @@ if javascript {
/// </div>
///
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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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)
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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\]$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@ -1608,7 +1650,7 @@ if javascript {
/// occur.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@ -1656,7 +1698,7 @@ if javascript {
/// $$\(-\infty, +\infty\)$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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\]$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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 }$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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 }$$.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@ -1814,7 +1856,7 @@ pub fn to_radian(x: Float) -> Float {
/// The min function.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
@ -1916,8 +1958,7 @@ pub fn minmax(x: Float, y: Float) -> #(Float, Float) {
/// </a>
/// </div>
///
/// 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.
///
/// <div style="text-align: right;">
/// <a href="#">
@ -1953,7 +1994,7 @@ if javascript {
/// </a>
/// </div>
///
/// 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$$.
///
/// <div style="text-align: right;">
/// <a href="#">
@ -1962,18 +2003,14 @@ if javascript {
/// </div>
///
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)
}
}
/// <div style="text-align: right;">
@ -1982,6 +2019,7 @@ pub fn copy_sign(x: Float, y: Float) -> Float {
/// </a>
/// </div>
///
/// The function flips the sign of a given input value.
///
/// <div style="text-align: right;">
/// <a href="#">
@ -2212,7 +2250,7 @@ pub fn tau() -> Float {
/// Note: If the input value $$x$$ is too large an overflow error might occur.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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.
/// <details>
/// <summary>Example:</summary>
/// <summary>Example</summary>
///
/// 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()
/// }
/// </details>

View file

@ -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$$.
///
/// <details>
/// <summary>Example:</summary>
@ -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$$.
///
/// <details>
/// <summary>Example:</summary>
@ -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$$.
///
/// <details>
/// <summary>Example:</summary>
@ -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$$.
///
/// <details>
/// <summary>Example:</summary>
@ -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))
/// }
/// </details>
///
@ -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))
/// }
/// </details>
///
@ -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) {
/// </a>
/// </div>
///
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)))
/// }
/// </details>
///
@ -638,7 +632,30 @@ pub fn arg_mininmum(arr: List(Float)) -> Result(List(Int), String) {
/// </div>
///
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
}
}
}
/// <div style="text-align: right;">

View file

@ -19,8 +19,7 @@
//// .katex { font-size: 1.1em; }
////</style>
////
//// 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
/// <summary>Example:</summary>
///
/// 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)
/// }
/// </details>
@ -113,13 +112,13 @@ pub fn minimum(x: Int, y: Int) -> Int {
/// <summary>Example:</summary>
///
/// 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)
/// }
/// </details>
@ -149,13 +148,13 @@ pub fn maximum(x: Int, y: Int) -> Int {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
@ -204,7 +203,7 @@ if erlang {
if javascript {
external fn do_sign(Int) -> Int =
"../math.mjs" "sign"
"../intx.mjs" "sign"
}
/// <div style="text-align: right;">
@ -224,6 +223,31 @@ pub fn flip_sign(x: Int) -> Int {
-1 * x
}
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
/// </a>
/// </div>
///
/// The function takes two arguments $$x$$ and $$y$$ and returns $$x$$ such that it has the same sign as $$y$$.
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
/// </a>
/// </div>
///
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)
}
}
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
@ -243,22 +267,22 @@ pub fn flip_sign(x: Int) -> Int {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
@ -314,23 +338,23 @@ pub fn combination(n: Int, k: Int) -> Result(Int, String) {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
@ -379,22 +403,22 @@ pub fn factorial(n) -> Result(Int, String) {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
@ -450,13 +474,13 @@ pub fn permutation(n: Int, k: Int) -> Result(Int, String) {
/// <summary>Example:</summary>
///
/// 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)
/// }
/// </details>
@ -482,7 +506,7 @@ pub fn absolute_difference(a: Int, b: Int) -> Int {
/// <summary>Example:</summary>
///
/// 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
}

View file

@ -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
/// <summary>Example:</summary>
///
/// 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]))
/// }
/// </details>
@ -71,7 +78,7 @@ import gleam_community/maths/int as intx
/// </a>
/// </div>
///
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) {
/// <summary>Example:</summary>
///
/// 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]))
/// }
/// </details>
@ -131,7 +138,7 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) {
/// </a>
/// </div>
///
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) {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
///
@ -191,7 +198,7 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) {
/// </a>
/// </div>
///
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) {
/// <summary>Example:</summary>
///
/// 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))
/// }
/// </details>
///
@ -246,7 +253,7 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) {
/// </a>
/// </div>
///
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) {
/// <summary>Example:</summary>
///
/// 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)))
/// }
/// </details>
///
@ -300,6 +307,29 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) {
/// </a>
/// </div>
///
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
}
}
}

View file

@ -19,11 +19,8 @@
//// .katex { font-size: 1.1em; }
////</style>
////
//// 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 <a href="https://en.wikipedia.org/wiki/C_mathematical_functions"> C mathematical function</a>.
////
//// ---
////
//// * **Miscellaneous functions**
@ -39,24 +36,23 @@ import gleam/float
/// </a>
/// </div>
///
/// 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.
///
/// <details>
/// <summary>Example:</summary>
///
/// 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.]))
/// }
/// </details>

View file

@ -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-Diaconiss 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]))
}

View file

@ -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)))
}

View file

@ -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()
}

View file

@ -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)))
}

View file

@ -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)