diff --git a/README.md b/README.md index 98cfd57..5cc1e8d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ pub fn main() { // Find the greatest common divisor intx.gcd(54, 24) - // Returns Int: 6 + // Returns Int: 6 // Find the minimum and maximum of a list float_list.extrema([10.0, 3.0, 50.0, 20.0, 3.0]) diff --git a/src/gleam_community/maths/float.gleam b/src/gleam_community/maths/float.gleam index 399d0d2..6e510d6 100644 --- a/src/gleam_community/maths/float.gleam +++ b/src/gleam_community/maths/float.gleam @@ -20,33 +20,31 @@ //// //// //// A module containing several different kinds of mathematical constants and -//// functions applying to real numbers. +//// functions that apply to real numbers (floats). //// -//// Function naming has been adopted from C mathematical function. -//// //// --- //// //// * **Rounding functions** -//// * [`ceil`](#ceil) +//// * [`ceiling`](#ceiling) //// * [`floor`](#floor) -//// * [`trunc`](#trunc) +//// * [`truncate`](#truncate) //// * [`round`](#round) //// * **Sign and absolute value functions** -//// * [`abs2`](#abs2) -//// * [`absdiff`](#absdiff) +//// * [`absolute_difference`](#absolute_difference) //// * [`sign`](#sign) -//// * [`copysign`](#copysign) -//// * [`flipsign`](#flipsign) +//// * [`copy_sign`](#copy_sign) +//// * [`flip_sign`](#flip_sign) //// * **Powers, logs and roots** -//// * [`exp`](#exp) -//// * [`ln`](#ln) -//// * [`log`](#log) -//// * [`log10`](#log10) -//// * [`log2`](#log2) -//// * [`pow`](#pow) -//// * [`sqrt`](#sqrt) -//// * [`cbrt`](#cbrt) -//// * [`hypot`](#hypot) +//// * [`exponential`](#exponential) +//// * [`natural_logarithm`](#natural_logarithm) +//// * [`logarithm`](#logarithm) +//// * [`logarithm_2`](#logarithm_2) +//// * [`logarithm_10`](#logarithm_10) +//// * [`power`](#power) +//// * [`square_root`](#square_root) +//// * [`cube_root`](#cube_root) +//// * [`nth_root`](#nth_root) +//// * [`hypotenuse`](#hypotentuse) //// * **Trigonometric and hyperbolic functions** //// * [`acos`](#acos) //// * [`acosh`](#acosh) @@ -61,34 +59,34 @@ //// * [`sinh`](#sinh) //// * [`tan`](#tan) //// * [`tanh`](#tanh) -//// * [`deg2rad`](#deg2rad) -//// * [`rad2deg`](#rad2deg) +//// * [`to_radian`](#to_radian) +//// * [`to_degree`](#to_degree) //// * **Misc. mathematical functions** -//// * [`min`](#min) -//// * [`max`](#max) +//// * [`minimum`](#minimum) +//// * [`maximum`](#maximum) //// * [`minmax`](#minmax) //// * **Special mathematical functions** //// * [`beta`](#beta) -//// * [`erf`](#erf) +//// * [`error`](#erf) //// * [`gamma`](#gamma) -//// * [`gammainc`](#gammainc) +//// * [`incomplete_gamma`](#incomplete_gamma) //// * **Mathematical constants** //// * [`pi`](#pi) //// * [`tau`](#tau) +//// * [`e`](#e) //// * **Tests** -//// * [`isclose`](#isclose) +//// * [`is_close`](#is_close) //// * **Misc. functions** //// * [`to_int`](#to_int) - import gleam/list import gleam/int import gleam/float -import gleam/option import gleam/io +import gleam/option ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -145,11 +143,11 @@ if erlang { if javascript { external fn do_acos(Float) -> Float = - "../math.mjs" "acos" + "../floatx.mjs" "acos" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -203,11 +201,11 @@ if erlang { if javascript { external fn do_acosh(Float) -> Float = - "../math.mjs" "acosh" + "../floatx.mjs" "acosh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -226,16 +224,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.asin(0.0) +/// floatx.asin(0.0) /// |> should.equal(0.0) /// -/// math.asin(1.1) +/// floatx.asin(1.1) /// |> should.be_error() /// -/// math.asin(-1.1) +/// floatx.asin(-1.1) /// |> should.be_error() /// } /// @@ -264,11 +262,11 @@ if erlang { if javascript { external fn do_asin(Float) -> Float = - "../math.mjs" "asin" + "../floatx.mjs" "asin" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -286,10 +284,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.asinh(0.0) +/// floatx.asinh(0.0) /// |> should.equal(0.0) /// } /// @@ -311,11 +309,11 @@ if erlang { if javascript { external fn do_asinh(Float) -> Float = - "../math.mjs" "asinh" + "../floatx.mjs" "asinh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -333,10 +331,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.atan(0.0) +/// floatx.atan(0.0) /// |> should.equal(0.0) /// } /// @@ -358,11 +356,11 @@ if erlang { if javascript { external fn do_atan(Float) -> Float = - "../math.mjs" "atan" + "../floatx.mjs" "atan" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -389,10 +387,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.atan2(0.0, 0.0) +/// floatx.atan2(0.0, 0.0) /// |> should.equal(0.0) /// } /// @@ -414,11 +412,11 @@ if erlang { if javascript { external fn do_atan2(Float, Float) -> Float = - "../math.mjs" "atan2" + "../floatx.mjs" "atan2" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -437,16 +435,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.atanh(0.0) +/// floatx.atanh(0.0) /// |> should.equal(Ok(0.0)) /// -/// math.atanh(1.0) +/// floatx.atanh(1.0) /// |> should.be_error() /// -/// math.atanh(-1.0) +/// floatx.atanh(-1.0) /// |> should.be_error() /// } /// @@ -475,11 +473,11 @@ if erlang { if javascript { external fn do_atanh(Float) -> Float = - "../math.mjs" "atanh" + "../floatx.mjs" "atanh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -497,13 +495,13 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.cos(0.0) +/// floatx.cos(0.0) /// |> should.equal(1.0) /// -/// math.cos(math.pi()) +/// floatx.cos(floatx.pi()) /// |> should.equal(-1.0) /// } /// @@ -525,11 +523,11 @@ if erlang { if javascript { external fn do_cos(Float) -> Float = - "../math.mjs" "cos" + "../floatx.mjs" "cos" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -548,10 +546,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.cosh(0.0) +/// floatx.cosh(0.0) /// |> should.equal(0.0) /// } /// @@ -573,11 +571,11 @@ if erlang { if javascript { external fn do_cosh(Float) -> Float = - "../math.mjs" "cosh" + "../floatx.mjs" "cosh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -588,16 +586,18 @@ if javascript { /// \forall x \in \(-\infty, \infty\), \\; e^{(x)} = y \in \(0, +\infty\) /// \\] /// -/// If the input value is too large an overflow error might occur. +/// $$e \approx 2.71828\dots$$ is Eulers' number. +/// +/// Note: If the input value $$x$$ is too large an overflow error might occur. /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.exp(0.0) +/// floatx.exp(0.0) /// |> should.equal(1.0) /// } ///
@@ -619,11 +619,11 @@ if erlang { if javascript { external fn do_exp(Float) -> Float = - "../math.mjs" "exp" + "../floatx.mjs" "exp" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -642,16 +642,17 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam/option +/// import gleam_community/maths/float as floatx /// /// pub fn example () { -/// math.log(1.0) +/// floatx.logarithm(1.0, option.Some(10.0)) /// |> should.equal(Ok(0.0)) /// -/// math.log(math.exp(1.0)) +/// floatx.logarithm(floatx.e(), option.Some(floatx.e())) /// |> should.equal(1.0) /// -/// math.log(-1.0) +/// floatx.logarithm(-1.0, option.Some(2.0)) /// |> should.be_error() /// } /// @@ -663,16 +664,16 @@ if javascript { /// /// /// -pub fn log(x: Float, base: option.Option) -> Result(Float, String) { +pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String) { case x >. 0.0 { - True -> { + True -> case base { - option.Some(a) -> { + option.Some(a) -> case a >. 0.0 && a != 1.0 { True -> { - // Apply the change of base formula - assert Ok(numerator) = log10(x) - assert Ok(denominator) = log10(b) + // Apply the "change of base formula" + assert Ok(numerator) = logarithm_10(x) + assert Ok(denominator) = logarithm_10(a) numerator /. denominator |> Ok } @@ -680,29 +681,61 @@ pub fn log(x: Float, base: option.Option) -> Result(Float, String) { "Invalid input argument: base <= 0 or base == 1. Valid input is base > 0 and base != 1." |> Error } - case - } - _ -> { - "Invalid input argument: x <= 0. Valid input is x > 0." + _ -> + "Invalid input argument: base <= 0 or base == 1. Valid input is base > 0 and base != 1." |> Error - } } - } + _ -> + "Invalid input argument: x <= 0. Valid input is x > 0." + |> Error } - // case x >. 0.0 { - // True -> - // do_log(x) - // |> Ok - // False -> - // "Invalid input argument: x <= 0. Valid input is x > 0." - // |> Error - // } } -pub fn ln(x: Float) -> Result(Float, String) { +///
+/// +/// Spot a typo? Open an issue! +/// +///
+/// +/// The natural logarithm function: +/// +/// \\[ +/// \forall x \in \(0, \infty\), \\; \log_{e}{(x)} = y \in \(-\infty, +\infty\) +/// \\] +/// +/// The function takes a number $$x$$ in its domain $$\(0, \infty\)$$ as input and returns +/// a numeric value $$y$$ that lies in the range $$\(-\infty, \infty\)$$. +/// If the input value is outside the domain of the function an error is returned. +/// +///
+/// Example: +/// +/// import gleeunit/should +/// import gleam_community/maths/float as floatx +/// +/// pub fn example () { +/// floatx.natural_logarithm(1.0) +/// |> should.equal(Ok(0.0)) +/// +/// floatx.natural_logarithm(floatx.e()) +/// |> should.equal(1.0) +/// +/// floatx.natural_logarithm(-1.0) +/// |> should.be_error() +/// } +///
+/// +/// +///
+/// +/// Back to top ↑ +/// +///
+/// +pub fn natural_logarithm(x: Float) -> Result(Float, String) { case x >. 0.0 { True -> - do_log(x) + do_natural_logarithm(x) |> Ok False -> "Invalid input argument: x <= 0. Valid input is x > 0." @@ -711,22 +744,22 @@ pub fn ln(x: Float) -> Result(Float, String) { } if erlang { - external fn do_log(Float) -> Float = + external fn do_natural_logarithm(Float) -> Float = "math" "log" } if javascript { - external fn do_log(Float) -> Float = - "../math.mjs" "log" + external fn do_natural_logarithm(Float) -> Float = + "../floatx.mjs" "log" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
/// -/// The The base-10 logarithm function: +/// The base-10 logarithm function: /// /// \\[ /// \forall x \in \(0, \infty), \\; \log_{10}{(x)} = y \in \(-\infty, +\infty\) @@ -740,16 +773,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example () { -/// math.log10(1.0) +/// floatx.logarithm_10(1.0) /// |> should.equal(Ok(0.0)) /// -/// math.log10(10.0) +/// floatx.logarithm_10(10.0) /// |> should.equal(Ok(1.0)) /// -/// math.log10(-1.0) +/// floatx.logarithm_10(-1.0) /// |> should.be_error() /// } /// @@ -760,10 +793,10 @@ if javascript { /// /// /// -pub fn log10(x: Float) -> Result(Float, String) { +pub fn logarithm_10(x: Float) -> Result(Float, String) { case x >. 0.0 { True -> - do_log10(x) + do_logarithm_10(x) |> Ok False -> "Invalid input argument: x <= 0. Valid input is x > 0." @@ -772,17 +805,17 @@ pub fn log10(x: Float) -> Result(Float, String) { } if erlang { - external fn do_log10(Float) -> Float = + external fn do_logarithm_10(Float) -> Float = "math" "log10" } if javascript { - external fn do_log10(Float) -> Float = - "../math.mjs" "log10" + external fn do_logarithm_10(Float) -> Float = + "../floatx.mjs" "log10" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -801,16 +834,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example () { -/// math.log2(1.0) +/// floatx.logarithm_2(1.0) /// |> should.equal(Ok(0.0)) /// -/// math.log2(2.0) +/// floatx.logarithm_2(2.0) /// |> should.equal(Ok(1.0)) /// -/// math.log2(-1.0) +/// floatx.logarithm_2(-1.0) /// |> should.be_error() /// } /// @@ -821,10 +854,10 @@ if javascript { /// /// /// -pub fn log2(x: Float) -> Result(Float, String) { +pub fn logarithm_2(x: Float) -> Result(Float, String) { case x >. 0.0 { True -> - do_log2(x) + do_logarithm_2(x) |> Ok False -> "Invalid input argument: x <= 0. Valid input is x > 0." @@ -833,13 +866,13 @@ pub fn log2(x: Float) -> Result(Float, String) { } if erlang { - external fn do_log2(Float) -> Float = + external fn do_logarithm_2(Float) -> Float = "math" "log2" } if javascript { - external fn do_log2(Float) -> Float = - "../math.mjs" "log2" + external fn do_logarithm_2(Float) -> Float = + "../floatx.mjs" "log2" } // pub fn logb(x: Float, b: Float) -> Result(Float, String) { @@ -864,7 +897,7 @@ if javascript { // } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -883,16 +916,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example () { -/// math.log2(1.0) +/// floatx.logarithm_2(1.0) /// |> should.equal(Ok(0.0)) /// -/// math.log2(2.0) +/// floatx.logarithm_2(2.0) /// |> should.equal(Ok(1.0)) /// -/// math.log2(-1.0) +/// floatx.logarithm_2(-1.0) /// |> should.be_error() /// } /// @@ -904,7 +937,7 @@ if javascript { /// /// ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -923,16 +956,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.pow(2., -1.) -/// |> should.equal(0.5) +/// floatx.power(2., -1.) +/// |> should.equal(Ok(0.5)) /// -/// math.pow(2., 2.) -/// |> should.equal(4.0) +/// floatx.power(2., 2.) +/// |> should.equal(Ok(4.0)) /// -/// math.pow(-1., 0.5) +/// floatx.power(-1., 0.5) /// |> should.be_error() /// } /// @@ -943,8 +976,8 @@ if javascript { /// /// /// -pub fn pow(x: Float, y: Float) -> Result(Float, String) { - let fractional: Bool = ceil(y) -. y >. 0.0 +pub fn power(x: Float, y: Float) -> Result(Float, String) { + let fractional: Bool = ceiling(y) -. y >. 0.0 // In the following check: // 1. If the base (x) is negative and the exponent (y) is fractional // then return an error as it will otherwise be an imaginary number @@ -956,23 +989,23 @@ pub fn pow(x: Float, y: Float) -> Result(Float, String) { "Invalid input argument: x < 0 and y is fractional or x = 0 and y < 0." |> Error False -> - do_pow(x, y) + do_power(x, y) |> Ok } } if erlang { - external fn do_pow(Float, Float) -> Float = + external fn do_power(Float, Float) -> Float = "math" "pow" } if javascript { - external fn do_pow(Float, Float) -> Float = - "../math.mjs" "pow" + external fn do_power(Float, Float) -> Float = + "../floatx.mjs" "pow" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -980,23 +1013,23 @@ if javascript { /// The square root function: $$y = \sqrt[2]{x} = x^{\frac{1}{2}}$$. /// /// Note that the function is not defined if: -/// 1. The base is negative ($$x < 0$$). An error will be returned +/// 1. The input is negative ($$x < 0$$). An error will be returned /// as an imaginary number will otherwise have to be returned. /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.sqrt(1.0) -/// |> should.equal(1.0) +/// floatx.square_root(1.0) +/// |> should.equal(Ok(1.0)) /// -/// math.sqrt(4.0) -/// |> should.equal(2.0) +/// floatx.square_root(4.0) +/// |> should.equal(Ok(2.0)) /// -/// math.sqrt(-1.0) +/// floatx.square_root(-1.0) /// |> should.be_error() /// } ///
@@ -1007,7 +1040,7 @@ if javascript { /// /// /// -pub fn sqrt(x: Float) -> Result(Float, String) { +pub fn square_root(x: Float) -> Result(Float, String) { // In the following check: // 1. If x is negative then return an error as it will otherwise be an // imaginary number @@ -1016,7 +1049,7 @@ pub fn sqrt(x: Float) -> Result(Float, String) { "Invalid input argument: x < 0." |> Error False -> { - assert Ok(result) = pow(x, 1.0 /. 2.0) + assert Ok(result) = power(x, 1.0 /. 2.0) result |> Ok } @@ -1024,7 +1057,7 @@ pub fn sqrt(x: Float) -> Result(Float, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1032,23 +1065,23 @@ pub fn sqrt(x: Float) -> Result(Float, String) { /// The cube root function: $$y = \sqrt[3]{x} = x^{\frac{1}{3}}$$. /// /// Note that the function is not defined if: -/// 1. The base is negative ($$x < 0$$). An error will be returned +/// 1. The input is negative ($$x < 0$$). An error will be returned /// as an imaginary number will otherwise have to be returned. /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.cbrt(1.0) -/// |> should.equal(1.0) +/// floatx.cube_root(1.0) +/// |> should.equal(Ok(1.0)) /// -/// math.cbrt(27.0) -/// |> should.equal(3.0) +/// floatx.cube_root(27.0) +/// |> should.equal(Ok(3.0)) /// -/// math.cbrt(-1.0) +/// floatx.cube_root(-1.0) /// |> should.be_error() /// } ///
@@ -1059,7 +1092,7 @@ pub fn sqrt(x: Float) -> Result(Float, String) { /// /// /// -pub fn cbrt(x: Float) -> Result(Float, String) { +pub fn cube_root(x: Float) -> Result(Float, String) { // In the following check: // 1. If x is negative then return an error as it will otherwise be an // imaginary number @@ -1068,7 +1101,7 @@ pub fn cbrt(x: Float) -> Result(Float, String) { "Invalid input argument: x < 0." |> Error False -> { - assert Ok(result) = pow(x, 1.0 /. 3.0) + assert Ok(result) = power(x, 1.0 /. 3.0) result |> Ok } @@ -1076,7 +1109,68 @@ pub fn cbrt(x: Float) -> Result(Float, String) { } ///
-/// +/// +/// Spot a typo? Open an issue! +/// +///
+/// +/// The nth root function: $$y = \sqrt[3]{x} = x^{\frac{1}{n}}$$. +/// +/// Note that the function is not defined if: +/// 1. The input is negative ($$x < 0$$). An error will be returned +/// as an imaginary number will otherwise have to be returned. +/// +///
+/// Example: +/// +/// import gleeunit/should +/// import gleam_community/maths/float as floatx +/// +/// pub fn example() { +/// floatx.nth_root(1.0, 2) +/// |> should.equal(Ok(1.0)) +/// +/// floatx.nth_root(27.0, 3) +/// |> should.equal(Ok(3.0)) +/// +/// floatx.nth_root(256.0, 4) +/// |> should.equal(Ok(4.0)) +/// +/// floatx.nth_root(-1.0, 2) +/// |> should.be_error() +/// } +///
+/// +///
+/// +/// Back to top ↑ +/// +///
+/// +pub fn nth_root(x: Float, n: Int) -> Result(Float, String) { + // In the following check: + // 1. If x is negative then return an error as it will otherwise be an + // imaginary number + case x <. 0.0 { + True -> + "Invalid input argument: x < 0. Valid input is x > 0" + |> Error + False -> + case n >= 2 { + True -> { + assert Ok(result) = power(x, 1.0 /. int.to_float(n)) + result + |> Ok + } + False -> + "Invalid input argyment: n < 2. Valid input is n >= 2." + |> Error + } + } +} + +///
+/// /// Spot a typo? Open an issue! /// ///
@@ -1091,7 +1185,7 @@ pub fn cbrt(x: Float) -> Result(Float, String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { /// @@ -1104,31 +1198,15 @@ pub fn cbrt(x: Float) -> Result(Float, String) { /// /// /// -pub fn hypot(x: Float, y: Float, corrected: option.Option(Bool)) -> Float { - assert Ok(term1) = pow(x, 2.0) - assert Ok(term2) = pow(y, 2.0) - assert Ok(h) = sqrt(term1 +. term2) - case corrected { - option.Some(True) -> { - let ax = float.absolute_value(x) - let ay = float.absolute_value(y) - case ay >. ax { - True -> { - - } - False -> { - - } - } - } - _ -> { - h - } - } +pub fn hypotenuse(x: Float, y: Float) -> Float { + assert Ok(term1) = power(x, 2.0) + assert Ok(term2) = power(y, 2.0) + assert Ok(h) = square_root(term1 +. term2) + h } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1146,13 +1224,13 @@ pub fn hypot(x: Float, y: Float, corrected: option.Option(Bool)) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.sin(0.0) +/// floatx.sin(0.0) /// |> should.equal(0.0) /// -/// math.sin(0.5 *. math.pi()) +/// floatx.sin(0.5 *. floatx.pi()) /// |> should.equal(1.0) /// } /// @@ -1174,11 +1252,11 @@ if erlang { if javascript { external fn do_sin(Float) -> Float = - "../math.mjs" "sin" + "../floatx.mjs" "sin" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1198,10 +1276,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.sinh(0.0) +/// floatx.sinh(0.0) /// |> should.equal(0.0) /// } /// @@ -1223,11 +1301,11 @@ if erlang { if javascript { external fn do_sinh(Float) -> Float = - "../math.mjs" "sinh" + "../floatx.mjs" "sinh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1246,10 +1324,10 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.tan(0.0) +/// floatx.tan(0.0) /// |> should.equal(0.0) /// } /// @@ -1271,11 +1349,11 @@ if erlang { if javascript { external fn do_tan(Float) -> Float = - "../math.mjs" "tan" + "../floatx.mjs" "tan" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1293,16 +1371,16 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example () { -/// math.tanh(0.0) +/// floatx.tanh(0.0) /// |> should.equal(0.0) /// -/// math.tanh(25.0) +/// floatx.tanh(25.0) /// |> should.equal(1.0) /// -/// math.tanh(-25.0) +/// floatx.tanh(-25.0) /// |> should.equal(-1.0) /// } /// @@ -1324,11 +1402,11 @@ if erlang { if javascript { external fn do_tanh(Float) -> Float = - "../math.mjs" "tanh" + "../floatx.mjs" "tanh" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1340,13 +1418,13 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.rad2deg(0.0) +/// floatx.to_degree(0.0) /// |> should.equal(0.0) /// -/// math.rad2deg(2. *. pi()) +/// floatx.to_degree(2. *. pi()) /// |> should.equal(360.) /// } /// @@ -1357,12 +1435,12 @@ if javascript { /// /// /// -pub fn rad2deg(x: Float) -> Float { +pub fn to_degree(x: Float) -> Float { x *. 180.0 /. pi() } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1374,10 +1452,10 @@ pub fn rad2deg(x: Float) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.deg2rad(360.) +/// floatx.to_radian(360.) /// |> should.equal(2. *. pi()) /// } /// @@ -1388,30 +1466,30 @@ pub fn rad2deg(x: Float) -> Float { /// /// /// -pub fn deg2rad(x: Float) -> Float { +pub fn to_radian(x: Float) -> Float { x *. pi() /. 180.0 } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
/// /// The ceiling function that rounds given input $$x \in \mathbb{R}$$ towards $$+\infty$$. -/// ceil(x) returns the nearest integral value of the same type as x that is greater than or equal to x. +/// ceiling(x) returns the nearest integral value of the same type as x that is greater than or equal to x. /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.ceil(0.2) +/// floatx.ceiling(0.2) /// |> should.equal(1.0) /// -/// math.ceil(0.8) +/// floatx.ceiling(0.8) /// |> should.equal(1.0) /// } ///
@@ -1422,22 +1500,22 @@ pub fn deg2rad(x: Float) -> Float { /// /// /// -pub fn ceil(x: Float) -> Float { - do_ceil(x) +pub fn ceiling(x: Float) -> Float { + do_ceiling(x) } if erlang { - external fn do_ceil(Float) -> Float = + external fn do_ceiling(Float) -> Float = "math" "ceil" } if javascript { - external fn do_ceil(Float) -> Float = - "../math.mjs" "ceil" + external fn do_ceiling(Float) -> Float = + "../floatx.mjs" "ceil" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1449,13 +1527,13 @@ if javascript { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.floor(0.2) +/// floatx.floor(0.2) /// |> should.equal(0.0) /// -/// math.floor(0.8) +/// floatx.floor(0.8) /// |> should.equal(0.0) /// } /// @@ -1477,7 +1555,7 @@ if erlang { if javascript { external fn do_floor(Float) -> Float = - "../math.mjs" "floor" + "../floatx.mjs" "floor" } fn to_int(x: Float) -> Int { @@ -1490,30 +1568,42 @@ if erlang { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
/// -/// The function rounds a floating point number to a specific decimal precision. +/// The function rounds a floating point number to a specific decimal precision using a given 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. +/// - An alias for this rounding mode is [`truncate`](#truncate) +/// - `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`: If the last digit is equal to 5, then the previous digit is rounded towards $$0$$. +/// - `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) /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam/option +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.round(0.4444, 2) +/// floatx.round(0.4444, 2) /// |> should.equal(0.44) /// -/// math.round(0.4445, 2) +/// floatx.round(0.4445, 2) /// |> should.equal(0.44) /// -/// math.round(0.4455, 2) +/// floatx.round(0.4455, 2) /// |> should.equal(0.45) /// -/// math.round(0.4555, 2) +/// floatx.round(0.4555, 2) /// |> should.equal(0.46) /// } ///
@@ -1529,141 +1619,117 @@ pub fn round( digits: option.Option(Int), mode: option.Option(String), ) -> Result(Float, String) { + // sigdigits: option.Option(Int), case digits { - option.Some(a) -> + option.Some(a) -> { + assert Ok(p) = power(10.0, int.to_float(a)) case mode { - option.Some("Nearest") -> { - let positive = x >. 0.0 - // let geq_tie = - // float.absolute_value(x) -. float.absolute_value(truncate(x)) >=. 0.5 - let xabs = float.absolute_value(x) - let geq_tie = xabs -. truncate(xabs) >=. 0.5 - assert Ok(is_even) = int.modulo(to_int(xabs), 2) - io.debug(is_even) - case geq_tie { - True -> - case is_even == 0 { - True -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 0.0 } *. p) /. p - |> Ok - } - False -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 1.0 } *. p) /. p - |> Ok - } - } - False -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 0.0 } *. p) /. p - |> Ok - } - } - } - option.Some("TiesAway") -> { - let positive = x >. 0.0 - let xabs = float.absolute_value(x) - let g_tie = xabs -. truncate(xabs) >=. 0.5 - io.debug(xabs -. truncate(xabs)) - // assert Ok(p) = pow(10.0, int.to_float(a)) - // sign(x) *. truncate({ float.absolute_value(x) +. 1.0 } *. p) /. p - // |> Ok - case g_tie { - True -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 1.0 } *. p) /. p - |> Ok - } - False -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - truncate(x *. p) /. p - |> Ok - } - } - } - // assert Ok(p) = pow(10.0, int.to_float(a)) - // sign(x) *. truncate({ float.absolute_value(x) +. 1.0 } *. p) /. p - // |> Ok - // Round towards positive infinity - option.Some("TiesUp") -> { - let positive = x >. 0.0 - // let geq_tie = - // float.absolute_value(x) -. float.absolute_value(truncate(x)) >=. 0.5 - let xabs = float.absolute_value(x) - let geq_tie = xabs -. truncate(xabs) >=. 0.5 - case geq_tie { - True -> - case positive { - True -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 1.0 } *. p) /. p - |> Ok - } - False -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 0.0 } *. p) /. p - |> Ok - } - } - False -> - case positive { - True -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 0.0 } *. p) /. p - |> Ok - } - False -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - sign(x) *. truncate({ xabs +. 0.0 } *. p) /. p - |> Ok - } - } - } - } - option.Some("ToZero") -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - truncate(x *. p) /. p + // Rounding mode choices + option.Some("Nearest") -> + round_nearest(p, x) |> Ok - } - option.Some("Down") -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - floor(x *. p) /. p + option.Some("TiesAway") -> + round_ties_away(p, x) |> Ok - } - option.Some("Up") -> { - assert Ok(p) = pow(10.0, int.to_float(a)) - ceil(x *. p) /. p + 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 } + } _ -> "Invalid!" |> Error } - // assert Ok(p) = pow(10.0, int.to_float(digits)) - // int.to_float(float.round(x *. p)) /. p } -pub fn truncate(x: Float) -> Float { - do_truncate(x) +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 -> + case is_even == 0 { + True -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. p + False -> sign(x) *. truncate_float({ xabs +. 1.0 } *. p) /. p + } + False -> sign(x) *. truncate_float({ xabs +. 0.0 } *. p) /. 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 + } +} + +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 + } + } +} + +fn round_to_zero(p: Float, x: Float) -> Float { + truncate_float(x *. p) /. p +} + +fn round_down(p: Float, x: Float) -> Float { + floor(x *. p) /. p +} + +fn round_up(p: Float, x: Float) -> Float { + ceiling(x *. p) /. p +} + +fn truncate_float(x: Float) -> Float { + do_truncate_float(x) } if erlang { - external fn do_truncate(Float) -> Float = + external fn do_truncate_float(Float) -> Float = "erlang" "trunc" } // pub fn round_to_nearest_ties_away(x: Float, digits: Int) -> Float { -// assert Ok(p) = pow(10.0, int.to_float(digits)) +// assert Ok(p) = power(10.0, int.to_float(digits)) // int.to_float(float.round(x *. p)) /. p // } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1674,19 +1740,19 @@ if erlang { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.round(0.4444, 2) +/// floatx.round(0.4444, 2) /// |> should.equal(0.44) /// -/// math.round(0.4445, 2) +/// floatx.round(0.4445, 2) /// |> should.equal(0.44) /// -/// math.round(0.4455, 2) +/// floatx.round(0.4455, 2) /// |> should.equal(0.45) /// -/// math.round(0.4555, 2) +/// floatx.round(0.4555, 2) /// |> should.equal(0.46) /// } /// @@ -1697,13 +1763,14 @@ if erlang { /// /// /// -pub fn trunc(x: Float, precision: Int) -> Float { - assert Ok(p) = pow(10.0, int.to_float(precision)) - int.to_float(float.round(x *. p)) /. p +pub fn truncate(x: Float, precision: Int) -> Float { + todo + // assert Ok(p) = power(10.0, int.to_float(precision)) + // int.to_float(float.round(x *. p)) /. p } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1714,13 +1781,13 @@ pub fn trunc(x: Float, precision: Int) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.min(2.0, 1.5) +/// floatx.minimum(2.0, 1.5) /// |> should.equal(1.5) /// -/// math.min(1.5, 2.0) +/// floatx.minimum(1.5, 2.0) /// |> should.equal(1.5) /// } /// @@ -1731,7 +1798,7 @@ pub fn trunc(x: Float, precision: Int) -> Float { /// /// /// -pub fn min(x: Float, y: Float) -> Float { +pub fn minimum(x: Float, y: Float) -> Float { case x <. y { True -> x False -> y @@ -1739,7 +1806,7 @@ pub fn min(x: Float, y: Float) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1750,13 +1817,13 @@ pub fn min(x: Float, y: Float) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.min(2.0, 1.5) +/// floatx.maximum(2.0, 1.5) /// |> should.equal(1.5) /// -/// math.min(1.5, 2.0) +/// floatx.maximum(1.5, 2.0) /// |> should.equal(1.5) /// } /// @@ -1767,7 +1834,7 @@ pub fn min(x: Float, y: Float) -> Float { /// /// /// -pub fn max(x: Float, y: Float) -> Float { +pub fn maximum(x: Float, y: Float) -> Float { case x >. y { True -> x False -> y @@ -1775,7 +1842,7 @@ pub fn max(x: Float, y: Float) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1786,13 +1853,13 @@ pub fn max(x: Float, y: Float) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.minmax(2.0, 1.5) +/// floatx.minmax(2.0, 1.5) /// |> should.equal(#(1.5, 2.0)) /// -/// math.minmax(1.5, 2.0) +/// floatx.minmax(1.5, 2.0) /// |> should.equal(#(1.5, 2.0)) /// } /// @@ -1804,11 +1871,11 @@ pub fn max(x: Float, y: Float) -> Float { /// /// pub fn minmax(x: Float, y: Float) -> #(Float, Float) { - #(min(x, y), max(x, y)) + #(minimum(x, y), maximum(x, y)) } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1841,11 +1908,40 @@ if erlang { if javascript { external fn do_sign(Float) -> Float = - "../math.mjs" "sign" + "../floatx.mjs" "sign" } ///
-/// +/// +/// Spot a typo? Open an issue! +/// +///
+/// +/// The function returns $$x$$ such that it has the same sign as $$y$$. +/// +///
+/// +/// Back to top ↑ +/// +///
+/// +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 +} + +///
+/// /// Spot a typo? Open an issue! /// ///
@@ -1857,12 +1953,12 @@ if javascript { /// /// /// -pub fn flipsign(x: Float) -> Float { +pub fn flip_sign(x: Float) -> Float { -1.0 *. x } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1886,7 +1982,7 @@ pub fn beta(x: Float, y: Float) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1922,7 +2018,7 @@ pub fn erf(x: Float) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1968,15 +2064,15 @@ fn gamma_lanczos(x: Float) -> Float { }, ) let t: Float = z +. lanczos_g +. 0.5 - assert Ok(v1) = pow(2.0 *. pi(), 0.5) - assert Ok(v2) = pow(t, z +. 0.5) + assert Ok(v1) = power(2.0 *. pi(), 0.5) + assert Ok(v2) = power(t, z +. 0.5) v1 *. v2 *. exp(-1.0 *. t) *. x } } } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -1992,11 +2088,11 @@ fn gamma_lanczos(x: Float) -> Float { /// /// /// -pub fn gammainc(a: Float, x: Float) -> Result(Float, String) { +pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, String) { case a >. 0.0 && x >=. 0.0 { True -> { - assert Ok(v) = pow(x, a) - v *. exp(-1.0 *. x) *. gammainc_sum(a, x, 1.0 /. a, 0.0, 1.0) + assert Ok(v) = power(x, a) + v *. exp(-1.0 *. x) *. incomplete_gamma_sum(a, x, 1.0 /. a, 0.0, 1.0) |> Ok } @@ -2006,19 +2102,25 @@ pub fn gammainc(a: Float, x: Float) -> Result(Float, String) { } } -fn gammainc_sum(a: Float, x: Float, t: Float, s: Float, n: Float) -> Float { +fn incomplete_gamma_sum( + a: Float, + x: Float, + t: Float, + s: Float, + n: Float, +) -> Float { case t { 0.0 -> s _ -> { let ns: Float = s +. t let nt: Float = t *. { x /. { a +. n } } - gammainc_sum(a, x, nt, ns, n +. 1.0) + incomplete_gamma_sum(a, x, nt, ns, n +. 1.0) } } } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -2042,11 +2144,11 @@ if erlang { if javascript { external fn do_pi() -> Float = - "../math.mjs" "pi" + "../floatx.mjs" "pi" } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -2064,7 +2166,40 @@ pub fn tau() -> Float { } ///
-/// +/// +/// Spot a typo? Open an issue! +/// +///
+/// +/// Euler's number $$e \approx 2.71828\dots$$. +/// +/// Note: If the input value $$x$$ is too large an overflow error might occur. +/// +///
+/// Example: +/// +/// import gleeunit/should +/// import gleam_community/maths/float as floatx +/// +/// pub fn example() { +/// floatx.e() +/// |> floatx.is_close(2.7128, 0.0, 0.000001) +/// |> should.be_true() +/// } +///
+/// +///
+/// +/// Back to top ↑ +/// +///
+/// +pub fn e() -> Float { + exp(1.0) +} + +///
+/// /// Spot a typo? Open an issue! /// ///
@@ -2082,13 +2217,13 @@ pub fn tau() -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/math +/// import gleam_community/maths/float as floatx /// /// pub fn example() { -/// math.absdiff(-10.0, 10.0) +/// floatx.absolute_difference(-10.0, 10.0) /// |> should.equal(20.0) /// -/// math.absdiff(0.0, -2.0) +/// floatx.absolute_difference(0.0, -2.0) /// |> should.equal(2.0) /// } /// @@ -2099,13 +2234,13 @@ pub fn tau() -> Float { /// /// /// -pub fn absdiff(a: Float, b: Float) -> Float { +pub fn absolute_difference(a: Float, b: Float) -> Float { a -. b |> float.absolute_value() } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -2132,7 +2267,7 @@ pub fn absdiff(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.isclose(val, ref_val, rtol, atol) +/// stats.is_close(val, ref_val, rtol, atol) /// |> should.be_true() /// } /// @@ -2143,8 +2278,8 @@ pub fn absdiff(a: Float, b: Float) -> Float { /// /// /// -pub fn isclose(a: Float, b: Float, rtol: Float, atol: Float) -> Bool { - let x: Float = float.absolute_value(a -. b) +pub fn is_close(a: Float, b: Float, rtol: Float, atol: Float) -> Bool { + let x: Float = absolute_difference(a, b) let y: Float = atol +. rtol *. float.absolute_value(b) case x <=. y { True -> True diff --git a/src/gleam_community/maths/float_list.gleam b/src/gleam_community/maths/float_list.gleam index 008b1d3..f835b5e 100644 --- a/src/gleam_community/maths/float_list.gleam +++ b/src/gleam_community/maths/float_list.gleam @@ -28,22 +28,22 @@ //// //// * **Distances, sums and products** //// * [`sum`](#sum) -//// * [`prod`](#prod) +//// * [`product`](#product) //// * [`norm`](#norm) -//// * [`cumsum`](#cumsum) -//// * [`cumprod`](#cumprod) +//// * [`cumulative_sum`](#cumulative_sum) +//// * [`cumulative_product`](#cumulative_product) //// * **Ranges and intervals** -//// * [`linspace`](#linspace) -//// * [`logspace`](#linspace) -//// * [`geomspace`](#linspace) +//// * [`linear_space`](#linear_space) +//// * [`logarithm_space`](#logarithm_space) +//// * [`geometric_space`](#geometric_space) //// * **Misc. mathematical functions** -//// * [`amax`](#amax) -//// * [`amin`](#amin) -//// * [`argmax`](#argmax) -//// * [`argmin`](#argmin) +//// * [`maximum`](#maximum) +//// * [`minimum`](#minimum) //// * [`extrema`](#extrema) +//// * [`argmax`](#arg_maximum) +//// * [`argmin`](#arg_minimum) //// * **Tests** -//// * [`allclose`](#allclose) +//// * [`all_close`](#all_close) //// * **Misc. functions** //// * [`trim`](#trim) @@ -51,10 +51,11 @@ import gleam/list import gleam/int import gleam/float import gleam/pair +import gleam/option import gleam_community/maths/float as floatx ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -67,7 +68,7 @@ import gleam_community/maths/float as floatx /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// @@ -80,30 +81,29 @@ import gleam_community/maths/float as floatx /// /// /// -pub fn linspace( +pub fn linear_space( start: Float, stop: Float, num: Int, - endpoint: option.Option, - retstep: option.Option, + endpoint: option.Option(Bool), ) -> List(Float) { todo } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
/// -/// Return numbers spaced evenly on a log scale. +/// Return numbers spaced evenly on a logarrithmic scale. /// In linear space, the sequence starts at base ** start (base to the power of start) and ends with base ** stop. /// ///
/// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// @@ -116,19 +116,18 @@ pub fn linspace( /// /// /// -pub fn logspace( +pub fn logarithm_space( start: Float, stop: Float, num: Int, - endpoint: option.Option, - retstep: option.Option, + endpoint: option.Option(Bool), base: Int, ) -> List(Float) { todo } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -140,7 +139,7 @@ pub fn logspace( /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// @@ -153,18 +152,17 @@ pub fn logspace( /// /// /// -pub fn geomspace( +pub fn geometric_space( start: Float, stop: Float, num: Int, - endpoint: option.Option, - retstep: option.Option, + endpoint: option.Option(Bool), ) -> List(Float) { todo } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -182,17 +180,17 @@ pub fn geomspace( /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty list returns an error /// [] -/// |> stats.sum() +/// |> float_list.sum() /// |> should.equal(0.) /// /// // Valid input returns a result /// [1., 2., 3.] -/// |> stats.sum() +/// |> float_list.sum() /// |> should.equal(6.) /// } ///
@@ -213,7 +211,7 @@ pub fn sum(arr: List(Float)) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -231,17 +229,17 @@ pub fn sum(arr: List(Float)) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty list returns an error /// [] -/// |> stats.sum() +/// |> float_list.sum() /// |> should.equal(0.) /// /// // Valid input returns a result /// [1., 2., 3.] -/// |> stats.prod() +/// |> float_list.product() /// |> should.equal(6.) /// } /// @@ -252,7 +250,7 @@ pub fn sum(arr: List(Float)) -> Float { /// /// /// -pub fn prod(arr: List(Float)) -> Float { +pub fn product(arr: List(Float)) -> Float { case arr { [] -> 0.0 _ -> @@ -262,7 +260,7 @@ pub fn prod(arr: List(Float)) -> Float { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -280,18 +278,17 @@ pub fn prod(arr: List(Float)) -> Float { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { -/// // An empty list returns an error /// [] -/// |> stats.sum() -/// |> should.equal(0.) +/// |> float_list.cumulative_sum() +/// |> should.equal([]) /// /// // Valid input returns a result -/// [1., 2., 3.] -/// |> stats.sum() -/// |> should.equal(6.) +/// [1.0, 2.0, 3.0] +/// |> float_list.cumulative_sum() +/// |> should.equal([1.0, 3.0, 6.0]) /// } /// /// @@ -301,12 +298,12 @@ pub fn prod(arr: List(Float)) -> Float { /// /// /// -pub fn cumsum(arr: List(Float)) -> List(Float) { +pub fn cumulative_sum(arr: List(Float)) -> List(Float) { todo } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -324,18 +321,18 @@ pub fn cumsum(arr: List(Float)) -> List(Float) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty list returns an error /// [] -/// |> stats.sum() +/// |> float_list.sum() /// |> should.equal(0.) /// /// // Valid input returns a result -/// [1., 2., 3.] -/// |> stats.prod() -/// |> should.equal(6.) +/// [1.0, 2.0, 3.0] +/// |> float_list.cumulative_product() +/// |> should.equal([1.0, 2.0, 6.0]) /// } /// /// @@ -345,12 +342,12 @@ pub fn cumsum(arr: List(Float)) -> List(Float) { /// /// /// -pub fn cumprod(arr: List(Float)) -> List(Float) { +pub fn cumumlative_product(arr: List(Float)) -> List(Float) { todo } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -360,7 +357,7 @@ pub fn cumprod(arr: List(Float)) -> List(Float) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// @@ -378,7 +375,7 @@ pub fn norm(xarr: List(Float), yarr: List(Float), p: Int) -> List(Float) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -389,17 +386,17 @@ pub fn norm(xarr: List(Float), yarr: List(Float), p: Int) -> List(Float) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty lists returns an error /// [] -/// |> stats.amax() +/// |> float_list.maximum() /// |> should.be_error() /// /// // Valid input returns a result /// [4., 4., 3., 2., 1.] -/// |> stats.amax() +/// |> float_list.maximum() /// |> should.equal(Ok(4.)) /// } /// @@ -410,7 +407,7 @@ pub fn norm(xarr: List(Float), yarr: List(Float), p: Int) -> List(Float) { /// /// /// -pub fn amax(arr: List(Float)) -> Result(Float, String) { +pub fn maximum(arr: List(Float)) -> Result(Float, String) { case arr { [] -> "Invalid input argument: The list is empty." @@ -433,7 +430,7 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -444,17 +441,17 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty lists returns an error /// [] -/// |> stats.amin() +/// |> float_list.minimum() /// |> should.be_error() /// /// // Valid input returns a result /// [4., 4., 3., 2., 1.] -/// |> stats.amin() +/// |> float_list.minimum() /// |> should.equal(Ok(1.)) /// } /// @@ -465,7 +462,7 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) { /// /// /// -pub fn amin(arr: List(Float)) -> Result(Float, String) { +pub fn minimum(arr: List(Float)) -> Result(Float, String) { case arr { [] -> "Invalid input argument: The list is empty." @@ -488,7 +485,7 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -499,17 +496,17 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty lists returns an error /// [] -/// |> stats.argmax() +/// |> float_list.arg_maximum() /// |> should.be_error() /// /// // Valid input returns a result /// [4., 4., 3., 2., 1.] -/// |> stats.argmax() +/// |> float_list.arg_maximum() /// |> should.equal(Ok([0, 1])) /// } /// @@ -520,7 +517,7 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) { /// /// /// -pub fn argmax(arr: List(Float)) -> Result(List(Int), String) { +pub fn arg_maximum(arr: List(Float)) -> Result(List(Int), String) { case arr { [] -> "Invalid input argument: The list is empty." @@ -528,7 +525,7 @@ 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 { @@ -548,7 +545,7 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -559,17 +556,17 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty lists returns an error /// [] -/// |> stats.argmin() +/// |> float_list.arg_minimum() /// |> should.be_error() /// /// // Valid input returns a result /// [4., 4., 3., 2., 1.] -/// |> stats.argmin() +/// |> float_list.arg_minimum() /// |> should.equal(Ok([4])) /// } /// @@ -580,7 +577,7 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) { /// /// /// -pub fn argmin(arr: List(Float)) -> Result(List(Int), String) { +pub fn arg_mininmum(arr: List(Float)) -> Result(List(Int), String) { case arr { [] -> "Invalid input argument: The list is empty." @@ -588,7 +585,7 @@ 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 { @@ -608,7 +605,7 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -619,17 +616,17 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam_community/maths/float_list /// /// pub fn example () { /// // An empty lists returns an error /// [] -/// |> stats.amin() +/// |> float_list.extrema() /// |> should.be_error() /// /// // Valid input returns a result /// [4., 4., 3., 2., 1.] -/// |> stats.amin() +/// |> float_list.extrema() /// |> should.equal(Ok(1.)) /// } /// @@ -645,7 +642,7 @@ pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -657,7 +654,8 @@ pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) { /// Example: /// /// import gleeunit/should -/// import gleam_stats/stats +/// import gleam/list +/// import gleam_community/maths/float_list /// /// pub fn example () { /// let val: Float = 99. @@ -668,7 +666,7 @@ pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) { /// // 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) +/// float_list.all_close(xarr, yarr, rtol, atol) /// |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) { /// case zarr { /// Ok(arr) -> @@ -688,7 +686,7 @@ pub fn extrema(arr: List(Float)) -> Result(#(Float, Float), String) { /// /// /// -pub fn allclose( +pub fn all_close( xarr: List(Float), yarr: List(Float), rtol: Float, @@ -703,7 +701,7 @@ pub fn allclose( True -> list.zip(xarr, yarr) |> list.map(fn(z: #(Float, Float)) -> Bool { - floatx.isclose(pair.first(z), pair.second(z), rtol, atol) + floatx.is_close(pair.first(z), pair.second(z), rtol, atol) }) |> Ok } diff --git a/src/gleam_community/maths/int.gleam b/src/gleam_community/maths/int.gleam index d86cd6f..32d7115 100644 --- a/src/gleam_community/maths/int.gleam +++ b/src/gleam_community/maths/int.gleam @@ -65,7 +65,7 @@ import gleam/int import gleam/float ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -101,7 +101,7 @@ pub fn min(x: Int, y: Int) -> Int { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -137,7 +137,7 @@ pub fn max(x: Int, y: Int) -> Int { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -170,7 +170,7 @@ pub fn minmax(x: Int, y: Int) -> #(Int, Int) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -207,7 +207,7 @@ if javascript { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -224,7 +224,7 @@ pub fn flipsign(x: Int) -> Int { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -301,7 +301,7 @@ pub fn combination(n: Int, k: Int) -> Result(Int, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -362,7 +362,7 @@ pub fn factorial(n) -> Result(Int, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -431,7 +431,7 @@ pub fn permutation(n: Int, k: Int) -> Result(Int, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
diff --git a/src/gleam_community/maths/int_list.gleam b/src/gleam_community/maths/int_list.gleam index a4ae823..0b928d0 100644 --- a/src/gleam_community/maths/int_list.gleam +++ b/src/gleam_community/maths/int_list.gleam @@ -39,7 +39,7 @@ import gleam/pair import gleam_community/maths/int as intx ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -99,7 +99,7 @@ pub fn argmin(arr: List(Float)) -> Result(List(Int), String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -159,7 +159,7 @@ pub fn argmax(arr: List(Float)) -> Result(List(Int), String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -214,7 +214,7 @@ pub fn amax(arr: List(Float)) -> Result(Float, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
@@ -269,7 +269,7 @@ pub fn amin(arr: List(Float)) -> Result(Float, String) { } ///
-/// +/// /// Spot a typo? Open an issue! /// ///
diff --git a/src/gleam_community/maths/list.gleam b/src/gleam_community/maths/list.gleam index ba0d74a..634ac83 100644 --- a/src/gleam_community/maths/list.gleam +++ b/src/gleam_community/maths/list.gleam @@ -34,7 +34,7 @@ import gleam/int import gleam/float ///
-/// +/// /// Spot a typo? Open an issue! /// ///
diff --git a/test/gleam/gleam_community_maths_float_test.gleam b/test/gleam/gleam_community_maths_float_test.gleam index a20323a..ca6fc92 100644 --- a/test/gleam/gleam_community_maths_float_test.gleam +++ b/test/gleam/gleam_community_maths_float_test.gleam @@ -10,17 +10,17 @@ pub fn main() { } pub fn float_acos_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values assert Ok(result) = floatx.acos(1.0) result - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() assert Ok(result) = floatx.acos(0.5) result - |> floatx.isclose(1.047197, 0.0, tol) + |> floatx.is_close(1.047197, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated @@ -33,12 +33,12 @@ pub fn float_acos_test() { } pub fn float_acosh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values assert Ok(result) = floatx.acosh(1.0) result - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated @@ -53,10 +53,10 @@ pub fn float_asin_test() { floatx.asin(0.0) |> should.equal(Ok(0.0)) - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) assert Ok(result) = floatx.asin(0.5) result - |> floatx.isclose(0.523598, 0.0, tol) + |> floatx.is_close(0.523598, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated @@ -69,91 +69,91 @@ pub fn float_asin_test() { } pub fn float_asinh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.asinh(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.asinh(0.5) - |> floatx.isclose(0.481211, 0.0, tol) + |> floatx.is_close(0.481211, 0.0, tol) |> should.be_true() } pub fn float_atan_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.atan(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.atan(0.5) - |> floatx.isclose(0.463647, 0.0, tol) + |> floatx.is_close(0.463647, 0.0, tol) |> should.be_true() } pub fn math_atan2_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.atan2(0.0, 0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.atan2(0.0, 1.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() // Check atan2(y=1.0, x=0.5) // Should be equal to atan(y / x) for any x > 0 and any y let result = floatx.atan(1.0 /. 0.5) floatx.atan2(1.0, 0.5) - |> floatx.isclose(result, 0.0, tol) + |> floatx.is_close(result, 0.0, tol) |> should.be_true() // Check atan2(y=2.0, x=-1.5) // Should be equal to pi + atan(y / x) for any x < 0 and y >= 0 let result = floatx.pi() +. floatx.atan(2.0 /. -1.5) floatx.atan2(2.0, -1.5) - |> floatx.isclose(result, 0.0, tol) + |> floatx.is_close(result, 0.0, tol) |> should.be_true() // Check atan2(y=-2.0, x=-1.5) // Should be equal to atan(y / x) - pi for any x < 0 and y < 0 let result = floatx.atan(-2.0 /. -1.5) -. floatx.pi() floatx.atan2(-2.0, -1.5) - |> floatx.isclose(result, 0.0, tol) + |> floatx.is_close(result, 0.0, tol) |> should.be_true() // Check atan2(y=1.5, x=0.0) // Should be equal to pi/2 for x = 0 and any y > 0 let result = floatx.pi() /. 2.0 floatx.atan2(1.5, 0.0) - |> floatx.isclose(result, 0.0, tol) + |> floatx.is_close(result, 0.0, tol) |> should.be_true() // Check atan2(y=-1.5, x=0.0) // Should be equal to -pi/2 for x = 0 and any y < 0 let result = -1.0 *. floatx.pi() /. 2.0 floatx.atan2(-1.5, 0.0) - |> floatx.isclose(result, 0.0, tol) + |> floatx.is_close(result, 0.0, tol) |> should.be_true() } pub fn float_atanh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values assert Ok(result) = floatx.atanh(0.0) result - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() assert Ok(result) = floatx.atanh(0.5) result - |> floatx.isclose(0.549306, 0.0, tol) + |> floatx.is_close(0.549306, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated @@ -172,32 +172,32 @@ pub fn float_atanh_test() { } pub fn float_cos_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.cos(0.0) - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() floatx.cos(floatx.pi()) - |> floatx.isclose(-1.0, 0.0, tol) + |> floatx.is_close(-1.0, 0.0, tol) |> should.be_true() floatx.cos(0.5) - |> floatx.isclose(0.877582, 0.0, tol) + |> floatx.is_close(0.877582, 0.0, tol) |> should.be_true() } pub fn float_cosh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.cosh(0.0) - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() floatx.cosh(0.5) - |> floatx.isclose(1.127625, 0.0, tol) + |> floatx.is_close(1.127625, 0.0, tol) |> should.be_true() // An (overflow) error might occur when given an input // value that will result in a too large output value @@ -205,16 +205,16 @@ pub fn float_cosh_test() { // runtime. } -pub fn float_exp_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) +pub fn float_exponential_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.exp(0.0) - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() floatx.exp(0.5) - |> floatx.isclose(1.648721, 0.0, tol) + |> floatx.is_close(1.648721, 0.0, tol) |> should.be_true() // An (overflow) error might occur when given an input // value that will result in a too large output value @@ -222,205 +222,233 @@ pub fn float_exp_test() { // runtime. } -pub fn float_log_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) +pub fn float_natural_logarithm_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values - floatx.log(1.0) + floatx.natural_logarithm(1.0) |> should.equal(Ok(0.0)) - assert Ok(result) = floatx.log(0.5) + assert Ok(result) = floatx.natural_logarithm(0.5) result - |> floatx.isclose(-0.693147, 0.0, tol) + |> floatx.is_close(-0.693147, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated // outside its domain - floatx.log(-1.0) + floatx.natural_logarithm(-1.0) |> should.be_error() } -pub fn floatx_log10_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) +pub fn float_logarithm_10_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values - assert Ok(result) = floatx.log10(1.0) + assert Ok(result) = floatx.logarithm_10(1.0) result - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() - assert Ok(result) = floatx.log10(10.0) + assert Ok(result) = floatx.logarithm_10(10.0) result - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() - assert Ok(result) = floatx.log10(50.0) + assert Ok(result) = floatx.logarithm_10(50.0) result - |> floatx.isclose(1.698970, 0.0, tol) + |> floatx.is_close(1.698970, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated // outside its domain - floatx.log10(-1.0) + floatx.logarithm_10(-1.0) |> should.be_error() } -pub fn floatx_log2_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) +pub fn float_logarithm_2_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values - floatx.log2(1.0) + floatx.logarithm_2(1.0) |> should.equal(Ok(0.0)) - floatx.log2(2.0) + floatx.logarithm_2(2.0) |> should.equal(Ok(1.0)) - assert Ok(result) = floatx.log2(5.0) + assert Ok(result) = floatx.logarithm_2(5.0) result - |> floatx.isclose(2.321928, 0.0, tol) + |> floatx.is_close(2.321928, 0.0, tol) |> should.be_true() // Check that we get an error when the function is evaluated // outside its domain - floatx.log2(-1.0) + floatx.logarithm_2(-1.0) |> should.be_error() } -pub fn floatx_logb_test() { +pub fn float_logarithm_test() { // Check that the function agrees, at some arbitrary input // points, with known function values - floatx.logb(10.0, 10.0) + floatx.logarithm(10.0, option.Some(10.0)) |> should.equal(Ok(1.0)) - floatx.logb(10.0, 100.0) + floatx.logarithm(10.0, option.Some(100.0)) |> should.equal(Ok(0.5)) - floatx.logb(1.0, 0.25) + floatx.logarithm(1.0, option.Some(0.25)) |> should.equal(Ok(0.0)) // Check that we get an error when the function is evaluated // outside its domain - floatx.logb(1.0, 1.0) + floatx.logarithm(1.0, option.Some(1.0)) |> should.be_error() - floatx.logb(10.0, 1.0) + floatx.logarithm(10.0, option.Some(1.0)) |> should.be_error() - floatx.logb(-1.0, 1.0) + floatx.logarithm(-1.0, option.Some(1.0)) + |> should.be_error() + + floatx.logarithm(1.0, option.Some(10.0)) + |> should.equal(Ok(0.0)) + + floatx.logarithm(floatx.e(), option.Some(floatx.e())) + |> should.equal(Ok(1.0)) + + floatx.logarithm(-1.0, option.Some(2.0)) |> should.be_error() } -pub fn float_pow_test() { - floatx.pow(2.0, 2.0) +pub fn float_power_test() { + floatx.power(2.0, 2.0) |> should.equal(Ok(4.0)) - floatx.pow(-5.0, 3.0) + floatx.power(-5.0, 3.0) |> should.equal(Ok(-125.0)) - floatx.pow(10.5, 0.0) + floatx.power(10.5, 0.0) |> should.equal(Ok(1.0)) - floatx.pow(16.0, 0.5) + floatx.power(16.0, 0.5) |> should.equal(Ok(4.0)) - floatx.pow(2.0, -1.0) + floatx.power(2.0, -1.0) |> should.equal(Ok(0.5)) - floatx.pow(2.0, -1.0) + floatx.power(2.0, -1.0) |> should.equal(Ok(0.5)) - // floatx.pow(-1.0, 0.5) is equivalent to float.square_root(-1.0) + // floatx.power(-1.0, 0.5) is equivalent to float.square_root(-1.0) // and should return an error as an imaginary number would otherwise // have to be returned - floatx.pow(-1.0, 0.5) + floatx.power(-1.0, 0.5) |> should.be_error() // Check another case with a negative base and fractional exponent - floatx.pow(-1.5, 1.5) + floatx.power(-1.5, 1.5) |> should.be_error() - // floatx.pow(0.0, -1.0) is equivalent to 1. /. 0 and is expected + // floatx.power(0.0, -1.0) is equivalent to 1. /. 0 and is expected // to be an error - floatx.pow(0.0, -1.0) + floatx.power(0.0, -1.0) |> should.be_error() // Check that a negative base and exponent is fine as long as the // exponent is not fractional - floatx.pow(-2.0, -1.0) + floatx.power(-2.0, -1.0) |> should.equal(Ok(-0.5)) } -pub fn float_sqrt_test() { - floatx.sqrt(1.0) +pub fn float_square_root_test() { + floatx.square_root(1.0) |> should.equal(Ok(1.0)) - floatx.sqrt(9.0) + floatx.square_root(9.0) |> should.equal(Ok(3.0)) // An error should be returned as an imaginary number would otherwise // have to be returned - floatx.sqrt(-1.0) + floatx.square_root(-1.0) |> should.be_error() } -pub fn float_cbrt_test() { - floatx.cbrt(1.0) +pub fn float_cube_root_test() { + floatx.cube_root(1.0) |> should.equal(Ok(1.0)) - floatx.cbrt(27.0) + floatx.cube_root(27.0) |> should.equal(Ok(3.0)) // An error should be returned as an imaginary number would otherwise // have to be returned - floatx.cbrt(-1.0) + floatx.cube_root(-1.0) |> should.be_error() } -pub fn float_hypot_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) +pub fn float_nth_root_test() { + floatx.nth_root(9.0, 2) + |> should.equal(Ok(3.0)) - floatx.hypot(0.0, 0.0) + floatx.nth_root(27.0, 3) + |> should.equal(Ok(3.0)) + + floatx.nth_root(1.0, 4) + |> should.equal(Ok(1.0)) + + floatx.nth_root(256.0, 4) + |> should.equal(Ok(4.0)) + + // An error should be returned as an imaginary number would otherwise + // have to be returned + floatx.nth_root(-1.0, 4) + |> should.be_error() +} + +pub fn float_hypotenuse_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) + + floatx.hypotenuse(0.0, 0.0) |> should.equal(0.0) - floatx.hypot(1.0, 0.0) + floatx.hypotenuse(1.0, 0.0) |> should.equal(1.0) - floatx.hypot(0.0, 1.0) + floatx.hypotenuse(0.0, 1.0) |> should.equal(1.0) - let result = floatx.hypot(11.0, 22.0) + let result = floatx.hypotenuse(11.0, 22.0) result - |> floatx.isclose(24.596747, 0.0, tol) + |> floatx.is_close(24.596747, 0.0, tol) |> should.be_true() } pub fn float_sin_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.sin(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.sin(0.5 *. floatx.pi()) - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() floatx.sin(0.5) - |> floatx.isclose(0.479425, 0.0, tol) + |> floatx.is_close(0.479425, 0.0, tol) |> should.be_true() } pub fn float_sinh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.sinh(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.sinh(0.5) - |> floatx.isclose(0.521095, 0.0, tol) + |> floatx.is_close(0.521095, 0.0, tol) |> should.be_true() // An (overflow) error might occur when given an input // value that will result in a too large output value @@ -429,66 +457,66 @@ pub fn float_sinh_test() { } pub fn math_tan_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.tan(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.tan(0.5) - |> floatx.isclose(0.546302, 0.0, tol) + |> floatx.is_close(0.546302, 0.0, tol) |> should.be_true() } pub fn math_tanh_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) + assert Ok(tol) = floatx.power(-10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values floatx.tanh(0.0) - |> floatx.isclose(0.0, 0.0, tol) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() floatx.tanh(25.0) - |> floatx.isclose(1.0, 0.0, tol) + |> floatx.is_close(1.0, 0.0, tol) |> should.be_true() floatx.tanh(-25.0) - |> floatx.isclose(-1.0, 0.0, tol) + |> floatx.is_close(-1.0, 0.0, tol) |> should.be_true() floatx.tanh(0.5) - |> floatx.isclose(0.462117, 0.0, tol) + |> floatx.is_close(0.462117, 0.0, tol) |> should.be_true() } -pub fn float_rad2deg_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) - floatx.rad2deg(0.0) - |> floatx.isclose(0.0, 0.0, tol) +pub fn float_to_degree_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) + floatx.to_degree(0.0) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() - floatx.rad2deg(2.0 *. floatx.pi()) - |> floatx.isclose(360.0, 0.0, tol) + floatx.to_degree(2.0 *. floatx.pi()) + |> floatx.is_close(360.0, 0.0, tol) |> should.be_true() } -pub fn float_deg2rads_test() { - assert Ok(tol) = floatx.pow(-10.0, -6.0) - floatx.deg2rad(0.0) - |> floatx.isclose(0.0, 0.0, tol) +pub fn float_to_radian_test() { + assert Ok(tol) = floatx.power(-10.0, -6.0) + floatx.to_radian(0.0) + |> floatx.is_close(0.0, 0.0, tol) |> should.be_true() - floatx.deg2rad(360.0) - |> floatx.isclose(2.0 *. floatx.pi(), 0.0, tol) + floatx.to_radian(360.0) + |> floatx.is_close(2.0 *. floatx.pi(), 0.0, tol) |> should.be_true() } -pub fn float_ceil_test() { - floatx.ceil(0.1) +pub fn float_ceiling_test() { + floatx.ceiling(0.1) |> should.equal(1.0) - floatx.ceil(0.9) + floatx.ceiling(0.9) |> should.equal(1.0) } @@ -500,31 +528,31 @@ pub fn float_floor_test() { |> should.equal(0.0) } -pub fn float_min_test() { - floatx.min(0.75, 0.5) +pub fn float_minimum_test() { + floatx.minimum(0.75, 0.5) |> should.equal(0.5) - floatx.min(0.5, 0.75) + floatx.minimum(0.5, 0.75) |> should.equal(0.5) - floatx.min(-0.75, 0.5) + floatx.minimum(-0.75, 0.5) |> should.equal(-0.75) - floatx.min(-0.75, 0.5) + floatx.minimum(-0.75, 0.5) |> should.equal(-0.75) } -pub fn float_max_test() { - floatx.max(0.75, 0.5) +pub fn float_maximum_test() { + floatx.maximum(0.75, 0.5) |> should.equal(0.75) - floatx.max(0.5, 0.75) + floatx.maximum(0.5, 0.75) |> should.equal(0.75) - floatx.max(-0.75, 0.5) + floatx.maximum(-0.75, 0.5) |> should.equal(0.5) - floatx.max(-0.75, 0.5) + floatx.maximum(-0.75, 0.5) |> should.equal(0.5) } @@ -542,38 +570,38 @@ pub fn float_minmax_test() { |> should.equal(#(-0.75, 0.5)) } -pub fn float_sign_test() { - floatx.sign(100.0) - |> should.equal(1.0) +// pub fn float_sign_test() { +// floatx.sign(100.0) +// |> should.equal(1.0) - floatx.sign(0.0) - |> should.equal(0.0) +// floatx.sign(0.0) +// |> should.equal(0.0) - floatx.sign(-100.0) - |> should.equal(-1.0) +// floatx.sign(-100.0) +// |> should.equal(-1.0) +// } + +// pub fn float_flipsign_test() { +// floatx.flipsign(100.0) +// |> should.equal(-100.0) + +// floatx.flipsign(0.0) +// |> should.equal(-0.0) + +// floatx.flipsign(-100.0) +// |> should.equal(100.0) +// } + +pub fn float_beta_function_test() { + io.debug("TODO: Implement tests for 'float.beta'.") } -pub fn float_flipsign_test() { - floatx.flipsign(100.0) - |> should.equal(-100.0) - - floatx.flipsign(0.0) - |> should.equal(-0.0) - - floatx.flipsign(-100.0) - |> should.equal(100.0) +pub fn float_error_function_test() { + io.debug("TODO: Implement tests for 'float.erf'.") } -pub fn float_beta_test() { - io.debug("TODO: Implement tests for 'floatx.beta'.") -} - -pub fn float_erf_test() { - io.debug("TODO: Implement tests for 'floatx.erf'.") -} - -pub fn float_gamma_test() { - io.debug("TODO: Implement tests for 'floatx.gamma'.") +pub fn float_gamma_function_test() { + io.debug("TODO: Implement tests for 'float.gamma'.") } pub fn math_round_to_nearest_test() { @@ -620,6 +648,7 @@ pub fn math_round_up_test() { } pub fn math_round_down_test() { + // Try with positive values floatx.round(0.45, option.Some(0), option.Some("Down")) |> should.equal(Ok(0.0)) @@ -637,6 +666,25 @@ pub fn math_round_down_test() { floatx.round(0.5050, option.Some(2), option.Some("Down")) |> should.equal(Ok(0.50)) + + // Try with negative values + floatx.round(-0.45, option.Some(0), option.Some("Down")) + |> should.equal(Ok(-1.0)) + + floatx.round(-0.50, option.Some(0), option.Some("Down")) + |> should.equal(Ok(-1.0)) + + floatx.round(-0.45, option.Some(1), option.Some("Down")) + |> should.equal(Ok(-0.5)) + + floatx.round(-0.50, option.Some(1), option.Some("Down")) + |> should.equal(Ok(-0.50)) + + floatx.round(-0.4550, option.Some(2), option.Some("Down")) + |> should.equal(Ok(-0.46)) + + floatx.round(-0.5050, option.Some(2), option.Some("Down")) + |> should.equal(Ok(-0.51)) } pub fn math_round_to_zero_test() { @@ -705,60 +753,71 @@ pub fn math_round_ties_up_test() { |> should.equal(Ok(3.0)) } -pub fn float_gammainc_test() { +pub fn float_incomplete_gamma_function_test() { // Invalid input gives an error // 1st arg is invalid - floatx.gammainc(-1.0, 1.0) + floatx.incomplete_gamma(-1.0, 1.0) |> should.be_error() // 2nd arg is invalid - floatx.gammainc(1.0, -1.0) + floatx.incomplete_gamma(1.0, -1.0) |> should.be_error() // Valid input returns a result - floatx.gammainc(1.0, 0.0) + floatx.incomplete_gamma(1.0, 0.0) |> result.unwrap(-999.0) - |> floatx.isclose(0.0, 0.0, 0.01) + |> floatx.is_close(0.0, 0.0, 0.01) |> should.be_true() - floatx.gammainc(1.0, 2.0) + floatx.incomplete_gamma(1.0, 2.0) |> result.unwrap(-999.0) - |> floatx.isclose(0.864664716763387308106, 0.0, 0.01) + |> floatx.is_close(0.864664716763387308106, 0.0, 0.01) |> should.be_true() - floatx.gammainc(2.0, 3.0) + floatx.incomplete_gamma(2.0, 3.0) |> result.unwrap(-999.0) - |> floatx.isclose(0.8008517265285442280826, 0.0, 0.01) + |> floatx.is_close(0.8008517265285442280826, 0.0, 0.01) |> should.be_true() - floatx.gammainc(3.0, 4.0) + floatx.incomplete_gamma(3.0, 4.0) |> result.unwrap(-999.0) - |> floatx.isclose(1.523793388892911312363, 0.0, 0.01) + |> floatx.is_close(1.523793388892911312363, 0.0, 0.01) |> should.be_true() } -pub fn float_absdiff_test() { - floatx.absdiff(0.0, 0.0) +pub fn float_absolute_difference_test() { + floatx.absolute_difference(0.0, 0.0) |> should.equal(0.0) - floatx.absdiff(1.0, 2.0) + floatx.absolute_difference(1.0, 2.0) |> should.equal(1.0) - floatx.absdiff(2.0, 1.0) + floatx.absolute_difference(2.0, 1.0) |> should.equal(1.0) - floatx.absdiff(-1.0, 0.0) + floatx.absolute_difference(-1.0, 0.0) |> should.equal(1.0) - floatx.absdiff(0.0, -1.0) + floatx.absolute_difference(0.0, -1.0) |> should.equal(1.0) - floatx.absdiff(10.0, 20.0) + floatx.absolute_difference(10.0, 20.0) |> should.equal(10.0) - floatx.absdiff(-10.0, -20.0) + floatx.absolute_difference(-10.0, -20.0) |> should.equal(10.0) - floatx.absdiff(-10.5, 10.5) + floatx.absolute_difference(-10.5, 10.5) |> should.equal(21.0) } + +pub fn float_constants_test() { + floatx.e() + |> io.debug() + |> floatx.is_close(2.71828, 0.0, 0.00001) + |> should.be_true() + + floatx.pi() + |> floatx.is_close(3.14159, 0.0, 0.00001) + |> should.be_true() +}