sx primitives: add trig/transcendental/bit-op math helpers

Adds sin/cos/tan + inverse + hyperbolic + inverse-hyperbolic, log/log2/log10/log1p,
exp/expm1, cbrt, hypot (variadic), sign, fround/clz32/imul. All one-liners over
Float.* / Int32.*. Needed by JS-on-SX to unblock built-ins/Math tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 10:23:04 +00:00
parent 1473e277fd
commit cee9ae7f22

View File

@@ -144,6 +144,90 @@ let () =
register "pow" (fun args ->
match args with [a; b] -> Number (as_number a ** as_number b)
| _ -> raise (Eval_error "pow: 2 args"));
register "cbrt" (fun args ->
match args with [a] -> Number (Float.cbrt (as_number a)) | _ -> raise (Eval_error "cbrt: 1 arg"));
register "exp" (fun args ->
match args with [a] -> Number (Float.exp (as_number a)) | _ -> raise (Eval_error "exp: 1 arg"));
register "expm1" (fun args ->
match args with [a] -> Number (Float.expm1 (as_number a)) | _ -> raise (Eval_error "expm1: 1 arg"));
register "log" (fun args ->
match args with [a] -> Number (Float.log (as_number a)) | _ -> raise (Eval_error "log: 1 arg"));
register "log2" (fun args ->
match args with [a] -> Number (Float.log (as_number a) /. Float.log 2.0) | _ -> raise (Eval_error "log2: 1 arg"));
register "log10" (fun args ->
match args with [a] -> Number (Float.log10 (as_number a)) | _ -> raise (Eval_error "log10: 1 arg"));
register "log1p" (fun args ->
match args with [a] -> Number (Float.log1p (as_number a)) | _ -> raise (Eval_error "log1p: 1 arg"));
register "sin" (fun args ->
match args with [a] -> Number (Float.sin (as_number a)) | _ -> raise (Eval_error "sin: 1 arg"));
register "cos" (fun args ->
match args with [a] -> Number (Float.cos (as_number a)) | _ -> raise (Eval_error "cos: 1 arg"));
register "tan" (fun args ->
match args with [a] -> Number (Float.tan (as_number a)) | _ -> raise (Eval_error "tan: 1 arg"));
register "asin" (fun args ->
match args with [a] -> Number (Float.asin (as_number a)) | _ -> raise (Eval_error "asin: 1 arg"));
register "acos" (fun args ->
match args with [a] -> Number (Float.acos (as_number a)) | _ -> raise (Eval_error "acos: 1 arg"));
register "atan" (fun args ->
match args with [a] -> Number (Float.atan (as_number a)) | _ -> raise (Eval_error "atan: 1 arg"));
register "atan2" (fun args ->
match args with [a; b] -> Number (Float.atan2 (as_number a) (as_number b))
| _ -> raise (Eval_error "atan2: 2 args"));
register "sinh" (fun args ->
match args with [a] -> Number (Float.sinh (as_number a)) | _ -> raise (Eval_error "sinh: 1 arg"));
register "cosh" (fun args ->
match args with [a] -> Number (Float.cosh (as_number a)) | _ -> raise (Eval_error "cosh: 1 arg"));
register "tanh" (fun args ->
match args with [a] -> Number (Float.tanh (as_number a)) | _ -> raise (Eval_error "tanh: 1 arg"));
register "asinh" (fun args ->
match args with [a] -> Number (Float.asinh (as_number a)) | _ -> raise (Eval_error "asinh: 1 arg"));
register "acosh" (fun args ->
match args with [a] -> Number (Float.acosh (as_number a)) | _ -> raise (Eval_error "acosh: 1 arg"));
register "atanh" (fun args ->
match args with [a] -> Number (Float.atanh (as_number a)) | _ -> raise (Eval_error "atanh: 1 arg"));
register "hypot" (fun args ->
let square x = x *. x in
let sum = List.fold_left (fun acc a -> acc +. square (as_number a)) 0.0 args in
Number (Float.sqrt sum));
register "sign" (fun args ->
match args with
| [a] ->
let n = as_number a in
Number (if Float.is_nan n then Float.nan
else if n > 0.0 then 1.0
else if n < 0.0 then -1.0
else n)
| _ -> raise (Eval_error "sign: 1 arg"));
register "fround" (fun args ->
match args with [a] -> Number (Int32.float_of_bits (Int32.bits_of_float (as_number a)))
| _ -> raise (Eval_error "fround: 1 arg"));
register "clz32" (fun args ->
match args with
| [a] ->
let n = as_number a in
let i = if Float.is_nan n || Float.is_infinite n then 0l
else Int32.of_float (Float.rem n 4294967296.0) in
if i = 0l then Number 32.0
else
let high_bit = Int32.shift_left 1l 31 in
let count = ref 0 in
let x = ref i in
while Int32.logand !x high_bit = 0l do
incr count;
x := Int32.shift_left !x 1
done;
Number (float_of_int !count)
| _ -> raise (Eval_error "clz32: 1 arg"));
register "imul" (fun args ->
match args with
| [a; b] ->
let tou32 f =
if Float.is_nan f || Float.is_infinite f then 0l
else Int32.of_float (Float.rem f 4294967296.0) in
let ai = tou32 (as_number a) and bi = tou32 (as_number b) in
let r = Int32.mul ai bi in
Number (Int32.to_float r)
| _ -> raise (Eval_error "imul: 2 args"));
register "clamp" (fun args ->
match args with
| [x; lo; hi] ->