553 lines
9.7 KiB
JavaScript
553 lines
9.7 KiB
JavaScript
import { Ok, Error, Empty as $Empty, divideFloat } from "../gleam.mjs";
|
|
import * as $order from "../gleam/order.mjs";
|
|
import {
|
|
parse_float as parse,
|
|
float_to_string as to_string,
|
|
ceiling,
|
|
floor,
|
|
round as js_round,
|
|
truncate,
|
|
identity as do_to_float,
|
|
power as do_power,
|
|
random_uniform as random,
|
|
log as do_log,
|
|
exp as exponential,
|
|
} from "../gleam_stdlib.mjs";
|
|
|
|
export { ceiling, exponential, floor, parse, random, to_string, truncate };
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
export function compare(a, b) {
|
|
let $ = a === b;
|
|
if ($) {
|
|
return new $order.Eq();
|
|
} else {
|
|
let $1 = a < b;
|
|
if ($1) {
|
|
return new $order.Lt();
|
|
} else {
|
|
return new $order.Gt();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compares two `Float`s, returning the smaller of the two.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* min(2.0, 2.3)
|
|
* // -> 2.0
|
|
* ```
|
|
*/
|
|
export function min(a, b) {
|
|
let $ = a < b;
|
|
if ($) {
|
|
return a;
|
|
} else {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compares two `Float`s, returning the larger of the two.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* max(2.0, 2.3)
|
|
* // -> 2.3
|
|
* ```
|
|
*/
|
|
export function max(a, b) {
|
|
let $ = a > b;
|
|
if ($) {
|
|
return a;
|
|
} else {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restricts a `Float` between a lower and upper bound.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* clamp(1.2, min: 1.4, max: 1.6)
|
|
* // -> 1.4
|
|
* ```
|
|
*/
|
|
export function clamp(x, min_bound, max_bound) {
|
|
let _pipe = x;
|
|
let _pipe$1 = min(_pipe, max_bound);
|
|
return max(_pipe$1, min_bound);
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* ```
|
|
*/
|
|
export function absolute_value(x) {
|
|
let $ = x >= 0.0;
|
|
if ($) {
|
|
return x;
|
|
} else {
|
|
return 0.0 - x;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
export function loosely_compare(a, b, tolerance) {
|
|
let difference = absolute_value(a - b);
|
|
let $ = difference <= tolerance;
|
|
if ($) {
|
|
return new $order.Eq();
|
|
} else {
|
|
return 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
|
|
* ```
|
|
*/
|
|
export function loosely_equals(a, b, tolerance) {
|
|
let difference = absolute_value(a - b);
|
|
return difference <= tolerance;
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
* ```
|
|
*/
|
|
export function power(base, exponent) {
|
|
let fractional = (ceiling(exponent) - exponent) > 0.0;
|
|
let $ = ((base < 0.0) && fractional) || ((base === 0.0) && (exponent < 0.0));
|
|
if ($) {
|
|
return new Error(undefined);
|
|
} else {
|
|
return new Ok(do_power(base, exponent));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
* ```
|
|
*/
|
|
export function square_root(x) {
|
|
return power(x, 0.5);
|
|
}
|
|
|
|
/**
|
|
* Returns the negative of the value provided.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* negate(1.0)
|
|
* // -> -1.0
|
|
* ```
|
|
*/
|
|
export function negate(x) {
|
|
return -1.0 * x;
|
|
}
|
|
|
|
/**
|
|
* Rounds the value to the nearest whole number as an `Int`.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* round(2.3)
|
|
* // -> 2
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* round(2.5)
|
|
* // -> 3
|
|
* ```
|
|
*/
|
|
export function round(x) {
|
|
let $ = x >= 0.0;
|
|
if ($) {
|
|
return js_round(x);
|
|
} else {
|
|
return 0 - js_round(negate(x));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts the value to a given precision as a `Float`.
|
|
* The precision is the number of allowed decimal places.
|
|
* Negative precisions are allowed and force rounding
|
|
* to the nearest tenth, hundredth, thousandth etc.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* to_precision(2.43434348473, precision: 2)
|
|
* // -> 2.43
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* to_precision(547890.453444, precision: -3)
|
|
* // -> 548000.0
|
|
* ```
|
|
*/
|
|
export function to_precision(x, precision) {
|
|
let $ = precision <= 0;
|
|
if ($) {
|
|
let factor = do_power(10.0, do_to_float(- precision));
|
|
return do_to_float(round(divideFloat(x, factor))) * factor;
|
|
} else {
|
|
let factor = do_power(10.0, do_to_float(precision));
|
|
return divideFloat(do_to_float(round(x * factor)), factor);
|
|
}
|
|
}
|
|
|
|
function sum_loop(loop$numbers, loop$initial) {
|
|
while (true) {
|
|
let numbers = loop$numbers;
|
|
let initial = loop$initial;
|
|
if (numbers instanceof $Empty) {
|
|
return initial;
|
|
} else {
|
|
let first = numbers.head;
|
|
let rest = numbers.tail;
|
|
loop$numbers = rest;
|
|
loop$initial = first + initial;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sums a list of `Float`s.
|
|
*
|
|
* ## Example
|
|
*
|
|
* ```gleam
|
|
* sum([1.0, 2.2, 3.3])
|
|
* // -> 6.5
|
|
* ```
|
|
*/
|
|
export function sum(numbers) {
|
|
return sum_loop(numbers, 0.0);
|
|
}
|
|
|
|
function product_loop(loop$numbers, loop$initial) {
|
|
while (true) {
|
|
let numbers = loop$numbers;
|
|
let initial = loop$initial;
|
|
if (numbers instanceof $Empty) {
|
|
return initial;
|
|
} else {
|
|
let first = numbers.head;
|
|
let rest = numbers.tail;
|
|
loop$numbers = rest;
|
|
loop$initial = first * initial;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multiplies a list of `Float`s and returns the product.
|
|
*
|
|
* ## Example
|
|
*
|
|
* ```gleam
|
|
* product([2.5, 3.2, 4.2])
|
|
* // -> 33.6
|
|
* ```
|
|
*/
|
|
export function product(numbers) {
|
|
return product_loop(numbers, 1.0);
|
|
}
|
|
|
|
/**
|
|
* Computes the modulo of an float division of inputs as a `Result`.
|
|
*
|
|
* Returns division of the inputs as a `Result`: If the given divisor equals
|
|
* `0`, this function returns an `Error`.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* modulo(13.3, by: 3.3)
|
|
* // -> Ok(0.1)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* modulo(-13.3, by: 3.3)
|
|
* // -> Ok(3.2)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* modulo(13.3, by: -3.3)
|
|
* // -> Ok(-3.2)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* modulo(-13.3, by: -3.3)
|
|
* // -> Ok(-0.1)
|
|
* ```
|
|
*/
|
|
export function modulo(dividend, divisor) {
|
|
if (divisor === 0.0) {
|
|
return new Error(undefined);
|
|
} else {
|
|
return new Ok(dividend - (floor(divideFloat(dividend, divisor)) * divisor));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns division of the inputs as a `Result`.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* divide(0.0, 1.0)
|
|
* // -> Ok(0.0)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* divide(1.0, 0.0)
|
|
* // -> Error(Nil)
|
|
* ```
|
|
*/
|
|
export function divide(a, b) {
|
|
if (b === 0.0) {
|
|
return new Error(undefined);
|
|
} else {
|
|
let b$1 = b;
|
|
return new Ok(divideFloat(a, b$1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* ```
|
|
*/
|
|
export function add(a, b) {
|
|
return 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
|
|
* ```
|
|
*/
|
|
export function multiply(a, b) {
|
|
return 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
|
|
* ```
|
|
*/
|
|
export function subtract(a, b) {
|
|
return a - b;
|
|
}
|
|
|
|
/**
|
|
* Returns the natural logarithm (base e) of the given as a `Result`. If the
|
|
* input is less than or equal to 0, returns `Error(Nil)`.
|
|
*
|
|
* ## Examples
|
|
*
|
|
* ```gleam
|
|
* logarithm(1.0)
|
|
* // -> Ok(0.0)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* logarithm(2.718281828459045) // e
|
|
* // -> Ok(1.0)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* logarithm(0.0)
|
|
* // -> Error(Nil)
|
|
* ```
|
|
*
|
|
* ```gleam
|
|
* logarithm(-1.0)
|
|
* // -> Error(Nil)
|
|
* ```
|
|
*/
|
|
export function logarithm(x) {
|
|
let $ = x <= 0.0;
|
|
if ($) {
|
|
return new Error(undefined);
|
|
} else {
|
|
return new Ok(do_log(x));
|
|
}
|
|
}
|