nx_exp.nx
buildroot/runtime/nx_exp.nx
about
nx_exp.nx -- exp(x) primitive in Q10 fixed point.
Bits-up math primitive. Replaces / generalises the previously
private _attn_exp_q10 helper inside nx_attention.nx. Public so
nx_silu, nx_softmax (future generalisation), nx_gelu, attention,
and any future kernel that needs exp() can compose against ONE
canonical implementation.
===== Domain =====================================================
Q10-only. Input x_q10 in i64. We split by sign for stability:
x >= 0: exp grows; in Q10 i64 we have headroom only up to
exp(40) ~= 2.35e17 which fits i64. Return clamped at
i64-max-headroom for x > 40 (rare in our pipelines).
x < 0: exp decays toward 0. Use the 16-entry lookup table
for x in [-7.5, 0) at 0.5 Q10 bin width; for x <= -7.5
return 0 (negligible under Q10 precision).
We expose three entrypoints:
nx_exp_q10_neg(x_q10) -- caller-asserts x <= 0; lookup path
nx_exp_q10(x_q10) -- general; dispatches by sign
nx_exp_q10_clamped(x_q10) -- same as nx_exp_q10 but saturates
large positives to a documented
ceiling for softmax-like usage
===== Lookup table ==============================================
Values of exp(-k*0.5) for k = 0..15 in Q10:
k=0 exp(0) = 1024
k=1 exp(-0.5) = 621
k=2 exp(-1.0) = 376
k=3 exp(-1.5) = 228
k=4 exp(-2.0) = 138
k=5 exp(-2.5) = 84
k=6 exp(-3.0) = 51
k=7 exp(-3.5) = 31
dependencies 2 imports · 3 importers
imports: nx_syscalls.nxnx_tier.nx
imported by: nx_arrhenius.nxnx_ferment_kinetics.nxnx_silu.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 72 | const NX_MAGIC_1024: i64 = 1024 |
| 73 | const NX_MAGIC_2048: i64 = 2048 |
| 74 | const NX_MAGIC_9000: i64 = 9000 |
| 75 | const NX_MAGIC_1685: i64 = 1685 |
| 76 | const NX_MAGIC_1695: i64 = 1695 |
| 77 | const NX_MAGIC_2780: i64 = 2780 |
| 78 | const NX_MAGIC_2800: i64 = 2800 |
| 79 | const NX_MAGIC_7580: i64 = 7580 |
| 80 | const NX_MAGIC_7610: i64 = 7610 |
| 81 | const NX_MAGIC_100000: i64 = 100000 |
| 83 | const NX_EXP_Q10: nx_int = 1024 |
| 84 | const NX_EXP_BIN_WIDTH_Q10: nx_int = 512 // 0.5 in Q10 |
| 85 | const NX_EXP_CLAMP_NEG_Q10: nx_int = 7680 // 7.5 in Q10 |
| 86 | const NX_EXP_TABLE_N: nx_int = 16 |
| 139 | const NX_EXP_SAT_Q10: nx_int = 9000000000 // ~8.8 million in raw units |
functions
| 88 | func _nx_exp_table_get(bin: nx_int) -> nx_int called by 1: nx_exp_q10_neg |
| 115 | func nx_exp_q10_neg(x_q10: nx_int) -> nx_int |
| 141 | func nx_exp_q10(x_q10: nx_int) -> nx_int |
| 162 | func main() -> i64 |