code wiki / _hdl_build / _f64_erf_gate_authored.nx
_f64_erf_gate_authored.nx source
↩ module page · 132 lines · 5762 B
1// _f64_erf_gate_authored.nx -- f64 EDGE gate for the Builder-authored erf (component 5).
2// Complements the bf oracle gate (semantics) with IEEE edge discipline:
3// E1 denormal in -> finite, sign-preserved, non-NaN (series path: x*p well-defined)
4// E2 monotone non-decreasing over 0.5..1.75 step 1/256 (no Horner wiggle at the top)
5// E3 gap contract: first bits ABOVE the 1.75 cut -> NAN_RAW (loud, never wrong-number)
6// E4 result strictly < 1.0 inside the series domain (erf(1.75)=0.98667...)
7// E5 SEMANTIC ANCHORS (the tamper judge's teeth -- RUNGRUN re-runs THIS gate after
8// flipping a kernel literal, so edge checks alone are blind to coefficient/scale
9// flips that preserve monotonicity): 8-point bf-oracle ULP<=4 at x=k/8, k=1..8,
10// with 2/sqrt(pi) re-derived INDEPENDENTLY (judge diversity, not shared spec).
11// Durable: F64ERF row -> knowledge/status/math_engine.log. Exit 0 iff all held.
12// license_tier: ORIGINAL
13import "nx_syscalls.nx"
14import "nx_bigfloat120.nx"
15import "nx_bigfloat120_div.nx"
16import "nx_bigfloat120_trig.nx"
17import "_pe_f64erf.nx"
18func fg_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
19func fg_f(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
20func fg_n(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
21func fg_sqrt(out: *i64, a: *i64, seed_raw: i64) -> i64 {
22 let s: *i64 = bf_new()
23 bf_set_f64(s, seed_raw)
24 let q: *i64 = bf_new()
25 let sum: *i64 = bf_new()
26 var i: i64 = 0
27 while i < 8 {
28 bf_div(q, a, s)
29 bf_add(sum, s, q)
30 bf_div_small(s, sum, 2)
31 i = i + 1
32 }
33 return bf_copy(out, s)
34}
35func fg_oracle(xbits: i64, tosp: *i64) -> i64 {
36 let x: *i64 = bf_new()
37 bf_set_f64(x, xbits)
38 let x2: *i64 = bf_new()
39 bf_mul(x2, x, x)
40 let u: *i64 = bf_new()
41 bf_copy(u, x)
42 let pos: *i64 = bf_new()
43 bf_copy(pos, x)
44 let neg: *i64 = bf_new()
45 bf_set_int(neg, 0)
46 let t: *i64 = bf_new()
47 let term: *i64 = bf_new()
48 let acc: *i64 = bf_new()
49 var n: i64 = 1
50 while n <= 44 {
51 bf_mul(t, u, x2)
52 bf_div_small(u, t, n)
53 bf_div_small(term, u, 2 * n + 1)
54 if (n & 1) == 1 { bf_add(acc, neg, term); bf_copy(neg, acc) } else { bf_add(acc, pos, term); bf_copy(pos, acc) }
55 n = n + 1
56 }
57 let dif: *i64 = bf_new()
58 if bf_cmp(pos, neg) >= 0 { bf_sub(dif, pos, neg) } else { bf_sub(dif, neg, pos) }
59 let r: *i64 = bf_new()
60 bf_mul(r, dif, tosp)
61 return bf_to_f64(r, 0, 0)
62}
63func main() -> i64 {
64 fg_p("=== F64-ERF EDGE GATE: denormals, monotonicity, gap contract, semantic anchors ===\n" as *u8)
65 var bad: i64 = 0
66 // E1 denormals (positive + negative smallest and a mid-denormal)
67 let d1: i64 = nx_f64_erf(1)
68 if d1 == NX_F64_NAN_RAW { bad = bad + 1 }
69 if (d1 & (1 << 63)) != 0 { bad = bad + 1 }
70 let d2: i64 = nx_f64_erf((1 << 63) | 1)
71 if d2 == NX_F64_NAN_RAW { bad = bad + 1 }
72 if (d2 & (1 << 63)) == 0 { bad = bad + 1 }
73 let d3: i64 = nx_f64_erf(0x000FFFFFFFFFFFFF)
74 if d3 == NX_F64_NAN_RAW { bad = bad + 1 }
75 // E2 monotone non-decreasing 0.5 -> 1.75 step 1/256 (bits compare valid: positive)
76 // 0.5 = 128/256 ... 1.75 = 448/256: x_k bits via integer-ratio f64 build is heavy --
77 // step in BITS instead: from 0x3FE0000000000000 (0.5) to 0x3FFC000000000000 (1.75)
78 // sampling 320 evenly spaced bit-points (monotone in bits = monotone in value for
79 // positive finite doubles; consecutive kernel outputs must not DECREASE)
80 let lo: i64 = 0x3FE0000000000000
81 let hi: i64 = 0x3FFC000000000000
82 let step: i64 = (hi - lo) / 320
83 var prev: i64 = 0
84 var k: i64 = 0
85 while k <= 320 {
86 let xb: i64 = lo + k * step
87 let y: i64 = nx_f64_erf(xb)
88 if y == NX_F64_NAN_RAW { bad = bad + 1 }
89 if y < prev { bad = bad + 1 }
90 prev = y
91 k = k + 1
92 }
93 // E3 gap contract: just above the cut -> loud NaN (cut bits 0x3FFC000000000000)
94 if nx_f64_erf(0x3FFC000000000001) != NX_F64_NAN_RAW { bad = bad + 1 }
95 // E4 strictly below one inside the domain
96 let top: i64 = nx_f64_erf(0x3FFC000000000000)
97 if top >= 0x3FF0000000000000 { bad = bad + 1 }
98 // E5 semantic anchors: 8-point independent bf oracle, ULP <= 4
99 let pi: *i64 = bf_new()
100 bf_pi(pi)
101 let spi: *i64 = bf_new()
102 fg_sqrt(spi, pi, 0x3FFC5BF891B4EF6A)
103 let two: *i64 = bf_new()
104 bf_set_int(two, 2)
105 let tosp: *i64 = bf_new()
106 bf_div(tosp, two, spi)
107 let kb: *i64 = bf_new()
108 let xb: *i64 = bf_new()
109 var j: i64 = 1
110 while j <= 8 {
111 bf_set_int(kb, j)
112 bf_div_small(xb, kb, 8)
113 let axbits: i64 = bf_to_f64(xb, 0, 0)
114 let want: i64 = fg_oracle(axbits, tosp)
115 let got: i64 = nx_f64_erf(axbits)
116 var du: i64 = got - want
117 if du < 0 { du = 0 - du }
118 if du > 4 { bad = bad + 1 }
119 j = j + 1
120 }
121 let lfd: i64 = sys_openat_append("knowledge/status/math_engine.log" as *u8, 0x1a4)
122 if lfd >= 0 {
123 fg_f(lfd, "F64ERF-GATE epoch=" as *u8); fg_n(lfd, sys_now_realtime_sec())
124 fg_f(lfd, " bad=" as *u8); fg_n(lfd, bad)
125 if bad == 0 { fg_f(lfd, " verdict=GREEN\n" as *u8) } else { fg_f(lfd, " verdict=RED\n" as *u8) }
126 sys_close(lfd)
127 }
128 if bad == 0 { fg_p(" F64ERF-GATE: GREEN (edges + monotone + gap contract held)\n" as *u8); sys_exit(0); return 0 }
129 fg_p(" F64ERF-GATE: RED\n" as *u8)
130 sys_exit(1)
131 return 1
132}