diff --git a/src/gleam_community/maths/float.gleam b/src/gleam_community/maths/float.gleam index 479ad82..c661683 100644 --- a/src/gleam_community/maths/float.gleam +++ b/src/gleam_community/maths/float.gleam @@ -90,7 +90,7 @@ import gleam/option /// /// /// -/// The ceiling function rounds a given input value $$x \in \mathbb{R}$$ towards $$+\infty$$ at a specified number of digits. +/// 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"`. /// @@ -146,7 +146,7 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Result(Float, String) { /// /// /// -/// The floor function rounds a given input value $$x \in \mathbb{R}$$ towards $$-\infty$$ at a specified number of digits. +/// 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"`. /// @@ -201,7 +201,7 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Result(Float, String) { /// /// /// -/// The truncate function rounds a given input value $$x \in \mathbb{R}$$ towards $$0$$ at a specified number of digits. +/// 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"`. /// @@ -392,8 +392,10 @@ pub fn round( case digits { option.Some(a) -> { assert Ok(p) = power(10.0, int.to_float(a)) + // Round the given input x using at the specified digit do_round(p, x, mode) } + // Round the given input x using at the default digit option.None -> do_round(1.0, x, mode) } } @@ -404,9 +406,9 @@ fn do_round( mode: option.Option(String), ) -> Result(Float, String) { case mode { - // Rounding mode choices + // Determine the rounding mode option.Some("Nearest") -> - round_nearest(p, x) + round_to_nearest(p, x) |> Ok option.Some("TiesAway") -> round_ties_away(p, x) @@ -423,9 +425,9 @@ fn do_round( option.Some("Up") -> round_up(p, x) |> Ok - // Default rounding mode. The default is "Nearest" + // Otherwise, use the Default rounding mode option.None -> - round_nearest(p, x) + round_to_nearest(p, x) |> Ok _ -> "Invalid rounding mode. Valid input is 'Nearest', 'TiesAway', 'TiesUp', 'ToZero', 'Down', 'Up'." @@ -433,69 +435,65 @@ fn do_round( } } -fn round_nearest(p: Float, x: Float) -> Float { +fn round_to_nearest(p: Float, x: Float) -> Float { 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 -> { + let xabs_truncated = truncate_float(xabs) + let remainder = xabs -. xabs_truncated + case remainder { + _ if remainder >. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p + _ if remainder == 0.5 -> { assert Ok(is_even) = int.modulo(to_int(xabs), 2) case is_even == 0 { - True -> sign(x) *. truncate_float(xabs) /. p + True -> sign(x) *. xabs_truncated /. p False -> sign(x) *. truncate_float(xabs +. 1.0) /. p } } - _ -> sign(x) *. truncate_float(xabs) /. p + _ -> sign(x) *. xabs_truncated /. p } } fn round_ties_away(p: Float, x: Float) -> Float { 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 + let remainder = xabs -. truncate_float(xabs) + case remainder { + _ if remainder >=. 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 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 + let xabs_truncated = truncate_float(xabs) + let remainder = xabs -. xabs_truncated + case remainder { + _ if remainder >=. 0.5 && x >=. 0.0 -> + sign(x) *. truncate_float(xabs +. 1.0) /. p + _ -> sign(x) *. xabs_truncated /. p } } +// Rounding mode: ToZero / Truncate fn round_to_zero(p: Float, x: Float) -> Float { truncate_float(x *. p) /. p } -fn round_down(p: Float, x: Float) -> Float { - do_floor(x *. p) /. p -} - -fn round_up(p: Float, x: Float) -> Float { - do_ceiling(x *. p) /. p -} - fn truncate_float(x: Float) -> Float { do_truncate_float(x) } if erlang { - external fn do_ceiling(Float) -> Float = - "math" "ceil" + external fn do_truncate_float(Float) -> Float = + "erlang" "trunc" } if javascript { - external fn do_ceiling(Float) -> Float = - "../floatx.mjs" "ceil" + external fn do_to_int(Float) -> Int = + "../floatx.mjs" "trunc" } -if erlang { - external fn do_truncate_float(Float) -> Float = - "erlang" "trunc" +// Rounding mode: Down / Floor +fn round_down(p: Float, x: Float) -> Float { + do_floor(x *. p) /. p } if erlang { @@ -508,7 +506,56 @@ if javascript { "../floatx.mjs" "floor" } -fn to_int(x: Float) -> Int { +// Rounding mode: Up / Ceiling +fn round_up(p: Float, x: Float) -> Float { + do_ceiling(x *. p) /. p +} + +if erlang { + external fn do_ceiling(Float) -> Float = + "math" "ceil" +} + +if javascript { + external fn do_ceiling(Float) -> Float = + "../floatx.mjs" "ceil" +} + +///