code wiki / _hdl_build / nx_nofloat_vs_float_gate.nx
nx_nofloat_vs_float_gate.nx
buildroot/runtime/_hdl_build/nx_nofloat_vs_float_gate.nx
about
nx_nofloat_vs_float_gate.nx -- CROSS-VALIDATION: do we need the float equivalent? Answer: it already EXISTS
(nx_autograd, the software-f32 scalar tape), and its right role is a VERIFICATION ORACLE + the exceed COMPETITOR
-- NOT a parallel product stack. This gate USES that role: it builds the SAME graph
loss = ( relu(w1*x + b1)*w2 + b2 )^2
in BOTH engines -- FLOAT via nx_autograd (ag_*, IEEE-754) and NO-FLOAT via nx_nofloat_autograd (nfa_*, integer
Q16) -- and asserts the four parameter gradients AGREE (in milli-units). Two INDEPENDENT autograd
implementations (different tapes, different number systems) computing the same gradients is far stronger
evidence than finite differences alone. It directly answers the question: the float engine validates the
no-float engine; we do not need to BUILD a float trainer (we have it) and do not need it in the PRODUCT
(no-float is the reproducibility exceed) -- we need it exactly here, as the oracle.
T1..T4: for each of {w1,b1,w2,b2}, |float_grad_milli - nofloat_grad_milli| < 60/1000.
The true grads (analytic): w1=3.094, b1=4.125, w2=2.063, b2=2.750 -> both engines land on them.
expect_exit: 0 license_tier: ORIGINAL imports: nx_autograd (->ag_*, ->nx_f32_*), nx_nofloat_autograd, nx_syscalls
dependencies 3 imports · 0 importers
imports: nx_autograd.nxnx_nofloat_autograd.nxnx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| none |
functions
| 19 | func v_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } |
| 20 | func v_pn(v: i64) -> i64 |
| 30 | func v_check(name: *u8, cond: i64) -> i64 { if cond==1 { v_puts(" PASS " as *u8) } else { v_puts(" FAIL " as *u8) } v_puts(name); v_puts("\n" as *u8); return cond } calls 1: v_puts |
| 31 | func v_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } called by 1: main |
| 34 | func f32_milli(v: i64) -> i64 |
| 47 | func q16_milli(q: i64) -> i64 { var neg: i64=0; var a: i64=q; if a<0 { neg=1; a=0-a } let m: i64=(a*1000)/65536; if neg==1 { return 0-m } return m } called by 1: main |
| 50 | func float_grads(gf: *i64) -> i64 |
| 69 | func nofloat_grads(gnf: *i64) -> i64 |
| 94 | func main() -> i64 |