// runtime/math.el — Float math, integer utilities, and numeric conversions. // // Implements the math/float surface from el-compiler/runtime/legacy/el_runtime.c // (lines 303–305 for el_abs/max/min, lines 4725–4771 for float/format ops) // in pure El, using seed primitives. // // Seed primitives consumed: // __sqrt_f(f: Float) -> Float // __log_f(f: Float) -> Float // __ln_f(f: Float) -> Float // __sin_f(f: Float) -> Float // __cos_f(f: Float) -> Float // __pi_f() -> Float // __float_to_str(f: Float) -> String // __str_to_float(s: String) -> Float // __int_to_str(n: Int) -> String // __str_to_int(s: String) -> Int // --------------------------------------------------------------------------- // Integer math — el_abs, el_max, el_min. // // Matches legacy el_abs, el_max, el_min (lines 303–305). // --------------------------------------------------------------------------- // el_abs — absolute value of an integer. fn el_abs(n: Int) -> Int { if n < 0 { return -n } return n } // el_max — larger of two integers. fn el_max(a: Int, b: Int) -> Int { if a > b { return a } return b } // el_min — smaller of two integers. fn el_min(a: Int, b: Int) -> Int { if a < b { return a } return b } // --------------------------------------------------------------------------- // Float math — thin wrappers over seed primitives. // // Matches legacy math_sqrt, math_log, math_ln, math_sin, math_cos, math_pi // (lines 4766–4771). // --------------------------------------------------------------------------- // math_sqrt — square root. fn math_sqrt(f: Float) -> Float { return __sqrt_f(f) } // math_log — base-10 logarithm. fn math_log(f: Float) -> Float { return __log_f(f) } // math_ln — natural logarithm. fn math_ln(f: Float) -> Float { return __ln_f(f) } // math_sin — sine (radians). fn math_sin(f: Float) -> Float { return __sin_f(f) } // math_cos — cosine (radians). fn math_cos(f: Float) -> Float { return __cos_f(f) } // math_pi — the constant π. fn math_pi() -> Float { return __pi_f() } // --------------------------------------------------------------------------- // Float conversions — float_to_str, int_to_float, float_to_int, str_to_float. // // Matches legacy float_to_str, int_to_float, float_to_int, str_to_float // (lines 4725–4762). // --------------------------------------------------------------------------- // float_to_str — format a float using %g (shortest exact representation). // Matches legacy float_to_str() → snprintf "%g". fn float_to_str(f: Float) -> String { return __float_to_str(f) } // int_to_float — convert an integer to a float. // Matches legacy int_to_float() → (double)(int64_t)n. fn int_to_float(n: Int) -> Float { return __int_to_float(n) } // float_to_int — truncate a float to an integer (toward zero). // Matches legacy float_to_int() → (int64_t)el_to_float(f). fn float_to_int(f: Float) -> Int { return __float_to_int(f) } // str_to_float — parse a float from a string. Returns 0.0 on failure. // Matches legacy str_to_float() → strtod(str, NULL). fn str_to_float(s: String) -> Float { return __str_to_float(s) } // --------------------------------------------------------------------------- // format_float — format a float to a fixed number of decimal places. // // decimals is clamped to [0, 30]. Matches legacy format_float() → snprintf "%.*f". // --------------------------------------------------------------------------- fn format_float(f: Float, decimals: Int) -> String { let d: Int = decimals if d < 0 { d = 0 } if d > 30 { d = 30 } // Delegate to seed; the seed exposes __format_float(f, d) -> String. // This matches snprintf(buf, 128, "%.*f", d, v) in the legacy runtime. return __format_float(f, d) } // --------------------------------------------------------------------------- // decimal_round — round a float to d decimal places (half-away-from-zero). // // Matches legacy decimal_round(): // mul = pow(10, d) // r = (v >= 0 ? floor(v*mul + 0.5) : -floor(-v*mul + 0.5)) / mul // // We implement pow(10, d) via a loop (d <= 15, so at most 15 multiplications). // --------------------------------------------------------------------------- // _pow10 — 10^n as a Float for n in [0, 15]. fn _pow10(n: Int) -> Float { let result: Float = 1.0 let i: Int = 0 while i < n { result = result * 10.0 i = i + 1 } return result } // _floor_f — floor of a float: largest integer <= f. // Uses __float_to_int (truncation) with correction for negative non-integers. fn _floor_f(f: Float) -> Float { let t: Int = __float_to_int(f) let tf: Float = __int_to_float(t) // if f was negative and not already an integer, subtract 1 if f < 0.0 { if tf > f { return tf - 1.0 } } return tf } fn decimal_round(f: Float, decimals: Int) -> Float { let d: Int = decimals if d < 0 { d = 0 } if d > 15 { d = 15 } let mul: Float = _pow10(d) if f >= 0.0 { return _floor_f(f * mul + 0.5) / mul } return 0.0 - _floor_f((0.0 - f) * mul + 0.5) / mul }