code wiki / (root) / sketch_geomean_test.nx

sketch_geomean_test.nx source

↩ module page · 93 lines · 3070 B

1// sketch_geomean_test.nx -- geometric mean via log-space accumulation tests. 2 3import "syscalls.nx" 4import "sketch_geomean.nx" 5import "sketch_types.nx" 6 7func iabs(x: i64) -> i64 { 8 if x < 0 { return -x } 9 return x 10} 11 12func main() -> i64 { 13 // ---- alloc + empty ---- 14 let g: *Geomean = nx_gm_alloc() 15 if g == (0 as *Geomean) { return __syscall(93, 5, 0, 0, 0, 0, 0) } 16 if nx_gm_value(g) != 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) } 17 18 // ---- single value: geomean = value (approximate) ---- 19 nx_gm_add(g, 100) 20 // floor(log_2(100)) = 6. 2^6 = 64 (under-estimate due to floor). 21 // We accept floor-log behavior; v2 can use mantissa interpolation. 22 let v_single: i64 = nx_gm_value(g) 23 if v_single < 50 { return __syscall(93, 10, 0, 0, 0, 0, 0) } 24 if v_single > 100 { return __syscall(93, 11, 0, 0, 0, 0, 0) } 25 26 // ---- powers of 2: floor-log is exact ---- 27 let g2: *Geomean = nx_gm_alloc() 28 nx_gm_add(g2, 8) // log_2(8) = 3 29 nx_gm_add(g2, 32) // log_2(32) = 5 30 // mean log = (3 + 5) / 2 = 4. 2^4 = 16. 31 if nx_gm_value(g2) != 16 { 32 return __syscall(93, 20, 0, 0, 0, 0, 0) 33 } 34 35 // ---- four powers-of-2: 2, 4, 8, 16 ---- 36 let g3: *Geomean = nx_gm_alloc() 37 nx_gm_add(g3, 2) // log=1 38 nx_gm_add(g3, 4) // log=2 39 nx_gm_add(g3, 8) // log=3 40 nx_gm_add(g3, 16) // log=4 41 // mean log = (1+2+3+4)/4 = 10/4 = 2.5. geomean = 2^2.5 ≈ 5.66. 42 // With linear approx: 2^2.5 = 2^2 * (1+0.5) = 4 * 1.5 = 6. 43 let v3: i64 = nx_gm_value(g3) 44 if iabs(v3 - 6) > 1 { 45 return __syscall(93, 30, 0, 0, 0, 0, 0) 46 } 47 48 // ---- non-positive values rejected ---- 49 if nx_gm_add(g, 0) != -1 { 50 return __syscall(93, 40, 0, 0, 0, 0, 0) 51 } 52 if nx_gm_add(g, -5) != -1 { 53 return __syscall(93, 41, 0, 0, 0, 0, 0) 54 } 55 if nx_gm_count_positive(g) != 1 { // unchanged from initial add 56 return __syscall(93, 42, 0, 0, 0, 0, 0) 57 } 58 59 // ---- log_mean_ppm query (log-domain access) ---- 60 let lm: i64 = nx_gm_log_mean_ppm(g3) 61 // (1+2+3+4)/4 = 2.5 -> 2_500_000 PPM. 62 if iabs(lm - 2500000) > 1 { 63 return __syscall(93, 50, 0, 0, 0, 0, 0) 64 } 65 66 // ---- typed envelope ---- 67 let q: *ApproxI64 = nx_gm_query(g3) 68 if q.envelope_kind != NX_ENV_REL_STDDEV { 69 return __syscall(93, 60, 0, 0, 0, 0, 0) 70 } 71 if q.maturity != NX_MATURITY_REFERENCE_IMPL { 72 return __syscall(93, 61, 0, 0, 0, 0, 0) 73 } 74 75 // ---- merge ---- 76 let g4a: *Geomean = nx_gm_alloc() 77 let g4b: *Geomean = nx_gm_alloc() 78 nx_gm_add(g4a, 2) 79 nx_gm_add(g4a, 4) 80 nx_gm_add(g4b, 8) 81 nx_gm_add(g4b, 16) 82 let merged: *Geomean = nx_gm_merge(g4a, g4b) 83 if nx_gm_count(merged) != 4 { 84 return __syscall(93, 70, 0, 0, 0, 0, 0) 85 } 86 // Same data as g3; same result. 87 let v_merged: i64 = nx_gm_value(merged) 88 if v_merged != v3 { 89 return __syscall(93, 71, 0, 0, 0, 0, 0) 90 } 91 92 return 0 93}