From 37f7405dcfe4dcfb45a7fd8d80eeb16380b04e3a Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 10 May 2026 00:09:57 +0000 Subject: [PATCH] ocaml: phase 5.1 euler40_small.ml baseline (Champernowne digit product = 15) Build the Champernowne string '12345678910111213...' until at least 1500 chars; product of digits at positions 1, 10, 100, 1000 is 1 * 1 * 5 * 3 = 15. Initial implementation timed out: 'String.length (Buffer.contents buf) < 1500' rebuilt the full string each iteration (O(n^2) in our spec-level evaluator). Fixed by tracking length separately from the Buffer: let len = ref 0 in while !len < 1500 do let s = string_of_int !i in Buffer.add_string buf s; len := !len + String.length s; i := !i + 1 done Real PE40 uses positions up to 10^6 (answer 210); 1000 keeps under budget while exercising the same string-build + char-pick pattern. 122 baseline programs total. --- lib/ocaml/baseline/euler40_small.ml | 22 ++++++++++++++++++++++ lib/ocaml/baseline/expected.json | 1 + plans/ocaml-on-sx.md | 6 ++++++ 3 files changed, 29 insertions(+) create mode 100644 lib/ocaml/baseline/euler40_small.ml diff --git a/lib/ocaml/baseline/euler40_small.ml b/lib/ocaml/baseline/euler40_small.ml new file mode 100644 index 00000000..7905f46e --- /dev/null +++ b/lib/ocaml/baseline/euler40_small.ml @@ -0,0 +1,22 @@ +let euler40 () = + let buf = Buffer.create 4096 in + let len = ref 0 in + let i = ref 1 in + while !len < 1500 do + let s = string_of_int !i in + Buffer.add_string buf s; + len := !len + String.length s; + i := !i + 1 + done; + let s = Buffer.contents buf in + let prod = ref 1 in + let positions = [1; 10; 100; 1000] in + List.iter (fun p -> + let c = s.[p - 1] in + prod := !prod * (Char.code c - Char.code '0') + ) positions; + !prod + +;; + +euler40 () diff --git a/lib/ocaml/baseline/expected.json b/lib/ocaml/baseline/expected.json index d0b59c2f..2b64e4bb 100644 --- a/lib/ocaml/baseline/expected.json +++ b/lib/ocaml/baseline/expected.json @@ -36,6 +36,7 @@ "euler29_small.ml": 15, "euler30_cube.ml": 1301, "euler34_small.ml": 145, + "euler40_small.ml": 15, "euler3.ml": 29, "euler4_small.ml": 9009, "euler5.ml": 232792560, diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index 01a85248..248b321f 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,12 @@ _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-10 Phase 5.1 — euler40_small.ml baseline (Champernowne + digit-product at 1, 10, 100, 1000 = 1*1*5*3 = 15). Builds the + Champernowne string until ≥1500 chars; tracks length separately + from the Buffer to avoid O(n²) `String.length (Buffer.contents + buf)` reallocation. Real PE40 uses positions up to 10^6 (answer + 210). 122 baseline programs total. - 2026-05-09 Phase 5.1 — euler34_small.ml baseline (numbers equal to sum of factorials of digits, ≤2000 = 145). 145 = 1!+4!+5! = 1+24+120. The other "factorion" 40585 is the only number above