Expand description
A one-byte unsigned normalized number (UNORM8), with no allocation or std.
f8 stores an integer b and represents the real number b / 255.
It is not an IEEE floating-point format: there is no exponent, negative
zero, infinity, or NaN. All 256 bit patterns are valid and ordered.
§Quantization
Conversion from f32 rounds the exact real product 255 * x to the
nearest integer, ties to even, after clamping to [0, 1]. NaN maps to zero.
Unlike (x * 255.0).round(), this neither rounds ties away from zero nor
introduces an intermediate floating-point rounding at bin boundaries.
Conversion to f32 is the correctly rounded value of b / 255.
use f8::f8;
let half = f8::from_f32(0.5);
assert_eq!(half.to_bits(), 128);
assert_eq!(half.to_f32(), 128.0 / 255.0);
assert_eq!(half + half, f8::ONE); // Saturates instead of wrapping.
assert_eq!(half * f8::ONE, half);§Traits
| Trait | Contract |
|---|---|
From<u8>, Into<u8> | Lossless raw storage, not a numeric cast. |
From<f32> | Saturating, nearest-even quantization; NaN becomes zero. |
Into<f32>, Display | Normalized value, not the raw byte. |
Eq, Ord, Hash | Compare/hash the byte; a total numerical order. |
Default | f8::ZERO. |
Add, Sub and assignments | Exact UNORM addition/subtraction, saturated. |
Mul, Div and assignments | Saturated, nearest-even UNORM arithmetic. |
Sum, Product | Left folds, starting at zero/one; quantize each step. |
Serde (feature serde) | A newtype named f8 containing one u8. |
Operators and iterator traits accept owned and borrowed values. Division
defines 0 / 0 = 0 and positive / 0 = 1; no arithmetic operation panics.
Quantized multiplication is not associative. Accumulate in f32 instead
when intermediate quantization is undesirable.
§Platforms and Performance
Scalar conversion and arithmetic use integer operations, even on soft-float
microcontrollers. f8::from_f32_slice and f8::to_f32_slice reuse caller
storage. With simd, x86-64 bulk encoding detects AVX2 and OS support at
runtime and uses an integer-only assembly kernel. Other targets, short
inputs, and Miri use portable Rust. A compile-time AVX2 target needs no probe.
AVX-512 targets stay in Rust so LLVM can use the wider instruction set.
Both features (serde, simd) are enabled by default; neither requires
std or an allocator. Disable default features for a dependency-free build.
Bare-metal x86-64, UEFI, and SGX always use Rust: this crate never probes or
assumes ownership of extended SIMD state on those targets. Explicit target
features may still let the compiler vectorize the portable loops.
Layout is transparent over u8, with size/alignment one. Slice views are
zero-copy and endian-independent. This storage contract corresponds to
UNORM8, not any of the E4M3/E5M2 formats sometimes also called “FP8”.
Structs§
- f8
- A one-byte UNORM representing
bits / 255in the inclusive range[0, 1].