5678745381
Migrates the time, math/float, and in-process state surfaces from el-compiler/runtime/legacy/el_runtime.c to self-hosted El source: - runtime/time.el: time_now, sleep_secs/ms, time_to_parts (via pure-El Gregorian civil_from_days decomposition), time_format (ISO + strftime subset), time_add, time_diff, time_from_parts; full Instant/Duration nanosecond API (now, unix_seconds/millis, duration_seconds/millis, instant_to_iso8601, sleep_duration); TTL cache (ttl_cache_set/get/age backed by state); uuid_new / uuid_v4 via __uuid_v4 seed. - runtime/math.el: el_abs, el_max, el_min (Int); math_sqrt/log/ln/sin/cos/pi (Float seed wrappers); float_to_str, int_to_float, float_to_int, str_to_float, format_float (__format_float seed), decimal_round (half-away-from-zero via pure-El _pow10/_floor_f helpers). - runtime/state.el: state_set/get/del/keys thin wrappers over __state_* seeds; convenience helpers state_has and state_get_or.
171 lines
5.2 KiB
EmacsLisp
171 lines
5.2 KiB
EmacsLisp
// 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
|
||
}
|