Current section
Files
Jump to
Current section
Files
src/gcalc.gleam
//// A set of algebraic operations for Gleam programs
/// MathError represents an error that can occur when performing
/// a mathematical operation
pub type MathError {
DivisionByZero
ValueOutOfRange
UnsupportedOperation
}
// Exponentiation Functions ---------------------------------------------------
/// Returns the exponentiation of the two arguments
/// (i.e. the first argument raised to the power of the second argument)
///
/// Example:
/// ```
/// let base = 2.0
/// let power = 3.0
/// pow(base, power) // 8.0
/// ```
pub fn pow(base: Float, power: Float) -> Float {
pow_iter(base, power, 1.0)
}
/// Helper function for the pow function
fn pow_iter(base: Float, power: Float, accumulator: Float) -> Float {
case power {
0.0 -> accumulator
_ -> pow_iter(base, power -. 1.0, base *. accumulator)
}
}
// Factorial Functions --------------------------------------------------------
/// Returns a result containing the factorial of the argument
/// or an error if the argument is negative
///
/// Note: This function only supports non-negative values
pub fn factorial(n: Float) -> Result(Float, MathError) {
case n <. 0.0 {
True -> Error(UnsupportedOperation)
False -> Ok(factorial_iter(n, 1.0))
}
}
/// Helper function for the factorial function
fn factorial_iter(n: Float, accumulator: Float) -> Float {
case n {
0.0 -> accumulator
_ -> factorial_iter(n -. 1.0, n *. accumulator)
}
}
// Absolute Value Function ----------------------------------------------------
/// Returns the absolute value of the argument
pub fn abs(n: Float) -> Float {
case n <. 0.0 {
True -> 0.0 -. n
False -> n
}
}
// Square Root Functions ------------------------------------------------------
/// Returns a result containing the square root of the argument
/// or an error if the argument is negative
///
/// Note: This function only supports non-negative values
///
/// Example:
/// ```gleam
/// sqrt(4.0) // Ok(2.000000000000002)
/// |> result.unwrap(0.0) // 2.000000000000002
/// |> float.floor // 2.0
/// ```
pub fn sqrt(n: Float) -> Result(Float, MathError) {
case n <. 0.0 {
True -> Error(ValueOutOfRange)
False -> Ok(sqrt_iter(0.0, 1.0, n))
}
}
/// Helper function for the square root function
fn sqrt_iter(x0: Float, x1: Float, n: Float) -> Float {
case abs(x1 -. x0) <. 0.0001 {
True -> x1
False -> {
let x0 = x1
let x1 = { x0 +. n /. x0 } /. 2.0
sqrt_iter(x0, x1, n)
}
}
}
// Common Exponential Functions -----------------------------------------------
/// Returns a result containing 2^n where n is the argument
pub fn pow2(n: Float) -> Result(Float, MathError) {
case n <. 0.0 {
True -> Error(ValueOutOfRange)
False -> Ok(pow2_iter(n, 1.0))
}
}
/// Helper function for the pow2 function
fn pow2_iter(n: Float, accumulator: Float) -> Float {
case n {
0.0 -> accumulator
_ -> pow2_iter(n -. 1.0, 2.0 *. accumulator)
}
}
/// Returns a result containing 10^n where n is the argument
///
/// Example:
/// ```
/// let n = 2.0
/// pow10(n) // Ok(100.0)
/// ```
pub fn pow10(n: Float) -> Result(Float, MathError) {
case n <. 0.0 {
True -> Error(ValueOutOfRange)
False -> Ok(pow10_iter(n, 1.0))
}
}
/// Helper function for the pow10 function
fn pow10_iter(n: Float, accumulator: Float) -> Float {
case n {
0.0 -> accumulator
_ -> pow10_iter(n -. 1.0, 10.0 *. accumulator)
}
}
// Cube Root Functions --------------------------------------------------------
/// Returns a result containing the cube root of the argument
///
/// Note: This function only supports non-negative values
///
/// Example:
/// ```
/// let n = 27.0
/// cbrt(n) // 3.0
/// ```
pub fn cbrt(n: Float) -> Result(Float, MathError) {
case n <. 0.0 {
True -> Error(ValueOutOfRange)
False -> Ok(cbrt_iter(0.0, 1.0, n))
}
}
/// Helper function for the cube root function
fn cbrt_iter(x0: Float, x1: Float, n: Float) -> Float {
case abs(x1 -. x0) <. 0.0001 {
True -> x1
False -> {
let x0 = x1
let x1 = { x0 +. n /. { x0 *. x0 } } /. 2.0
cbrt_iter(x0, x1, n)
}
}
}
// GCD ------------------------------------------------------------------------
/// Returns the greatest common divisor of a and b using the Euclidean
/// Algorithm
pub fn gcd(a: Int, b: Int) -> Int {
case a == b {
True -> a
False ->
case a > b {
True -> gcd_iter(a, b)
False -> gcd_iter(b, a)
}
}
}
/// Helper function for the gcd function
fn gcd_iter(a: Int, b: Int) {
case b == 0 {
True -> a
False -> {
let temp = b
let b = a % b
let a = temp
gcd_iter(a, b)
}
}
}
// Multiply-add Function ------------------------------------------------------
/// Returns the result of x*y+z
/// without losing precision in any intermediate result
///
/// Example:
/// ```
/// let x = 10.0
/// let y = 20.0
/// let z = 30.0
/// fma(x,y,z) // 230.0
/// ```
pub fn fma(x: Float, y: Float, z: Float) -> Float {
x *. y +. z
}