aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam')
-rw-r--r--aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam546
1 files changed, 546 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam
new file mode 100644
index 0000000..5d62419
--- /dev/null
+++ b/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam
@@ -0,0 +1,546 @@
+//// Functions for working with floats.
+////
+//// ## Division by zero
+////
+//// Gleam runs on the Erlang virtual machine, which does not follow the IEEE
+//// 754 standard for floating point arithmetic and does not have an `Infinity`
+//// value. In Erlang division by zero results in a crash, however Gleam does
+//// not have partial functions and operators in core so instead division by zero
+//// returns zero, a behaviour taken from Pony, Coq, and Lean.
+////
+//// This may seem unexpected at first, but it is no less mathematically valid
+//// than crashing or returning a special value. Division by zero is undefined
+//// in mathematics.
+
+import gleam/order.{type Order}
+
+/// Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was
+/// not possible.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > parse("2.3")
+/// Ok(2.3)
+/// ```
+///
+/// ```gleam
+/// > parse("ABC")
+/// Error(Nil)
+/// ```
+///
+pub fn parse(string: String) -> Result(Float, Nil) {
+ do_parse(string)
+}
+
+@external(erlang, "gleam_stdlib", "parse_float")
+@external(javascript, "../gleam_stdlib.mjs", "parse_float")
+fn do_parse(a: String) -> Result(Float, Nil)
+
+/// Returns the string representation of the provided `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > to_string(2.3)
+/// "2.3"
+/// ```
+///
+pub fn to_string(x: Float) -> String {
+ do_to_string(x)
+}
+
+@external(erlang, "gleam_stdlib", "float_to_string")
+@external(javascript, "../gleam_stdlib.mjs", "float_to_string")
+fn do_to_string(a: Float) -> String
+
+/// Restricts a `Float` between a lower and upper bound.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > clamp(1.2, min: 1.4, max: 1.6)
+/// 1.4
+/// ```
+///
+pub fn clamp(x: Float, min min_bound: Float, max max_bound: Float) -> Float {
+ x
+ |> min(max_bound)
+ |> max(min_bound)
+}
+
+/// Compares two `Float`s, returning an `Order`:
+/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > compare(2.0, 2.3)
+/// Lt
+/// ```
+///
+/// To handle
+/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)
+/// you may use [`loosely_compare`](#loosely_compare) instead.
+///
+pub fn compare(a: Float, with b: Float) -> Order {
+ case a == b {
+ True -> order.Eq
+ False ->
+ case a <. b {
+ True -> order.Lt
+ False -> order.Gt
+ }
+ }
+}
+
+/// Compares two `Float`s within a tolerance, returning an `Order`:
+/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
+///
+/// This function allows Float comparison while handling
+/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
+///
+/// Notice: For `Float`s the tolerance won't be exact:
+/// `5.3 - 5.0` is not exactly `0.3`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > loosely_compare(5.0, with: 5.3, tolerating: 0.5)
+/// Eq
+/// ```
+///
+/// If you want to check only for equality you may use
+/// [`loosely_equals`](#loosely_equals) instead.
+///
+pub fn loosely_compare(
+ a: Float,
+ with b: Float,
+ tolerating tolerance: Float,
+) -> Order {
+ let difference = absolute_value(a -. b)
+ case difference <=. tolerance {
+ True -> order.Eq
+ False -> compare(a, b)
+ }
+}
+
+/// Checks for equality of two `Float`s within a tolerance,
+/// returning an `Bool`.
+///
+/// This function allows Float comparison while handling
+/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
+///
+/// Notice: For `Float`s the tolerance won't be exact:
+/// `5.3 - 5.0` is not exactly `0.3`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > loosely_equals(5.0, with: 5.3, tolerating: 0.5)
+/// True
+/// ```
+///
+/// ```gleam
+/// > loosely_equals(5.0, with: 5.1, tolerating: 0.1)
+/// False
+/// ```
+///
+pub fn loosely_equals(
+ a: Float,
+ with b: Float,
+ tolerating tolerance: Float,
+) -> Bool {
+ let difference = absolute_value(a -. b)
+ difference <=. tolerance
+}
+
+/// Compares two `Float`s, returning the smaller of the two.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > min(2.0, 2.3)
+/// 2.0
+/// ```
+///
+pub fn min(a: Float, b: Float) -> Float {
+ case a <. b {
+ True -> a
+ False -> b
+ }
+}
+
+/// Compares two `Float`s, returning the larger of the two.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > max(2.0, 2.3)
+/// 2.3
+/// ```
+///
+pub fn max(a: Float, b: Float) -> Float {
+ case a >. b {
+ True -> a
+ False -> b
+ }
+}
+
+/// Rounds the value to the next highest whole number as a `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > ceiling(2.3)
+/// 3.0
+/// ```
+///
+pub fn ceiling(x: Float) -> Float {
+ do_ceiling(x)
+}
+
+@external(erlang, "math", "ceil")
+@external(javascript, "../gleam_stdlib.mjs", "ceiling")
+fn do_ceiling(a: Float) -> Float
+
+/// Rounds the value to the next lowest whole number as a `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > floor(2.3)
+/// 2.0
+/// ```
+///
+pub fn floor(x: Float) -> Float {
+ do_floor(x)
+}
+
+@external(erlang, "math", "floor")
+@external(javascript, "../gleam_stdlib.mjs", "floor")
+fn do_floor(a: Float) -> Float
+
+/// Rounds the value to the nearest whole number as an `Int`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > round(2.3)
+/// 2
+/// ```
+///
+/// ```gleam
+/// > round(2.5)
+/// 3
+/// ```
+///
+pub fn round(x: Float) -> Int {
+ do_round(x)
+}
+
+@target(erlang)
+@external(erlang, "erlang", "round")
+fn do_round(a: Float) -> Int
+
+@target(javascript)
+fn do_round(x: Float) -> Int {
+ case x >=. 0.0 {
+ True -> js_round(x)
+ _ -> 0 - js_round(negate(x))
+ }
+}
+
+@target(javascript)
+@external(javascript, "../gleam_stdlib.mjs", "round")
+fn js_round(a: Float) -> Int
+
+/// Returns the value as an `Int`, truncating all decimal digits.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > truncate(2.4343434847383438)
+/// 2
+/// ```
+///
+pub fn truncate(x: Float) -> Int {
+ do_truncate(x)
+}
+
+@external(erlang, "erlang", "trunc")
+@external(javascript, "../gleam_stdlib.mjs", "truncate")
+fn do_truncate(a: Float) -> Int
+
+/// Returns the absolute value of the input as a `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > absolute_value(-12.5)
+/// 12.5
+/// ```
+///
+/// ```gleam
+/// > absolute_value(10.2)
+/// 10.2
+/// ```
+///
+pub fn absolute_value(x: Float) -> Float {
+ case x >=. 0.0 {
+ True -> x
+ _ -> 0.0 -. x
+ }
+}
+
+/// Returns the results of the base being raised to the power of the
+/// exponent, as a `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > power(2.0, -1.0)
+/// Ok(0.5)
+/// ```
+///
+/// ```gleam
+/// > power(2.0, 2.0)
+/// Ok(4.0)
+/// ```
+///
+/// ```gleam
+/// > power(8.0, 1.5)
+/// Ok(22.627416997969522)
+/// ```
+///
+/// ```gleam
+/// > 4.0 |> power(of: 2.0)
+/// Ok(16.0)
+/// ```
+///
+/// ```gleam
+/// > power(-1.0, 0.5)
+/// Error(Nil)
+/// ```
+///
+pub fn power(base: Float, of exponent: Float) -> Result(Float, Nil) {
+ let fractional: Bool = ceiling(exponent) -. exponent >. 0.0
+ // In the following check:
+ // 1. If the base is negative and the exponent is fractional then
+ // return an error as it will otherwise be an imaginary number
+ // 2. If the base is 0 and the exponent is negative then the expression
+ // is equivalent to the exponent divided by 0 and an error should be
+ // returned
+ case base <. 0.0 && fractional || base == 0.0 && exponent <. 0.0 {
+ True -> Error(Nil)
+ False -> Ok(do_power(base, exponent))
+ }
+}
+
+@external(erlang, "math", "pow")
+@external(javascript, "../gleam_stdlib.mjs", "power")
+fn do_power(a: Float, b: Float) -> Float
+
+/// Returns the square root of the input as a `Float`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > square_root(4.0)
+/// Ok(2.0)
+/// ```
+///
+/// ```gleam
+/// > square_root(-16.0)
+/// Error(Nil)
+/// ```
+///
+pub fn square_root(x: Float) -> Result(Float, Nil) {
+ power(x, 0.5)
+}
+
+/// Returns the negative of the value provided.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > negate(1.0)
+/// -1.0
+/// ```
+///
+pub fn negate(x: Float) -> Float {
+ -1.0 *. x
+}
+
+/// Sums a list of `Float`s.
+///
+/// ## Example
+///
+/// ```gleam
+/// > sum([1.0, 2.2, 3.3])
+/// 6.5
+/// ```
+///
+pub fn sum(numbers: List(Float)) -> Float {
+ numbers
+ |> do_sum(0.0)
+}
+
+fn do_sum(numbers: List(Float), initial: Float) -> Float {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_sum(rest, x +. initial)
+ }
+}
+
+/// Multiplies a list of `Float`s and returns the product.
+///
+/// ## Example
+///
+/// ```gleam
+/// > product([2.5, 3.2, 4.2])
+/// 33.6
+/// ```
+///
+pub fn product(numbers: List(Float)) -> Float {
+ case numbers {
+ [] -> 1.0
+ _ -> do_product(numbers, 1.0)
+ }
+}
+
+fn do_product(numbers: List(Float), initial: Float) -> Float {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_product(rest, x *. initial)
+ }
+}
+
+/// Generates a random float between the given minimum and maximum values.
+///
+///
+/// ## Examples
+///
+/// ```gleam
+/// > random(1.0, 5.0)
+/// 2.646355926896028
+/// ```
+///
+pub fn random(min: Float, max: Float) -> Float {
+ do_random_uniform() *. { max -. min } +. min
+}
+
+/// Returns a random float uniformly distributed in the value range
+/// 0.0 =< X < 1.0 and updates the state in the process dictionary.
+/// See: <https://www.erlang.org/doc/man/rand.html#uniform-0>
+///
+@external(erlang, "rand", "uniform")
+@external(javascript, "../gleam_stdlib.mjs", "random_uniform")
+fn do_random_uniform() -> Float
+
+/// Returns division of the inputs as a `Result`.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > divide(0.0, 1.0)
+/// Ok(1.0)
+/// ```
+///
+/// ```gleam
+/// > divide(1.0, 0.0)
+/// Error(Nil)
+/// ```
+///
+pub fn divide(a: Float, by b: Float) -> Result(Float, Nil) {
+ case b {
+ 0.0 -> Error(Nil)
+ b -> Ok(a /. b)
+ }
+}
+
+/// Adds two floats together.
+///
+/// It's the function equivalent of the `+.` operator.
+/// This function is useful in higher order functions or pipes.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > add(1.0, 2.0)
+/// 3.0
+/// ```
+///
+/// ```gleam
+/// > import gleam/list
+/// > list.fold([1.0, 2.0, 3.0], 0.0, add)
+/// 6.0
+/// ```
+///
+/// ```gleam
+/// > 3.0 |> add(2.0)
+/// 5.0
+/// ```
+///
+pub fn add(a: Float, b: Float) -> Float {
+ a +. b
+}
+
+/// Multiplies two floats together.
+///
+/// It's the function equivalent of the `*.` operator.
+/// This function is useful in higher order functions or pipes.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > multiply(2.0, 4.0)
+/// 8.0
+/// ```
+///
+/// ```gleam
+/// import gleam/list
+/// > list.fold([2.0, 3.0, 4.0], 1.0, multiply)
+/// 24.0
+/// ```
+///
+/// ```gleam
+/// > 3.0 |> multiply(2.0)
+/// 6.0
+/// ```
+///
+pub fn multiply(a: Float, b: Float) -> Float {
+ a *. b
+}
+
+/// Subtracts one float from another.
+///
+/// It's the function equivalent of the `-.` operator.
+/// This function is useful in higher order functions or pipes.
+///
+/// ## Examples
+///
+/// ```gleam
+/// > subtract(3.0, 1.0)
+/// 2.0
+/// ```
+///
+/// ```gleam
+/// > import gleam/list
+/// > list.fold([1.0, 2.0, 3.0], 10.0, subtract)
+/// 4.0
+/// ```
+///
+/// ```gleam
+/// > 3.0 |> subtract(_, 2.0)
+/// 1.0
+/// ```
+///
+/// ```gleam
+/// > 3.0 |> subtract(2.0, _)
+/// -1.0
+/// ```
+///
+pub fn subtract(a: Float, b: Float) -> Float {
+ a -. b
+}