// 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
}