Intoduce type 'RoundingMode'. Ref issue #1

This commit is contained in:
NicklasXYZ 2023-01-25 23:45:38 +01:00
parent b4a8df737d
commit 54ad6b092e
2 changed files with 141 additions and 156 deletions

View file

@ -92,7 +92,7 @@ import gleam/option
///
/// The ceiling function rounds a given input value $$x \in \mathbb{R}$$ to the nearest integer value (at the specified digit) that is larger than or equal to the input $$x$$.
///
/// Note: The ceiling function is used as an alias for the rounding function [`round`](#round) with rounding mode `"Up"`.
/// Note: The ceiling function is used as an alias for the rounding function [`round`](#round) with rounding mode `RoundUp`.
///
/// <details>
/// <summary>Details</summary>
@ -137,7 +137,7 @@ import gleam/option
/// </div>
///
pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
round(x, digits, option.Some("Up"))
round(x, digits, option.Some(RoundUp))
}
/// <div style="text-align: right;">
@ -148,7 +148,7 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
/// The floor function rounds input $$x \in \mathbb{R}$$ to the nearest integer value (at the specified digit) that is less than or equal to the input $$x$$
///
/// Note: The floor function is used as an alias for the rounding function [`round`](#round) with rounding mode `"Down"`.
/// Note: The floor function is used as an alias for the rounding function [`round`](#round) with rounding mode `RoundDown`.
///
/// <details>
/// <summary>Details</summary>
@ -192,7 +192,7 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// </div>
///
pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
round(x, digits, option.Some("Down"))
round(x, digits, option.Some(RoundDown))
}
/// <div style="text-align: right;">
@ -203,7 +203,7 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
/// The truncate function rounds a given input $$x \in \mathbb{R}$$ to the nearest integer value (at the specified digit) that is less than or equal to the absolute value of the input $$x$$.
///
/// Note: The truncate function is used as an alias for the rounding function [`round`](#round) with rounding mode `"ToZero"`.
/// Note: The truncate function is used as an alias for the rounding function [`round`](#round) with rounding mode `RoundToZero`.
///
/// <details>
/// <summary>Details</summary>
@ -247,7 +247,7 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// </div>
///
pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
round(x, digits, option.Some("ToZero"))
round(x, digits, option.Some(RoundToZero))
}
/// <div style="text-align: right;">
@ -259,17 +259,17 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// 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): 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).
/// - `RoundNearest` (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.
/// - `RoundTiesAway`: 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).
/// - `RoundTiesUp`: 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).
/// - `RoundToZero`: 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).
/// - `RoundDown`: 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).
/// - `RoundUp`: 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>Details</summary>
///
/// The `"Nearest"` rounding mode, rounds $$12.0654$$ to:
/// The `RoundNearest` 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`)
@ -280,7 +280,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// - $$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:
/// The `RoundTiesAway` 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`)
@ -291,7 +291,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// - $$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:
/// The `RoundTiesUp` 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`)
@ -302,7 +302,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// - $$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:
/// The `RoundToZero` 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`)
@ -313,7 +313,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// - $$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:
/// The `RoundDown` 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`)
@ -324,7 +324,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
/// - $$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:
/// The `RoundUp` 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`)
@ -346,34 +346,30 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
///
/// pub fn example() {
/// // The default number of digits is 0 if None is provided
/// floatx.round(12.0654, option.None, option.Some("Nearest"))
/// floatx.round(12.0654, option.None, option.Some(floatx.RoundNearest))
/// |> should.equal(Ok(12.0))
///
/// // The default rounding mode is "Nearest" if None is provided
/// // The default rounding mode is "RoundNearest" if None is provided
/// floatx.round(12.0654, option.None, option.None)
/// |> should.equal(Ok(12.0))
///
/// // We get an error if an invalid rounding mode is provided
/// floatx.round(12.0654, option.None, option.Some("XYZ"))
/// |> should.be_error()
///
/// // Try different rounding modes
/// floatx.round(12.0654, option.Some(2), option.Some("Nearest"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundNearest))
/// |> should.equal(Ok(12.07))
///
/// floatx.round(12.0654, option.Some(2), option.Some("TiesAway"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundTiesAway))
/// |> should.equal(Ok(12.07))
///
/// floatx.round(12.0654, option.Some(2), option.Some("TiesUp"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundTiesUp))
/// |> should.equal(Ok(12.07)
///
/// floatx.round(12.0654, option.Some(2), option.Some("ToZero"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundToZero))
/// |> should.equal(Ok(12.06))
///
/// floatx.round(12.0654, option.Some(2), option.Some("Down"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundDown))
/// |> should.equal(Ok(12.06))
///
/// floatx.round(12.0654, option.Some(2), option.Some("Up"))
/// floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundUp))
/// |> should.equal(Ok(12.07))
/// }
/// </details>
@ -387,7 +383,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
pub fn round(
x: Float,
digits: option.Option(Int),
mode: option.Option(String),
mode: option.Option(RoundingMode),
) -> Result(Float, String) {
case digits {
option.Some(a) -> {
@ -400,45 +396,51 @@ pub fn round(
}
}
pub type RoundingMode {
RoundNearest
RoundTiesAway
RoundTiesUp
RoundToZero
RoundDown
RoundUp
}
fn do_round(
p: Float,
x: Float,
mode: option.Option(String),
mode: option.Option(RoundingMode),
) -> Result(Float, String) {
case mode {
// Determine the rounding mode
option.Some("Nearest") ->
option.Some(RoundNearest) ->
round_to_nearest(p, x)
|> Ok
option.Some("TiesAway") ->
option.Some(RoundTiesAway) ->
round_ties_away(p, x)
|> Ok
option.Some("TiesUp") ->
option.Some(RoundTiesUp) ->
round_ties_up(p, x)
|> Ok
option.Some("ToZero") ->
option.Some(RoundToZero) ->
round_to_zero(p, x)
|> Ok
option.Some("Down") ->
option.Some(RoundDown) ->
round_down(p, x)
|> Ok
option.Some("Up") ->
option.Some(RoundUp) ->
round_up(p, x)
|> Ok
// Otherwise, use the Default rounding mode
option.None ->
round_to_nearest(p, x)
|> Ok
_ ->
"Invalid rounding mode. Valid input is 'Nearest', 'TiesAway', 'TiesUp', 'ToZero', 'Down', 'Up'."
|> Error
}
}
fn round_to_nearest(p: Float, x: Float) -> Float {
let xabs = float.absolute_value(x) *. p
let xabs_truncated = truncate_float(xabs)
let remainder = xabs -. xabs_truncated
let xabs: Float = float.absolute_value(x) *. p
let xabs_truncated: Float = truncate_float(xabs)
let remainder: Float = xabs -. xabs_truncated
case remainder {
_ if remainder >. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p
_ if remainder == 0.5 -> {
@ -453,8 +455,8 @@ fn round_to_nearest(p: Float, x: Float) -> Float {
}
fn round_ties_away(p: Float, x: Float) -> Float {
let xabs = float.absolute_value(x) *. p
let remainder = xabs -. truncate_float(xabs)
let xabs: Float = float.absolute_value(x) *. p
let remainder: Float = xabs -. truncate_float(xabs)
case remainder {
_ if remainder >=. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p
_ -> sign(x) *. truncate_float(xabs) /. p
@ -462,9 +464,9 @@ fn round_ties_away(p: Float, x: Float) -> Float {
}
fn round_ties_up(p: Float, x: Float) -> Float {
let xabs = float.absolute_value(x) *. p
let xabs_truncated = truncate_float(xabs)
let remainder = xabs -. xabs_truncated
let xabs: Float = float.absolute_value(x) *. p
let xabs_truncated: Float = truncate_float(xabs)
let remainder: Float = xabs -. xabs_truncated
case remainder {
_ if remainder >=. 0.5 && x >=. 0.0 ->
sign(x) *. truncate_float(xabs +. 1.0) /. p
@ -544,7 +546,7 @@ if javascript {
/// // Note: Making the following function call is equivalent
/// // but instead of returning a value of type 'Int' a value
/// // of type 'Float' is returned.
/// floatx.round(12.0654, option.Some(0), option.Some("ToZero"))
/// floatx.round(12.0654, option.Some(0), option.Some(floatx.RoundToZero))
/// |> should.equal(Ok(12.0))
/// }
/// </details>
@ -2119,21 +2121,17 @@ pub fn beta(x: Float, y: Float) -> Float {
/// </div>
///
pub fn erf(x: Float) -> Float {
let [a1, a2, a3, a4, a5] = [
let [a1, a2, a3, a4, a5]: List(Float) = [
0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429,
]
let p = 0.3275911
let p: Float = 0.3275911
// TODO: Use the implemented sign function
let sign = case x <. 0.0 {
True -> -1.0
False -> 1.0
}
let x = float.absolute_value(x)
let sign: Float = sign(x)
let x: Float = float.absolute_value(x)
// Formula 7.1.26 given in Abramowitz and Stegun.
let t = 1.0 /. { 1.0 +. p *. x }
let y =
let t: Float = 1.0 /. { 1.0 +. p *. x }
let y: Float =
1.0 -. { { { { a5 *. t +. a4 } *. t +. a3 } *. t +. a2 } *. t +. a1 } *. t *. exponential(
-1.0 *. x *. x,
)

View file

@ -694,307 +694,294 @@ 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"))
floatx.round(1.50, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(2.0))
floatx.round(1.75, option.Some(0), option.Some("Nearest"))
floatx.round(1.75, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(2.0))
floatx.round(2.00, option.Some(0), option.Some("Nearest"))
floatx.round(2.00, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(2.0))
floatx.round(3.50, option.Some(0), option.Some("Nearest"))
floatx.round(3.50, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(4.0))
floatx.round(4.50, option.Some(0), option.Some("Nearest"))
floatx.round(4.50, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(4.0))
// Try with negative values
floatx.round(-3.50, option.Some(0), option.Some("Nearest"))
floatx.round(-3.50, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(-4.0))
floatx.round(-4.50, option.Some(0), option.Some("Nearest"))
floatx.round(-4.50, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(-4.0))
// Round 3. digit AFTER decimal point
floatx.round(12.0654, option.Some(3), option.Some("Nearest"))
floatx.round(12.0654, option.Some(3), option.Some(floatx.RoundNearest))
|> should.equal(Ok(12.065))
// Round 2. digit AFTER decimal point
floatx.round(12.0654, option.Some(2), option.Some("Nearest"))
floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundNearest))
|> should.equal(Ok(12.07))
// Round 1. digit AFTER decimal point
floatx.round(12.0654, option.Some(1), option.Some("Nearest"))
floatx.round(12.0654, option.Some(1), option.Some(floatx.RoundNearest))
|> should.equal(Ok(12.1))
// Round 0. digit BEFORE decimal point
floatx.round(12.0654, option.Some(0), option.Some("Nearest"))
floatx.round(12.0654, option.Some(0), option.Some(floatx.RoundNearest))
|> should.equal(Ok(12.0))
// Round 1. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-1), option.Some("Nearest"))
floatx.round(12.0654, option.Some(-1), option.Some(floatx.RoundNearest))
|> should.equal(Ok(10.0))
// Round 2. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-2), option.Some("Nearest"))
floatx.round(12.0654, option.Some(-2), option.Some(floatx.RoundNearest))
|> should.equal(Ok(0.0))
// Round 3. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-3), option.Some("Nearest"))
floatx.round(12.0654, option.Some(-3), option.Some(floatx.RoundNearest))
|> should.equal(Ok(0.0))
}
pub fn math_round_up_test() {
// Note: Rounding mode "Up" is an alias for the ceiling function
// Note: Rounding mode "RoundUp" is an alias for the ceiling function
// Try with positive values
floatx.round(0.45, option.Some(0), option.Some("Up"))
floatx.round(0.45, option.Some(0), option.Some(floatx.RoundUp))
|> should.equal(Ok(1.0))
floatx.round(0.50, option.Some(0), option.Some("Up"))
floatx.round(0.50, option.Some(0), option.Some(floatx.RoundUp))
|> should.equal(Ok(1.0))
floatx.round(0.45, option.Some(1), option.Some("Up"))
floatx.round(0.45, option.Some(1), option.Some(floatx.RoundUp))
|> should.equal(Ok(0.5))
floatx.round(0.50, option.Some(1), option.Some("Up"))
floatx.round(0.50, option.Some(1), option.Some(floatx.RoundUp))
|> should.equal(Ok(0.5))
floatx.round(0.455, option.Some(2), option.Some("Up"))
floatx.round(0.455, option.Some(2), option.Some(floatx.RoundUp))
|> should.equal(Ok(0.46))
floatx.round(0.505, option.Some(2), option.Some("Up"))
floatx.round(0.505, option.Some(2), option.Some(floatx.RoundUp))
|> should.equal(Ok(0.51))
// Try with negative values
floatx.round(-0.45, option.Some(0), option.Some("Up"))
floatx.round(-0.45, option.Some(0), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.0))
floatx.round(-0.50, option.Some(0), option.Some("Up"))
floatx.round(-0.50, option.Some(0), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.0))
floatx.round(-0.45, option.Some(1), option.Some("Up"))
floatx.round(-0.45, option.Some(1), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.4))
floatx.round(-0.50, option.Some(1), option.Some("Up"))
floatx.round(-0.50, option.Some(1), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.5))
floatx.round(-0.4550, option.Some(2), option.Some("Up"))
floatx.round(-0.4550, option.Some(2), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.45))
floatx.round(-0.5050, option.Some(2), option.Some("Up"))
floatx.round(-0.5050, option.Some(2), option.Some(floatx.RoundUp))
|> should.equal(Ok(-0.5))
}
pub fn math_round_down_test() {
// Note: Rounding mode "Down" is an alias for the floor function
// Note: Rounding mode "RoundDown" is an alias for the floor function
// Try with positive values
floatx.round(0.45, option.Some(0), option.Some("Down"))
floatx.round(0.45, option.Some(0), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.0))
floatx.round(0.50, option.Some(0), option.Some("Down"))
floatx.round(0.50, option.Some(0), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.0))
floatx.round(0.45, option.Some(1), option.Some("Down"))
floatx.round(0.45, option.Some(1), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.4))
floatx.round(0.50, option.Some(1), option.Some("Down"))
floatx.round(0.50, option.Some(1), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.50))
floatx.round(0.4550, option.Some(2), option.Some("Down"))
floatx.round(0.4550, option.Some(2), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.45))
floatx.round(0.5050, option.Some(2), option.Some("Down"))
floatx.round(0.5050, option.Some(2), option.Some(floatx.RoundDown))
|> should.equal(Ok(0.50))
// Try with negative values
floatx.round(-0.45, option.Some(0), option.Some("Down"))
floatx.round(-0.45, option.Some(0), option.Some(floatx.RoundDown))
|> should.equal(Ok(-1.0))
floatx.round(-0.50, option.Some(0), option.Some("Down"))
floatx.round(-0.50, option.Some(0), option.Some(floatx.RoundDown))
|> should.equal(Ok(-1.0))
floatx.round(-0.45, option.Some(1), option.Some("Down"))
floatx.round(-0.45, option.Some(1), option.Some(floatx.RoundDown))
|> should.equal(Ok(-0.5))
floatx.round(-0.50, option.Some(1), option.Some("Down"))
floatx.round(-0.50, option.Some(1), option.Some(floatx.RoundDown))
|> should.equal(Ok(-0.50))
floatx.round(-0.4550, option.Some(2), option.Some("Down"))
floatx.round(-0.4550, option.Some(2), option.Some(floatx.RoundDown))
|> should.equal(Ok(-0.46))
floatx.round(-0.5050, option.Some(2), option.Some("Down"))
floatx.round(-0.5050, option.Some(2), option.Some(floatx.RoundDown))
|> should.equal(Ok(-0.51))
}
pub fn math_round_to_zero_test() {
// Note: Rounding mode "ToZero" is an alias for the truncate function
// Note: Rounding mode "RoundToZero" is an alias for the truncate function
// Try with positive values
floatx.round(0.50, option.Some(0), option.Some("ToZero"))
floatx.round(0.50, option.Some(0), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.0))
floatx.round(0.75, option.Some(0), option.Some("ToZero"))
floatx.round(0.75, option.Some(0), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.0))
floatx.round(0.45, option.Some(1), option.Some("ToZero"))
floatx.round(0.45, option.Some(1), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.4))
floatx.round(0.57, option.Some(1), option.Some("ToZero"))
floatx.round(0.57, option.Some(1), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.50))
floatx.round(0.4575, option.Some(2), option.Some("ToZero"))
floatx.round(0.4575, option.Some(2), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.45))
floatx.round(0.5075, option.Some(2), option.Some("ToZero"))
floatx.round(0.5075, option.Some(2), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.50))
// Try with negative values
floatx.round(-0.50, option.Some(0), option.Some("ToZero"))
floatx.round(-0.50, option.Some(0), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.0))
floatx.round(-0.75, option.Some(0), option.Some("ToZero"))
floatx.round(-0.75, option.Some(0), option.Some(floatx.RoundToZero))
|> should.equal(Ok(0.0))
floatx.round(-0.45, option.Some(1), option.Some("ToZero"))
floatx.round(-0.45, option.Some(1), option.Some(floatx.RoundToZero))
|> should.equal(Ok(-0.4))
floatx.round(-0.57, option.Some(1), option.Some("ToZero"))
floatx.round(-0.57, option.Some(1), option.Some(floatx.RoundToZero))
|> should.equal(Ok(-0.50))
floatx.round(-0.4575, option.Some(2), option.Some("ToZero"))
floatx.round(-0.4575, option.Some(2), option.Some(floatx.RoundToZero))
|> should.equal(Ok(-0.45))
floatx.round(-0.5075, option.Some(2), option.Some("ToZero"))
floatx.round(-0.5075, option.Some(2), option.Some(floatx.RoundToZero))
|> 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"))
floatx.round(1.40, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(1.0))
floatx.round(1.50, option.Some(0), option.Some("TiesAway"))
floatx.round(1.50, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(2.0))
floatx.round(2.50, option.Some(0), option.Some("TiesAway"))
floatx.round(2.50, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(3.0))
// Try with negative values
floatx.round(-1.40, option.Some(0), option.Some("TiesAway"))
floatx.round(-1.40, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(-1.0))
floatx.round(-1.50, option.Some(0), option.Some("TiesAway"))
floatx.round(-1.50, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(-2.0))
floatx.round(-2.00, option.Some(0), option.Some("TiesAway"))
floatx.round(-2.00, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(-2.0))
floatx.round(-2.50, option.Some(0), option.Some("TiesAway"))
floatx.round(-2.50, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(-3.0))
// Round 3. digit AFTER decimal point
floatx.round(12.0654, option.Some(3), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(3), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(12.065))
// Round 2. digit AFTER decimal point
floatx.round(12.0654, option.Some(2), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(12.07))
// Round 1. digit AFTER decimal point
floatx.round(12.0654, option.Some(1), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(1), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(12.1))
// Round 0. digit BEFORE decimal point
floatx.round(12.0654, option.Some(0), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(0), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(12.0))
// Round 1. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-1), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(-1), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(10.0))
// Round 2. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-2), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(-2), option.Some(floatx.RoundTiesAway))
|> should.equal(Ok(0.0))
// Round 2. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-3), option.Some("TiesAway"))
floatx.round(12.0654, option.Some(-3), option.Some(floatx.RoundTiesAway))
|> 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"))
floatx.round(1.40, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(1.0))
floatx.round(1.50, option.Some(0), option.Some("TiesUp"))
floatx.round(1.50, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(2.0))
floatx.round(2.50, option.Some(0), option.Some("TiesUp"))
floatx.round(2.50, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(3.0))
// Try with negative values
floatx.round(-1.40, option.Some(0), option.Some("TiesUp"))
floatx.round(-1.40, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(-1.0))
floatx.round(-1.50, option.Some(0), option.Some("TiesUp"))
floatx.round(-1.50, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(-1.0))
floatx.round(-2.00, option.Some(0), option.Some("TiesUp"))
floatx.round(-2.00, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(-2.0))
floatx.round(-2.50, option.Some(0), option.Some("TiesUp"))
floatx.round(-2.50, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(-2.0))
// Round 3. digit AFTER decimal point
floatx.round(12.0654, option.Some(3), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(3), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(12.065))
// Round 2. digit AFTER decimal point
floatx.round(12.0654, option.Some(2), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(2), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(12.07))
// Round 1. digit AFTER decimal point
floatx.round(12.0654, option.Some(1), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(1), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(12.1))
// Round 0. digit BEFORE decimal point
floatx.round(12.0654, option.Some(0), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(0), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(12.0))
// Round 1. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-1), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(-1), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(10.0))
// Round 2. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-2), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(-2), option.Some(floatx.RoundTiesUp))
|> should.equal(Ok(0.0))
// Round 2. digit BEFORE decimal point
floatx.round(12.0654, option.Some(-3), option.Some("TiesUp"))
floatx.round(12.0654, option.Some(-3), option.Some(floatx.RoundTiesUp))
|> 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"))
floatx.round(12.0654, option.None, option.Some(floatx.RoundNearest))
|> should.equal(Ok(12.0))
// The default rounding mode is "Nearest" if None is provided
// The default rounding mode is floatx.RoundNearest 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() {