bop-lang 0.3.0

A small, embeddable, dynamically-typed programming language with zero dependencies
Documentation
// std.math — numeric constants and helpers.
//
// The core builtins already expose `abs`, `sqrt`, `sin`, `cos`,
// `tan`, `floor`, `ceil`, `round`, `pow`, `log`, `exp`, `min`,
// `max` without any use — they live in core because they
// wrap `f64::*` operations that the stdlib can't implement
// itself. This module adds the canonical constants plus a few
// convenience wrappers built in Bop.

const PI = 3.141592653589793
const E = 2.718281828459045
const TAU = 6.283185307179586

// Clamp `x` into the range `[lo, hi]`. Accepts ints and floats
// in any combination; return type mirrors the widest input.
fn clamp(x, lo, hi) {
    if x < lo { return lo }
    if x > hi { return hi }
    return x
}

// Integer sign: -1, 0, or 1. Works on both `Int` and `Number`
// inputs via Bop's numeric comparison rules.
fn sign(x) {
    if x > 0 { return 1 }
    if x < 0 { return -1 }
    return 0
}

// `n!` using iterative multiplication. Raises an integer-
// overflow error for n ≥ 21 (the smallest factorial that
// doesn't fit in `i64`), matching core's overflow semantics.
fn factorial(n) {
    if n < 0 { return 0 }
    let result = 1
    let i = 2
    while i <= n {
        result = result * i
        i = i + 1
    }
    return result
}

// Greatest common divisor using the iterative Euclidean
// algorithm. Returns 0 for gcd(0, 0).
fn gcd(a, b) {
    if a < 0 { a = -a }
    if b < 0 { b = -b }
    while b != 0 {
        let t = a % b
        a = b
        b = t
    }
    return a
}

// Least common multiple. `lcm(0, x) == 0` so callers don't have
// to special-case.
fn lcm(a, b) {
    if a == 0 { return 0 }
    if b == 0 { return 0 }
    let g = gcd(a, b)
    // Integer division keeps the result exact when both inputs
    // are ints.
    return ((a / g).to_int()) * b
}

// Arithmetic mean. Raises on an empty array so callers notice.
// `std.math.sum` used to live here; it was a duplicate of
// `std.iter.sum`, so mean now inlines the reduction instead of
// depending on either.
fn mean(arr) {
    let n = arr.len()
    if n == 0 {
        return none[0]
    }
    let total = 0
    for x in arr { total = total + x }
    return total / n
}