nx_isqrt.nx
buildroot/runtime/nx_isqrt.nx
about
nx_isqrt.nx -- integer square root, shared helper.
Per cardinal feedback-15 DRY-through-shared-libraries: the same
digit-by-digit binary-sqrt routine appeared inlined in
nx_henyey_greenstein.nx and nx_worley_noise.nx within hours of
each other. Third caller would have triggered "rule of three";
factoring at two callers + planned third (nx_distance_field_2d,
nx_curl_noise magnitude, nx_atmosphere_scatter optical-depth) is
the right time.
Algorithm: digit-by-digit binary square root (Wikipedia "Methods
of computing square roots", section "Binary numeral system (base
2)"). Returns floor(sqrt(n)) for n >= 0; refuses (returns 0) for
n < 0. O(log n) iterations. No division, no multiplication
except shifts -- safe on every Nishi target without depending on
the host's idiv.
Q10 wrapper: nx_isqrt_q10(x_q10) computes sqrt(x) where x is Q10-
scaled, returning the result also in Q10. Implementation:
sqrt(x) = sqrt(x_q10 / Q) = sqrt(x_q10) / sqrt(Q) = sqrt(x_q10) /
sqrt(Q). To recover Q10 scaling: sqrt(x_q10) * Q / sqrt(Q) =
sqrt(x_q10) * sqrt(Q) = sqrt(x_q10 * Q) -- this is the standard
Q-to-Q sqrt trick. For Q = 1024, sqrt(Q) = 32, so we can
alternatively compute nx_isqrt(x_q10) * 32 -- but the multiply-
then-sqrt form preserves more precision for small x_q10 values.
Loss audit: floor() in the integer-sqrt step truncates the
fractional bit; max relative error 1 / floor(sqrt(n)) at the
smallest representable values, asymptotically 0% as n grows.
genealogy_id: wikipedia_binary_isqrt + abacus_long_division_sqrt
lineage_id: nx_isqrt_digit_by_digit_binary
nx_safety_envelope:
intended_use: "Integer square root (digit-by-digit binary)
+ Q10 wrapper -- shared math primitive for
substrate kernels (noise, distance fields,
attenuation, atmospheric scattering)"
sil_target: SIL2 (math primitive; correctness affects
every consumer)
dependencies 2 imports · 23 importers
diagram shows first 10 each side; +0 more imports, +13 more importers in the complete lists below.
imports: nx_syscalls.nxnx_tier.nx
imported by: nx_acceleration.nxnx_audio_spatial.nxnx_audio_spatial_test.nxnx_bioacoustic_bench.nxnx_force.nxnx_gcode_extrude.nxnx_geo_buffer.nxnx_geo_distance.nxnx_geo_haversine.nxnx_geo_simplify.nxnx_groupnorm.nxnx_layernorm.nxnx_mesh_qem.nxnx_mesh_sculpt.nxnx_monte_carlo.nxnx_patch_attribution.nxnx_pillar_physics.nxnx_polygon.nxnx_rmsnorm.nxnx_sdf.nxnx_squeaker.nxnx_torque.nxnx_vox_source.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 58 | const NX_MAGIC_1024: i64 = 1024 |
| 59 | const NX_MAGIC_10000: i64 = 10000 |
| 60 | const NX_MAGIC_1048576: i64 = 1048576 |
| 61 | const NX_MAGIC_9999: i64 = 9999 |
| 62 | const NX_MAGIC_1000000000000: i64 = 1000000000000 |
| 63 | const NX_MAGIC_1000000: i64 = 1000000 |
| 64 | const NX_MAGIC_4096: i64 = 4096 |
| 65 | const NX_MAGIC_2048: i64 = 2048 |
| 96 | const NX_ISQRT_Q: nx_int = 1024 |
functions
| 69 | func nx_isqrt(n: nx_int) -> nx_int |
| 98 | func nx_isqrt_q10(x_q10: nx_int) -> nx_int |
| 104 | func main() -> i64 |