nx_trig.nx
buildroot/runtime/nx_trig.nx
about
nx_trig.nx -- cos / sin primitives in Q10 fixed point.
Bits-up math primitive sibling of nx_isqrt.nx + nx_exp.nx + nx_root.nx.
Provides the canonical trigonometric kernel everything else
composes against -- RoPE position embeddings (Su 2021), sinusoidal
position encoding (Vaswani 2017), DSP filters, rotation matrices,
2D/3D graphics, signal-processing FFT (when shipped), etc.
===== Domain choice: turn-fraction not radians ===================
Storing angle in radians (Q10) forces 2pi-range-reduction on every
call, which is awkward in i64 because 2pi = 6283 Q10 doesn't divide
any power-of-2 cleanly. Storing as TURN FRACTION (1 turn = 1 full
circle = 2pi rad) makes range reduction a single mod-Q10 operation
and aligns directly with the 4-quadrant symmetry.
turn_q10 in [0, NX_TRIG_TURN) -- one Q10 unit per (2pi/1024) rad
NX_TRIG_TURN = 1024 = a full circle in Q10
Per-quadrant breakdown:
[0, NX_TRIG_TURN/4) : cos > 0, sin > 0
[TURN/4, TURN/2) : cos < 0, sin > 0
[TURN/2, 3TURN/4) : cos < 0, sin < 0
[3TURN/4, TURN) : cos > 0, sin < 0
Lookup table covers the first quadrant only (256 entries for
1/4 turn at NX_TRIG_TURN=1024). Other three quadrants derived
by symmetry without any table extension.
Conversion: radians-to-turns and back are exposed for callers
who prefer radians input.
===== Quality envelope (honest) ==================================
256-entry table + linear interpolation over a quarter turn gives
max relative error ~0.5% across (0, pi/2) -- below substrate
Q10-precision floor. Identities `sin^2 + cos^2 = Q10^2` hold to
within +/- 8 Q10 units. Sufficient for RoPE / position encoding /
rotation matrices; for FFT-class precision a Padé approximant
(Q14 or Q20) upgrade is queued.
dependencies 3 imports · 4 importers
imports: nx_syscalls.nxnx_tier.nxnx_loop.nx
imported by: nx_cad.nxnx_csg_scene.nxnx_robot_kinematics.nxnx_rope.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 60 | const NX_TRIG_Q10: nx_int = 1024 |
| 61 | const NX_TRIG_TURN: nx_int = 1024 // 1 turn = 1024 Q10 units |
| 62 | const NX_TRIG_QUARTER: nx_int = 256 // TURN / 4 |
| 63 | const NX_TRIG_HALF: nx_int = 512 // TURN / 2 |
| 64 | const NX_TRIG_3QUARTER: nx_int = 768 // 3*TURN / 4 |
| 186 | const NX_TRIG_TWO_PI_Q10: nx_int = 6283 |
functions
| 77 | func _nx_cos_q1_table(k: nx_int) -> nx_int called by 1: nx_cos_turn_q10 |
| 131 | func _nx_trig_reduce(turn_q10: nx_int, out_quad: *i64, out_k: *i64) -> nx_int called by 1: nx_cos_turn_q10 |
| 157 | func nx_cos_turn_q10(turn_q10: nx_int) -> nx_int |
| 174 | func nx_sin_turn_q10(turn_q10: nx_int) -> nx_int |
| 188 | func nx_rad_to_turn_q10(rad_q10: nx_int) -> nx_int |
| 192 | func nx_cos_rad_q10(rad_q10: nx_int) -> nx_int |
| 196 | func nx_sin_rad_q10(rad_q10: nx_int) -> nx_int |
| 212 | func main() -> i64 |