Precision Levels

Transcendental functions come in multiple precision variants. Pick the level that matches your accuracy needs.

Precision Tiers

SuffixPrecisionRelative SpeedTypical Use
_lowp~12 bits (~3.5 decimal digits)FastestGraphics, audio, game physics
_midp~20 bits (~6 decimal digits)BalancedGeneral compute, ML inference
use magetypes::simd::{
    generic::f32x8,
    backends::F32x8Convert,
};

#[inline(always)]
fn example<T: F32x8Convert>(token: T) {
    let v = f32x8::<T>::splat(token, 2.0);

    let fast     = v.exp2_lowp();   // ~12-bit precision
    let balanced = v.exp2_midp();   // ~20-bit precision
}

There are no unsuffixed "full precision" transcendentals — _midp is the highest level. For exact results, use sqrt() (a hardware instruction).

When to Use Each

_lowp (~12 bits): Use when visual or perceptual quality is what matters. 12 bits of precision means errors below 1 part in 4000 — invisible in pixel colors, inaudible in audio samples, and unnoticeable in physics simulations. The speed advantage compounds when you're calling these functions millions of times per frame.

_midp (~20 bits): The default choice when you don't have a strong reason to pick another. Accurate enough for ML inference, signal processing, and most numerical work. The _midp variants use the same polynomial families as _lowp but with more terms.

Precise Variants

Some _midp functions have a _precise variant that adds a correction step:

use magetypes::simd::{
    generic::f32x8,
    backends::F32x8Convert,
};

#[inline(always)]
fn example<T: F32x8Convert>(token: T) {
    let v = f32x8::<T>::splat(token, 2.0);

    let result = v.log2_midp();          // ~20-bit precision
    let result = v.log2_midp_precise();  // Slightly more accurate, slightly slower
}

Available _precise variants: log2_midp_precise, ln_midp_precise, pow_midp_precise, log10_midp_precise, cbrt_midp_precise.

Unchecked Variants

Functions with domain restrictions (log requires positive input, etc.) have _unchecked variants that skip validation:

// given token: T where T: F32x8Convert
// let v = f32x8::<T>::splat(token, 2.0);

// Checked: returns NaN for non-positive inputs
let result = v.ln_lowp();

// Unchecked: undefined for non-positive inputs, slightly faster
let result = v.ln_lowp_unchecked();

Use _unchecked only when you've already validated inputs or your algorithm guarantees valid ranges. The speed difference is small — the check is usually a single comparison.

Available _unchecked variants exist for both _lowp and _midp tiers: log2, exp2, ln, exp, log10, pow.

Available Combinations

Function_lowp_midp_midp_precise
exp2yesyes
expyesyes
log2yesyesyes
lnyesyesyes
log10yesyesyes
powyesyesyes
cbrtyesyes
sqrtexact hardware instruction

sqrt is a hardware instruction, not an approximation — there's no precision variant because it's already fast and exact.

Found an error or it needs a clarification? Open an issue on GitHub.
Substantiated corrections will be incorporated with attribution.