code wiki / _hdl_build / nx_pattern_emit6_erf.nx
nx_pattern_emit6_erf.nx source
↩ module page · 95 lines · 6460 B
1// nx_pattern_emit6_erf.nx -- PATTERN EMITTER: MATH_KERNEL / ERF_TAYLOR (DLMF ch7 rung 1,
2// ME2-ERF-001). The Builder authors f64 erf from the SOVEREIGN spec (nx_mathspec_erf:
3// bf_pi + Newton sqrt, rails held bit-exact vs known-good). The emitter contains
4// STRUCTURE only -- every number written into the module comes from the spec table c[].
5// kernel: specials (NaN/+-0 sign-preserved/+-Inf->+-1) -> integer-compare domain cuts
6// on |x| bits (positive f64 ordering): |x|>=c[37] (6.0) -> +-1 sub-ulp; |x|>c[36]
7// (1.75) -> NAN_RAW = the RUNG-1 HONEST GAP (erfc route = ME2-ERF-002, named debt;
8// a wrong number is worse than a loud gap) -> else 32-term signed Horner in z=x*x
9// (plain f64, the ch4 core gene) -> EXACT two-product x*p (_er_mul2 27-bit-split dd)
10// -> dd scale by 2/sqrt(pi) (full-bits product + lo-residual tail recombine).
11// Antisymmetry erf(-x) = -erf(x) is BIT-EXACT by construction (odd path only).
12// The emitted test checks ALGORITHM INVARIANTS (specials/cuts/antisymmetry) -- the
13// semantic ULP bar is the Engineer's separate bf-oracle gate (_bf_erf_gate, next).
14// license_tier: ORIGINAL
15import "nx_pattern_emit.nx"
16import "nx_syscalls.nx"
17
18func pe6e_wlit(fd: i64, v: i64) -> i64 {
19 if v < 0 {
20 pe_w(fd, "0 - " as *u8)
21 pe_wn(fd, 0 - v)
22 return 0
23 }
24 pe_wn(fd, v)
25 return 0
26}
27
28func pe6e_mod_head(mf: i64) -> i64 {
29 pe_w(mf, "// AUTHORED BY THE NISHI BUILDER (pattern: MATH_KERNEL / ERF_TAYLOR) -- no Claude core logic.\n" as *u8)
30 pe_w(mf, "// All constants from the SOVEREIGN bigfloat spec (nx_mathspec_erf; rails R1+R2 held).\n" as *u8)
31 pe_w(mf, "// Rung-1 domain: |x|<=1.75 series; |x|>=6 exact +-1; gap = LOUD NAN (ME2-ERF-002 erfc).\n" as *u8)
32 pe_w(mf, "import \"nx_syscalls.nx\"\nimport \"nx_tier.nx\"\nimport \"nx_f64.nx\"\nimport \"nx_f64_div.nx\"\nimport \"nx_f64_cvt.nx\"\n" as *u8)
33 pe_w(mf, "const ER_SMASK: i64 = 0xFFFFFFFFF8000000\n" as *u8)
34 pe_w(mf, "func _er_mul2(a: i64, b: i64, out: *i64) -> i64 {\n" as *u8)
35 pe_w(mf, " let ah: i64 = a & ER_SMASK\n let al: i64 = nx_f64_sub(a, ah)\n" as *u8)
36 pe_w(mf, " let bh: i64 = b & ER_SMASK\n let bl: i64 = nx_f64_sub(b, bh)\n" as *u8)
37 pe_w(mf, " let p: i64 = nx_f64_mul(a, b)\n" as *u8)
38 pe_w(mf, " var e: i64 = nx_f64_sub(nx_f64_mul(ah, bh), p)\n" as *u8)
39 pe_w(mf, " e = nx_f64_add(e, nx_f64_mul(ah, bl))\n" as *u8)
40 pe_w(mf, " e = nx_f64_add(e, nx_f64_mul(al, bh))\n" as *u8)
41 pe_w(mf, " e = nx_f64_add(e, nx_f64_mul(al, bl))\n" as *u8)
42 pe_w(mf, " out[0] = p\n out[1] = e\n return 0\n}\n" as *u8)
43 return 0
44}
45
46func pe6_author_erf(modfile: *u8, modpath: *u8, testpath: *u8, c: *i64) -> i64 {
47 let mf: i64 = sys_openat_wr(modpath, 0x1a4); if mf < 0 { return 0 }
48 pe6e_mod_head(mf)
49 pe_w(mf, "func nx_f64_erf(x: i64) -> i64 {\n" as *u8)
50 pe_w(mf, " let cls: nx_int = nx_f64_classify(x)\n" as *u8)
51 pe_w(mf, " if cls == NX_F64_CLS_NAN { return NX_F64_NAN_RAW }\n" as *u8)
52 pe_w(mf, " if cls == NX_F64_CLS_ZERO { return x }\n" as *u8)
53 pe_w(mf, " let sgn: i64 = x & (1 << 63)\n" as *u8)
54 pe_w(mf, " let ax: i64 = x & 0x7FFFFFFFFFFFFFFF\n" as *u8)
55 pe_w(mf, " if cls == NX_F64_CLS_INF { return sgn | " as *u8); pe6e_wlit(mf, c[0]); pe_w(mf, " }\n" as *u8)
56 pe_w(mf, " if ax >= " as *u8); pe6e_wlit(mf, c[37]); pe_w(mf, " { return sgn | " as *u8); pe6e_wlit(mf, c[0]); pe_w(mf, " }\n" as *u8)
57 pe_w(mf, " if ax > " as *u8); pe6e_wlit(mf, c[36]); pe_w(mf, " { return NX_F64_NAN_RAW }\n" as *u8)
58 pe_w(mf, " let z: i64 = nx_f64_mul(x, x)\n" as *u8)
59 pe_w(mf, " var p: i64 = " as *u8); pe6e_wlit(mf, c[4]); pe_w(mf, "\n" as *u8)
60 var i: i64 = 5
61 while i <= 35 {
62 pe_w(mf, " p = nx_f64_add(nx_f64_mul(p, z), " as *u8); pe6e_wlit(mf, c[i]); pe_w(mf, ")\n" as *u8)
63 i = i + 1
64 }
65 pe_w(mf, " let sv: *i64 = sys_mmap(16) as *i64\n" as *u8)
66 pe_w(mf, " _er_mul2(x, p, sv)\n" as *u8)
67 pe_w(mf, " let pv: *i64 = sys_mmap(16) as *i64\n" as *u8)
68 pe_w(mf, " _er_mul2(sv[0], " as *u8); pe6e_wlit(mf, c[1]); pe_w(mf, ", pv)\n" as *u8)
69 pe_w(mf, " let tail: i64 = nx_f64_add(pv[1], nx_f64_mul(sv[1], " as *u8); pe6e_wlit(mf, c[1]); pe_w(mf, "))\n" as *u8)
70 pe_w(mf, " return nx_f64_add(pv[0], tail)\n}\n" as *u8)
71 sys_close(mf)
72 // ---- the emitted INVARIANT test (specials/cuts/antisymmetry; ULP = separate gate) ----
73 let tf: i64 = sys_openat_wr(testpath, 0x1a4); if tf < 0 { return 0 }
74 pe_w(tf, "// GENERATED invariant KATs for the Builder-authored erf (ERF_TAYLOR).\n" as *u8)
75 pe_w(tf, "import \"" as *u8); pe_w(tf, modfile); pe_w(tf, "\"\n" as *u8)
76 pe_w(tf, "func main() -> i64 {\n var bad: i64 = 0\n" as *u8)
77 pe_w(tf, " if nx_f64_erf(0x7FF8000000000000) != NX_F64_NAN_RAW { bad = bad + 1 }\n" as *u8)
78 pe_w(tf, " if nx_f64_erf(0) != 0 { bad = bad + 1 }\n" as *u8)
79 pe_w(tf, " if nx_f64_erf(0x8000000000000000) != 0x8000000000000000 { bad = bad + 1 }\n" as *u8)
80 pe_w(tf, " if nx_f64_erf(0x7FF0000000000000) != " as *u8); pe6e_wlit(tf, c[0]); pe_w(tf, " { bad = bad + 1 }\n" as *u8)
81 pe_w(tf, " if nx_f64_erf(0xFFF0000000000000) != (" as *u8); pe6e_wlit(tf, c[0]); pe_w(tf, " | (1 << 63)) { bad = bad + 1 }\n" as *u8)
82 pe_w(tf, " if nx_f64_erf(0x4020000000000000) != " as *u8); pe6e_wlit(tf, c[0]); pe_w(tf, " { bad = bad + 1 }\n" as *u8)
83 pe_w(tf, " if nx_f64_erf(0x4000000000000000) != NX_F64_NAN_RAW { bad = bad + 1 }\n" as *u8)
84 pe_w(tf, " if nx_f64_erf(" as *u8); pe6e_wlit(tf, c[36]); pe_w(tf, ") == NX_F64_NAN_RAW { bad = bad + 1 }\n" as *u8)
85 pe_w(tf, " let h: i64 = nx_f64_erf(0x3FE0000000000000)\n" as *u8)
86 pe_w(tf, " if nx_f64_erf(0xBFE0000000000000) != (h | (1 << 63)) { bad = bad + 1 }\n" as *u8)
87 pe_w(tf, " let o: i64 = nx_f64_erf(0x3FF0000000000000)\n" as *u8)
88 pe_w(tf, " if nx_f64_erf(0xBFF0000000000000) != (o | (1 << 63)) { bad = bad + 1 }\n" as *u8)
89 pe_w(tf, " if (h & 0x7FFFFFFFFFFFFFFF) >= " as *u8); pe6e_wlit(tf, c[0]); pe_w(tf, " { bad = bad + 1 }\n" as *u8)
90 pe_w(tf, " if (o & 0x7FFFFFFFFFFFFFFF) >= " as *u8); pe6e_wlit(tf, c[0]); pe_w(tf, " { bad = bad + 1 }\n" as *u8)
91 pe_w(tf, " if (o & 0x7FFFFFFFFFFFFFFF) <= (h & 0x7FFFFFFFFFFFFFFF) { bad = bad + 1 }\n" as *u8)
92 pe_w(tf, " sys_exit(bad)\n return bad\n}\n" as *u8)
93 sys_close(tf)
94 return 1
95}