diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index 8f40331b..548a2f92 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -609,6 +609,30 @@ let asprintf fmt = Printf.sprintf fmt end ;; + module Random = struct + (* Linear-congruential PRNG. Deterministic for testing — same + seed reproduces the same sequence. Real OCaml's Random uses + Lagged Fibonacci; ours is simpler but adequate for shuffles + and Monte Carlo demos in baseline programs. *) + let _state = ref 1 + + let init s = _state := s + + let self_init () = _state := 1 + + let int bound = + _state := (!_state * 1103515245 + 12345) mod 2147483647; + Int.abs (!_state) mod bound + + let bool () = int 2 = 1 + + let float bound = + let n = int 1000000 in + float_of_int n /. 1000000.0 *. bound + + let bits () = int 1073741824 + end ;; + module Lazy = struct let force lz = _lazy_force lz end ;; diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index c17c1f92..b8c5500d 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1360,6 +1360,16 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 5103) (eval "(ocaml-run \"let t = Hashtbl.create 4 in Hashtbl.add t \\\"a\\\" 1; Hashtbl.clear t; Hashtbl.length t\")") +;; ── Random module (deterministic LCG) ───────────────────────── +(epoch 5110) +(eval "(ocaml-run \"Random.init 42; Random.int 100\")") +(epoch 5111) +(eval "(ocaml-run \"Random.init 42; let a = Random.int 100 in let b = Random.int 100 in let c = Random.int 100 in a + b + c\")") +(epoch 5112) +(eval "(ocaml-run \"Random.init 1; Random.int 10\")") +(epoch 5113) +(eval "(ocaml-run \"Random.init 7; Random.bool ()\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -2161,6 +2171,12 @@ check 5101 "Hashtbl.values sum" '12' check 5102 "Hashtbl.remove + length" '1' check 5103 "Hashtbl.clear + length" '0' +# ── Random (deterministic LCG) ────────────────────────────────── +check 5110 "Random.int 100 seed=42" '48' +check 5111 "Random.int x3 seed=42 sum" '152' +check 5112 "Random.int 10 seed=1" '0' +check 5113 "Random.bool seed=7" 'true' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index e95cc8dd..7d8df6d3 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,13 @@ _Newest first._ binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree`) with insert + in-order traversal. Tests parametric ADT, recursive match, List.append, List.fold_left. +- 2026-05-09 Phase 6 — Random module (LCG-based, deterministic) (+4 + tests, 549 total). Linear-congruential PRNG with mutable seed + (`_state` ref). API: init, self_init, int, bool, float, bits. + `int bound` returns `|state| mod bound` after stepping. Same seed + reproduces same sequence — useful for testing shuffles and Monte + Carlo demos. Real OCaml's Random uses Lagged Fibonacci; ours is + simpler but adequate for baseline programs. - 2026-05-09 Phase 6 — Hashtbl.keys / values / bindings / remove / clear / reset / to_seq / to_seq_keys / to_seq_values (+4 tests, 545 total). Two new host primitives `_hashtbl_remove` and