code wiki / (root) / nx_exp_ab.nx

nx_exp_ab.nx source

↩ module page · 79 lines · 3405 B

1// nx_exp_ab.nx -- same-process A/B of the exp hot path: the OLD software 2// nx_f32_mul/add polynomial vs the NEW hardware __f32 one (now IN 3// nx_f32_exp). A = a local software-op copy of the poly; B = nx_f32_exp 4// (hardware). Same inputs, back-to-back -> noise-immune RATIO + a 5// bit-exactness check (must be 0 mismatches). license_tier: ORIGINAL 6// expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_tier.nx" 9import "nx_f32.nx" 10import "nx_f32_div.nx" 11import "nx_f32_cvt.nx" 12import "nx_f32_exp.nx" 13import "nx_fmt.nx" 14const K_MAGIC_2000000: i64 = 2000000 15const K_MAGIC_8192: i64 = 8192 16const K_MAGIC_4096: i64 = 4096 17 18func eab_nl() -> i64 { fmt_puts("\n" as *u8); return 0 } 19 20// software-op copy of the exp poly (the pre-2026-07-10 hot path), to time 21// against the shipped hardware nx_f32_exp. Same range-reduce + 6-term. 22func exp_soft(x: i64) -> i64 { 23 let cls: nx_int = nx_f32_classify(x) 24 if cls == NX_F32_CLS_NAN { return NX_F32_NAN_RAW } 25 if cls == NX_F32_CLS_ZERO { return NX_F32_ONE } 26 if cls == NX_F32_CLS_INF { if nx_f32_sign(x) == 1 { return 0 } return 0x7F800000 } 27 let sx: i64 = nx_f32_sign(x) 28 let ax: i64 = x & 0x7FFFFFFF 29 if sx == 0 { if ax > NX_F32_OVF_THRESH { return 0x7F800000 } } 30 else { if ax > (NX_F32_UNF_THRESH & 0x7FFFFFFF) { return 0 } } 31 let y: i64 = nx_f32_mul(x, NX_F32_INV_LN2) 32 let k: i64 = _f32_to_i32_rne(y) 33 let kf: i64 = nx_i32_to_f32(k) 34 let r: i64 = nx_f32_sub(x, nx_f32_mul(kf, NX_F32_LN2)) 35 let h6: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(r, NX_F32_INV_6)) 36 let h5: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(nx_f32_mul(r, NX_F32_INV_5), h6)) 37 let h4: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(nx_f32_mul(r, NX_F32_INV_4), h5)) 38 let h3: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(nx_f32_mul(r, NX_F32_INV_3), h4)) 39 let h2: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(nx_f32_mul(r, NX_F32_INV_2), h3)) 40 let er: i64 = nx_f32_add(NX_F32_ONE, nx_f32_mul(r, h2)) 41 return _f32_ldexp(er, k) 42} 43 44func main() -> i64 { 45 let N: i64 = K_MAGIC_2000000 46 // bit-exactness sweep over a representative range (-8..8 in /512 steps). 47 var mism: i64 = 0 48 var i: i64 = 0 49 while i < K_MAGIC_8192 { 50 let xv: i64 = nx_f32_div(nx_i32_to_f32(i - K_MAGIC_4096), nx_i32_to_f32(512)) 51 if exp_soft(xv) != nx_f32_exp(xv) { mism = mism + 1 } 52 i = i + 1 53 } 54 fmt_puts("BITEXACT soft==hw mismatches="); fmt_putn(mism); eab_nl() 55 if mism != 0 { fmt_puts("FATAL hw exp diverges"); eab_nl(); return 77 } 56 57 let xv: i64 = nx_f32_div(nx_i32_to_f32(0 - 3), nx_i32_to_f32(2)) // -1.5 58 // A: software 59 let ta: i64 = sys_now_us() 60 var acc: i64 = 0 61 var a: i64 = 0 62 while a < N { acc = acc ^ exp_soft(xv); a = a + 1 } 63 let usa: i64 = sys_now_us() - ta 64 // B: hardware 65 let tb: i64 = sys_now_us() 66 var acc2: i64 = 0 67 var b: i64 = 0 68 while b < N { acc2 = acc2 ^ nx_f32_exp(xv); b = b + 1 } 69 let usb: i64 = sys_now_us() - tb 70 71 fmt_puts("A(soft) us="); fmt_putn(usa); fmt_puts(" ns/exp="); fmt_putn(usa * 1000 / N); eab_nl() 72 fmt_puts("B(hw) us="); fmt_putn(usb); fmt_puts(" ns/exp="); fmt_putn(usb * 1000 / N); eab_nl() 73 var ub: i64 = usb 74 if ub < 1 { ub = 1 } 75 fmt_puts("soft_over_hw_x100="); fmt_putn(usa * 100 / ub); eab_nl() 76 if acc == acc2 { fmt_puts("(acc guard)"); eab_nl() } // keep both live 77 fmt_puts("EXP_AB DONE"); eab_nl() 78 return 0 79}