IMPORTANT: To view this page as Markdown, append `.md` to the URL (e.g. /max/get-started.md). For the complete documentation index, see llms.txt.
Skip to main content
For the complete documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /max/get-started.md).

Mojo function

decode_e2m1_to_f32_inject

def decode_e2m1_to_f32_inject[width: SIMDLength, //](nibble: SIMD[DType.uint16, width]) -> SIMD[DType.float32, width]

Decodes E2M1 nibbles to float32 by exponent injection (Preston's trick).

A branch-free alternative to decode_e2m1_to_f32 with NO select: inject the 3 value bits (e1 e0 m0) and the sign directly into a float32 bit pattern at a SHIFTED exponent position, then renormalize with a single * 2^126 multiply (a power-of-two scale, hence exact). The result is bit-identical to decode_e2m1_to_f32 / E2M1_TO_FLOAT32[nibble] for all 16 values on a denormal-honoring target (verified host-side, including +-0 and the signed values).

!!! warning "Wrong on flush-to-zero (FTZ) GPUs, including Apple M5" This trick relies on the +-0.5 E2M1 values (E == 0, m == 1) producing a denormal float32 intermediate (0x00400000) that survives until the * 2^126 renormalizes it. On a GPU that flushes denormals to zero on arithmetic inputs -- the Apple M5 does -- that intermediate is zeroed and +-0.5 decodes to +-0.0 (verified on-device: nibbles 1 and 9 mismatch, every other value is exact). Use decode_e2m1_to_f32 (which builds the normalized value directly, no denormal intermediate) on Apple GPU and any FTZ target. This function is retained only for non-FTZ targets and as documentation of why the injection trick does not port to M5.

Construction (float32 s | 8-bit exp | 23-bit mantissa): place (e1 e0 m0) at bits 22..24 and the sign at bit 31, leaving a denormalized/small float whose significand encodes the value; * 2^126 shifts those bits into the proper exponent range, reproducing 2^(E-1) * (1 + m/2) for E >= 1 and 0.5 * m for E == 0 exactly (the same value the table holds). The E == 0, m == 1 case is the lone denormal intermediate (see the warning).

NOTE on folding: 2^126 CANNOT be folded into the per-block FP8 scale -- scale * 2^126 overflows float32 for any scale >= 4.0 (fp8_e4m3 scales routinely exceed this), which corrupts the result. The * 2^126 must be applied to the injected value FIRST (where the product is <= 6.0, no overflow), then the caller multiplies by the block scale. So this is NOT a multiply saved over decode_e2m1_to_f32 -- it trades the select + the (E+126)<<23 | m<<22 assembly for an extra * 2^126; whether it is faster is a per-target measurement (on Apple M5 it is moot -- it is wrong, see the warning -- and the dequant cost there is the scale LOAD, not the arith).

Parameters:

  • width (SIMDLength): SIMD width (lane count) of the nibble vector.

Args:

Returns:

SIMD[DType.float32, width]: The decoded values as SIMD[DType.float32, width], bit-identical to E2M1_TO_FLOAT32[nibble].

Was this page helpful?