Skip to content

magetypes: recip() returns NaN at ±inf (Newton refinement) — bites sigmoid-after-exp-saturation #64

Description

@lilith

Found while implementing a SPAN-family SR forward on magetypes 0.9.28 (zensr).

f32xN::recip() is hardware-rcp + Newton-Raphson refinement, so recip(inf) = NaN (the refinement computes inf * 0). exp_midp/exp2_midp correctly saturate to inf for large inputs, which makes the natural sigmoid formulation

let s = ((-v).exp_midp() + one).recip();   // NaN wherever v <= ~-88

produce NaN lanes on real data (conv pre-activations reach ±100 in practice; 97% of the output tensor went NaN before root-causing). IEEE division is exact at the rails (1/inf = 0), so one / (exp + one) is the correct spelling.

Suggestions (any subset):

  1. Document the inf/NaN domain of recip() (and rsqrt if refined the same way) loudly in the doc comment.
  2. Consider a recip_precise() that blends recip(±inf) -> ±0 and recip(±0) -> ±inf post-refinement.
  3. A magetypes-level sigmoid_midp()/silu_midp() helper would remove the footgun entirely for NN work.

Bonus observation from the same session: f32::max-based diff checks mask NaN (max ignores NaN), which let this slip past a golden comparison until RMSE went NaN — maybe worth a note in the testing docs.

Repro + fix in imazen zensr repo (crates/zensr-micro/src/simd.rs, silu/gate kernels), 2026-07-22 session.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions