code wiki / (root) / nx_bench_spectral.nx

nx_bench_spectral.nx source

↩ module page · 124 lines · 3815 B

1// nx_bench_spectral.nx -- NishiLang twin of bench/xlang/spectral.c (spectral-norm, 2// Computer Language Benchmarks Game). FIRST FLOAT (f64) racing-bench workload, 3// proving the 2026-07-16 f64 codegen on a real 3rd-party task. N=100, published 4// answer 1.274219991 -> line 1 = eigenvalue*1e9 truncated (1274219991), line 2 = 5// us. f64 values ride as i64 bit-patterns in i64 arrays; scalars are `f64`. 6// Structurally identical scalar operations to the C twin (Newton sqrt, same 7// reduction order) so nx/gcc/clang agree bit-for-bit at 9-digit truncation. 8// license_tier: ORIGINAL No hw writes (Rule 26). 9// (nx_syscalls_x86_64.nx import REMOVED 2026-07-31, debt 1785528831: this file already 10// gets the canonical syscall layer via nx_clock.nx -> syscalls.nx, so importing the raw-x86 11// module too put TWO syscall layers in one TU -- every wrapper twice, numbering picked by 12// definition ORDER, silently.) 13import "nx_clock.nx" 14 15const SN_N: i64 = 100 16 17func sp_emit_i64(fd: i64, n: i64) -> i64 { 18 let scratch: *u8 = sys_mmap(32) 19 var v: i64 = n 20 var neg: i64 = 0 21 if v < 0 { neg = 1; v = 0 - v } 22 var k: i64 = 0 23 if v == 0 { scratch[0] = 0x30 as u8; k = 1 } 24 while v > 0 { scratch[k] = (0x30 + (v - (v / 10) * 10)) as u8; v = v / 10; k = k + 1 } 25 let rev: *u8 = sys_mmap(48) 26 var ro: i64 = 0 27 if neg == 1 { rev[0] = 0x2D as u8; ro = 1 } 28 var j: i64 = 0 29 while j < k { rev[ro + j] = scratch[k - 1 - j]; j = j + 1 } 30 rev[ro + k] = 0x0A as u8 31 sys_write(fd, rev, ro + k + 1) 32 return 0 33} 34 35// A(i,j) = 1 / (((i+j)(i+j+1))/2 + i + 1). Denominator is integer; convert then divide. 36func sp_eval_A(i: i64, j: i64) -> f64 { 37 let d: i64 = (((i + j) * (i + j + 1)) >> 1) + i + 1 38 return 1.0 / __f64_from_i64(d) 39} 40 41// Au[i] = sum_j A(i,j) * u[j]. u/Au are *i64 carriers of f64 bits. 42func sp_A_times_u(u: *i64, Au: *i64) -> i64 { 43 var i: i64 = 0 44 while i < SN_N { 45 var s: f64 = 0.0 46 var j: i64 = 0 47 while j < SN_N { 48 let uj: f64 = u[j] as f64 49 s = s + sp_eval_A(i, j) * uj 50 j = j + 1 51 } 52 Au[i] = s as i64 53 i = i + 1 54 } 55 return 0 56} 57 58// Au[i] = sum_j A(j,i) * u[j] (transpose). 59func sp_At_times_u(u: *i64, Au: *i64) -> i64 { 60 var i: i64 = 0 61 while i < SN_N { 62 var s: f64 = 0.0 63 var j: i64 = 0 64 while j < SN_N { 65 let uj: f64 = u[j] as f64 66 s = s + sp_eval_A(j, i) * uj 67 j = j + 1 68 } 69 Au[i] = s as i64 70 i = i + 1 71 } 72 return 0 73} 74 75// AtAu = A^t (A u), via a scratch vector. 76func sp_AtA_times_u(u: *i64, AtAu: *i64, tmp: *i64) -> i64 { 77 sp_A_times_u(u, tmp) 78 sp_At_times_u(tmp, AtAu) 79 return 0 80} 81 82// Newton sqrt on f64 -- matches the C twin exactly (avoids libm rounding drift). 83func sp_sqrt(x: f64) -> f64 { 84 var g: f64 = x 85 var k: i64 = 0 86 while k < 60 { g = 0.5 * (g + x / g); k = k + 1 } 87 return g 88} 89 90func main() -> i64 { 91 let u: *i64 = sys_mmap(SN_N * 8) as *i64 92 let v: *i64 = sys_mmap(SN_N * 8) as *i64 93 let tmp: *i64 = sys_mmap(SN_N * 8) as *i64 94 let start: i64 = nx_clock_monotonic_ns() 95 96 let one: f64 = 1.0 97 var i: i64 = 0 98 while i < SN_N { u[i] = one as i64; i = i + 1 } 99 100 var it: i64 = 0 101 while it < 10 { 102 sp_AtA_times_u(u, v, tmp) 103 sp_AtA_times_u(v, u, tmp) 104 it = it + 1 105 } 106 107 var vBv: f64 = 0.0 108 var vv: f64 = 0.0 109 var q: i64 = 0 110 while q < SN_N { 111 let uq: f64 = u[q] as f64 112 let vq: f64 = v[q] as f64 113 vBv = vBv + uq * vq 114 vv = vv + vq * vq 115 q = q + 1 116 } 117 let eval: f64 = sp_sqrt(vBv / vv) 118 119 let end: i64 = nx_clock_monotonic_ns() 120 let us: i64 = (end - start) / 1000 121 sp_emit_i64(1, __f64_to_i64(eval * 1000000000.0)) 122 sp_emit_i64(1, us) 123 return 0 124}