Advanced mathematics
Advanced mathematics provides 23 operations on both f32 and f64. Functions share portable Rust kernels across native and Wasm backends.
Calls and implementation
Functions exist on engine.f32/f64 and their arena counterparts. pow/hypot/atan2 accept a same-dtype vector or right scalar; atan2 takes (y, x). Inputs and scalars are represented in the target dtype. Internal advanced-math algorithms may use wider intermediates, rounding the final result to the target. This does not change basic arithmetic's per-step precision contract.
Default output is independent. Explicit output supports exact aliases with either binary input; partial overlap, wrong dtype/length and expired handles fail before writing. Empty input returns empty output. Domain errors yield per-element NaN rather than throwing. NaN payload and sign are unspecified.
The implementation pins Rust libm 0.2.16, disables default architecture features and enables force-soft-floats. Native and Wasm bindings use the same Rust algorithms, with no host libm, SLEEF/C++ dependency or fast-math mode. These signatures use scalar fallback on all SIMD backends. The libm license is shipped in the package. Consumers need neither MPFR nor Rust.
Special values
Rules apply to both floating types. Unless specified otherwise, NaN propagates, overflow yields appropriately signed infinity, and underflow is gradual. Subnormals are not deliberately flushed to zero. Trigonometric inputs use radians.
| Function | Domain and special values |
|---|---|
exp/exp2 | All real inputs; ±0 → 1, +∞ → +∞, −∞ → +0 |
expm1 | Preserve ±0; +∞ → +∞, −∞ → −1; avoid cancellation for small inputs |
log/log2/log10 | Positive inputs; ±0 → −∞, negative inputs → NaN, 1 → +0, +∞ → +∞ |
log1p | x ≥ −1; −1 → −∞, smaller inputs → NaN; preserve ±0; +∞ → +∞ |
pow | See the separate power rules below |
cbrt | All real inputs; preserve ±0 and ±∞; negative inputs have negative cube roots |
hypot | Nonnegative result; either infinity takes precedence over NaN; two zeros → +0; avoid intermediate square overflow |
sin/tan | Finite real inputs; preserve ±0; infinities → NaN; reduce large arguments |
cos | Finite real inputs; ±0 → 1; infinities → NaN |
asin | [−1, 1]; preserve ±0; ±1 → rounded ±π/2; outside domain → NaN |
acos | [−1, 1]; 1 → +0, −1 → rounded π, ±0 → rounded π/2; outside domain → NaN |
atan | All real inputs; preserve ±0; infinities → rounded ±π/2 |
atan2 | Quadrant-aware (y, x); signed zeros and infinities follow the rules below |
sinh | Preserve ±0 and ±∞; large finite magnitude may overflow |
cosh | ±0 → 1; either infinity → +∞; large finite magnitude may overflow |
tanh | Preserve ±0; infinities → ±1; large finite values may round to ±1 |
asinh | Preserve ±0 and ±∞; avoid intermediate square overflow |
acosh | [1, +∞]; 1 → +0; +∞ → +∞; all x < 1, including −∞ and ±0, → NaN |
atanh | [−1, 1]; preserve ±0; ±1 → ±∞; outside domain → NaN |
Finite floating values are not exact mathematical π/2 poles of tan. For atan2, y = ±0 and x = +0/+∞ gives ±0; x = −0/−∞ gives ±π. Finite nonzero y with x = ±0 gives ±π/2. Two infinite inputs select ±π/4 or ±3π/4 according to quadrant.
pow follows C/MPFR-style special values: pow(NaN, ±0) = 1, pow(1, NaN) = 1, and pow(-1, ±Infinity) = 1. The last two differ from JavaScript Math.pow. Other NaNs propagate. A finite negative base and finite noninteger exponent yield NaN; parity uses the exponent already represented in its dtype.
For ±0 bases, positive exponents yield zero and negative exponents yield infinity; only −0 with an odd integer exponent has a negative result. For ±∞ bases, positive exponents yield infinity and negative exponents yield zero; only −∞ with an odd integer exponent gives a negative sign. Infinite exponents select +0/+∞ according to the magnitude of the base relative to 1; magnitude 1 gives 1. General powers are not rewritten as exp(y * log(x)).
Independent oracle tests exposed negative-input errors in libm acosh/acoshf. laneops explicitly checks x < 1 first. Keep the Rust/API/oracle regressions when updating libm; a version change alone is not validation.
Accuracy contract
Error is the integer distance between representable numbers and the correctly rounded target-dtype reference, not error relative to an infinite-precision real. Ordered bit patterns measure normals and subnormals uniformly. Zero signs, infinity signs and NaN classification must match exactly.
The registry budgets are 4 ULP for pow and 2 ULP for every other function, per dtype. These are sampled acceptance budgets, not a proof over all possible inputs or a promise of correct rounding.
The independent MPFR oracle imports inputs exactly, computes directed intervals and rounds directly to the target dtype. Ordinary tests consume the committed fixture without requiring MPFR. See numerical validation for reproduction commands and the accuracy archive for recorded measurements.