nx_vecmath_slerp_candidate_t181.nx
buildroot/runtime/nx_vecmath_slerp_candidate_t181.nx
about
nx_vecmath.nx -- THE SHARED INTEGER LINEAR-ALGEBRA FOUNDATION (PG2, procgen.plan, 2026-08-24).
WHY THIS EXISTS, MEASURED NOT ASSERTED: before this file the estate's entire shared math foundation was
nx_itrig.nx at 1151 bytes -- it_sin4096 and it_cos4096 and nothing else. Every consumer above it re-rolled
its own primitives: nx_gsplat carries gs_isqrt AND a private exp-LUT, nx_bodybench carries a private acos
LUT. Three duplicate rulers for two operations. Worse, with no quaternion type nx_gsplat's gs_set_aniso had
to settle for a normal-plus-tangent SURFEL where full 3D gaussian covariance needs quaternion-plus-3-axis
scale -- a capability ceiling caused by a missing primitive, not by a design choice.
SCALE IS DERIVED, NOT PICKED: VM_ONE = 4096 because that is already the estate's unit. nx_itrig emits
fx4096 and measures angles in rad*4096; nx_vmd decodes quaternions at V_SCALE_ROT = 4096. Adopting any
other scale would have made this file a converter instead of a foundation. Every other constant here is
either derived from VM_ONE arithmetically or carries its derivation on its own line.
COMPOSES THE INCUMBENT: sine and cosine come from nx_itrig by import. This file does NOT re-derive Taylor
coefficients. VM_PI and VM_PI2 restate nx_itrig's angle constants because NishiLang const scope does not
cross the import, so nx_vecmath_gate carries a tooth that FAILS if the two ever disagree -- a guarded
duplicate, not a silent one.
NO HEAP, NO LOCAL ARRAYS, NO ALLOCATION ANYWHERE. Every routine works in scalar locals and writes through
caller-owned pointers. Two reasons, both estate law: this is hot-loop code and allocating in a hot loop is
a measured defect; and the estate's only allocation idiom is sys_mmap, which a pure math lib must not need.
Every routine that could alias its output with an input reads all operands into locals FIRST.
ALL INTEGER. The language has no float type, so every result here is bit-exact and reproducible by
construction. license_tier: ORIGINAL
dependencies 1 imports · 1 importers
imports: nx_itrig.nx
imported by: nx_vecmath_slerp_gate_t181.nx
structs
| none |
consts
| 31 | const VM_ONE: i64 = 4096 // fixed-point unit. DERIVED: nx_itrig fx4096 and nx_vmd V_SCALE_ROT. |
| 32 | const VM_PI: i64 = 12868 // round(PI * VM_ONE). Guarded by tooth pi-agrees-with-itrig. |
| 33 | const VM_PI2: i64 = 6434 // round(PI/2 * VM_ONE) |
| 34 | const VM_TAU: i64 = 25736 // 2 * VM_PI |
| 40 | const VM_ATAN_KN: i64 = 9 |
| 41 | const VM_ATAN_KD: i64 = 32 |
| 48 | const VM_SLERP_PARALLEL: i64 = 4095 // VM_ONE - 1 |
| 50 | const VM_V3: i64 = 3 |
| 51 | const VM_M3: i64 = 9 |
| 105 | const VM_CAP_Q: i64 = 256 |
| 162 | const VM_F32_MANT_MASK: i64 = 8388607 // 2^23 - 1 |
| 163 | const VM_F32_IMPLICIT: i64 = 8388608 // 2^23 |
| 164 | const VM_F32_EXP_BIAS: i64 = 127 |
| 165 | const VM_F32_MANT_BITS: i64 = 23 |
| 166 | const VM_F32_EXP_MASK: i64 = 255 |
| 167 | const VM_F32_SHIFT_MAX: i64 = 62 // a shift at or beyond this cannot be represented in i64 |
| 469 | const VM_Q30:i64=1073741824 |
| 470 | const VM_Q30_BITS:i64=30 |
functions
| 53 | func vm_one() -> i64 { return VM_ONE } |
| 54 | func vm_pi() -> i64 { return VM_PI } |
| 55 | func vm_pi2() -> i64 { return VM_PI2 } |
| 56 | func vm_tau() -> i64 { return VM_TAU } |
| 60 | func vm_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } |
| 61 | func vm_sgn(v: i64) -> i64 { if v > 0 { return 1 } if v < 0 { return 0 - 1 } return 0 } |
| 62 | func vm_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } |
| 63 | func vm_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } |
| 64 | func vm_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v < lo { return lo } if v > hi { return hi } return v } |
| 68 | func vm_isqrt(v: i64) -> i64 |
| 84 | func vm_sqrt_fx(v: i64) -> i64 |
| 106 | func vm_capsule_push(px: i64, py: i64, pz: i64, calls 1: vm_isqrt |
| 169 | func vm_f32_to_int(bits: i64, scale: i64) -> i64 |
| 187 | func vm_int_to_f32(v: i64, scale: i64) -> i64 |
| 203 | func vm_mul_fx(a: i64, b: i64) -> i64 { return a * b / VM_ONE } |
| 204 | func vm_div_fx(a: i64, b: i64) -> i64 { if b == 0 { return 0 } return a * VM_ONE / b } |
| 206 | func vm_sin(a: i64) -> i64 { return it_sin4096(a) } |
| 207 | func vm_cos(a: i64) -> i64 { return it_cos4096(a) } |
| 211 | func vm_tan(a: i64) -> i64 |
| 218 | func vm_atan_core(z: i64) -> i64 called by 1: vm_atan2 |
| 227 | func vm_atan2(y: i64, x: i64) -> i64 |
| 245 | func vm_acos(c0: i64) -> i64 |
| 253 | func vm_asin(s0: i64) -> i64 |
| 263 | func vm_v3_set(o: *i64, x: i64, y: i64, z: i64) -> i64 { o[0] = x; o[1] = y; o[2] = z; return 0 } |
| 264 | func vm_v3_copy(o: *i64, a: *i64) -> i64 { o[0] = a[0]; o[1] = a[1]; o[2] = a[2]; return 0 } |
| 265 | func vm_v3_add(o: *i64, a: *i64, b: *i64) -> i64 { o[0] = a[0]+b[0]; o[1] = a[1]+b[1]; o[2] = a[2]+b[2]; return 0 } |
| 266 | func vm_v3_sub(o: *i64, a: *i64, b: *i64) -> i64 { o[0] = a[0]-b[0]; o[1] = a[1]-b[1]; o[2] = a[2]-b[2]; return 0 } |
| 267 | func vm_v3_scale(o: *i64, a: *i64, s: i64) -> i64 { o[0] = a[0]*s/VM_ONE; o[1] = a[1]*s/VM_ONE; o[2] = a[2]*s/VM_ONE; return 0 } |
| 269 | func vm_v3_dot(a: *i64, b: *i64) -> i64 { return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]) / VM_ONE } |
| 272 | func vm_v3_cross(o: *i64, a: *i64, b: *i64) -> i64 |
| 281 | func vm_v3_len2(a: *i64) -> i64 { return (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]) / VM_ONE } called by 1: vm_v3_len |
| 282 | func vm_v3_len(a: *i64) -> i64 { return vm_sqrt_fx(vm_v3_len2(a)) } |
| 286 | func vm_v3_norm(o: *i64, a: *i64) -> i64 calls 1: vm_v3_len |
| 300 | func vm_q_ident(o: *i64) -> i64 { o[0] = 0; o[1] = 0; o[2] = 0; o[3] = VM_ONE; return 0 } |
| 301 | func vm_q_copy(o: *i64, a: *i64) -> i64 { o[0]=a[0]; o[1]=a[1]; o[2]=a[2]; o[3]=a[3]; return 0 } |
| 302 | func vm_q_conj(o: *i64, a: *i64) -> i64 |
| 306 | func vm_q_len(a: *i64) -> i64 |
| 310 | func vm_q_norm(o: *i64, a: *i64) -> i64 |
| 322 | func vm_q_mul(o: *i64, a: *i64, b: *i64) -> i64 |
| 333 | func vm_q_from_axis(o: *i64, axis: *i64, angle: i64) -> i64 |
| 349 | func vm_q_rotate_v3(o: *i64, q: *i64, v: *i64) -> i64 |
| 365 | func vm_q_slerp(o: *i64, a: *i64, b: *i64, t: i64) -> i64 |
| 389 | func vm_m3_ident(o: *i64) -> i64 called by 1: vm_q_to_m3 |
| 397 | func vm_m3_mul(o: *i64, a: *i64, b: *i64) -> i64 |
| 416 | func vm_m3_mulv(o: *i64, m: *i64, v: *i64) -> i64 |
| 424 | func vm_m3_transpose(o: *i64, m: *i64) -> i64 |
| 435 | func vm_q_to_m3(o: *i64, q: *i64) -> i64 |
| 459 | func vm_q_scale_to_m3(o: *i64, q: *i64, sx: i64, sy: i64, sz: i64) -> i64 calls 1: vm_q_to_m3 |
| 471 | func vm_q_norm_q30(a:*i64,out:*i64,tolerance:i64)->i64 |
| 478 | func vm_q_slerp_q30(a:*i64,b:*i64,t:i64,tolerance:i64,out:*i64,scratch:*i64)->i64 |