typedef nk_f32_t(*) nk_f32_unary_punned_t(nk_f32_t); The scalar wrappers in include/numkong/types.hpp are storage-first types.
They encode raw layout, default output types, and the kernel function pointer signatures for each family.
| Type | Layout | Bytes | Range | Inf | NaN |
|---|---|---|---|---|---|
nk_f16_t | 1+5+10 | 2 | ±65504 | yes | yes |
nk_bf16_t | 1+8+7 | 2 | ±3.4×10³⁸ | yes | yes |
nk_e4m3_t | 1+4+3 | 1 | ±448 | no | yes |
nk_e5m2_t | 1+5+2 | 1 | ±57344 | yes | yes |
nk_e2m3_t | 1+2+3 | 1 | ±7.5 | no | no |
nk_e3m2_t | 1+3+2 | 1 | ±28 | no | no |
nk_e2m1x2_t | 2 × (1+2+1) | 1 | ±6 per nibble | no | no |
nk_u1x8_t | 8 packed bits | 1 | 0 or 1 per bit | n/a | n/a |
nk_u4x2_t | 2 × 4-bit | 1 | 0…15 per nibble | n/a | n/a |
nk_i4x2_t | 2 × 4-bit signed | 1 | −8…7 per nibble | n/a | n/a |
The layout column shows sign, exponent, and mantissa bit counts for floating-point types.
For nk_f16_t, 1+5+10 means one sign bit, five exponent bits, and ten mantissa bits, totaling 16 bits stored in 2 bytes.
For nk_bf16_t, the wider exponent field (8 bits) gives the same dynamic range as IEEE 754 single precision but with reduced mantissa precision.
The Float8 types nk_e4m3_t and nk_e5m2_t follow the OFP8 specification.
The narrower nk_e2m3_t and nk_e3m2_t types are MX-compatible micro-floats, and nk_e2m1x2_t packs two FP4 values of the MXFP4 and NVFP4 formats.
Sub-byte types nk_e2m1x2_t, nk_u1x8_t, nk_u4x2_t, and nk_i4x2_t pack multiple logical values into a single byte.
Element 0 sits in the high nibble or the most significant bit, and every dimension count must be a multiple of the values per byte.
Default promotions are encoded on the type.
For example, f32_t::dot_result_t is wider than f32_t. i8_t::dot_result_t is i32_t. u1x8_t::dot_result_t is u32_t.
The higher-level templates use result_type_ = typename in_type_::dot_result_t and similar defaults.
The fast typed overloads are constrained so that overriding the result type away from the native policy can disable the specialized path and fall back to the more generic one.
When __cpp_lib_format >= 202110L for the C++23 <format> header support, all NumKong scalar types provide std::formatter specializations with similar format specs to the traditional float.
For the Float16 type, the output for nk::f16_t::from_f32(3.14f) will look like:
| Format spec | Output example | Description |
|---|---|---|
{} | 3.140625 | Clean float value |
{:#} | 3.140625 [0x4248] | Annotated with hex bits |
{:.2f} | 3.14 | Precision forwarded to float formatter |
{:x} | 4248 | Raw hex bits |
{:#x} | 0x4248 | Hex with prefix |
{:X} | 4248 | Uppercase hex |
{:b} | 0100001001001000 | Binary bits |
{:#b} | 0b0100001001001000 | Binary with prefix |
API
Types
nk_f32_unary_punned_tScalar kernels of one shape, cast back from nk_kernel_punned_t by their dispatch points.
nk_f16_to_f32_punned_tScalar conversion kernels of one shape, cast back from nk_kernel_punned_t by their dispatch points; the FP8 and FP6 codes share the byte shape.
typedef void(*) nk_f16_to_f32_punned_t(nk_f16_t const *, nk_f32_t *); nk_u1x8_tPacked 8-bit bit-vector (8 booleans in one byte), MSB = dimension 0.
typedef unsigned char nk_u1x8_t; Used for Hamming distance and Jaccard similarity via popcount. Dimension count must be a multiple of 8, the values per byte.
nk_i4x2_tPacked 4-bit signed integer pair (2 × i4 in one byte), [high nibble : low nibble].
typedef unsigned char nk_i4x2_t; Range per element: [−8, +7]. Elements sign-extended to i8 for arithmetic. Dimension count must be a multiple of 2, the values per byte.
nk_u4x2_tPacked 4-bit unsigned integer pair (2 × u4 in one byte), [high nibble : low nibble].
typedef unsigned char nk_u4x2_t; Range per element: [0, 15]. Elements zero-extended to u8 for arithmetic. Dimension count must be a multiple of 2, the values per byte.
nk_e4m3_t8-bit E4M3 float (OCP FP8): sign(1) + exponent(4) + mantissa(3), bias=7.
typedef unsigned char nk_e4m3_t; Range: ±448, no infinities (all-ones exponent → NaN at 0x7F/0xFF). 114 of 254 finite values, or 44.9%, fall in [−1, +1].
nk_e5m2_t8-bit E5M2 float (OCP FP8): sign(1) + exponent(5) + mantissa(2), bias=15.
typedef unsigned char nk_e5m2_t; Range: ±57 344, supports infinities at 0x7C/0xFC. 122 of 248 finite values (49.2%) fall in [−1, +1].
nk_e2m3_t6-bit E2M3 micro-float (OCP MX v1.0): sign(1) + exponent(2) + mantissa(3), bias=1.
typedef unsigned char nk_e2m3_t; Stored as 0b00SEEMMM with 2 bits of padding. Range: ±7.5, no infinities or NaN. 64 total codes: 48 normal, 14 subnormal (exp=0, mant ≠ 0), 2 zeros (±0). 18 of 64 values (28.1%) fall in [−1, +1]. Subnormal values span [±0.125, ±0.875]. Losslessly promotable to E4M3 by rebiasing exponent +6 (normals) or normalizing (subnormals).
nk_e3m2_t6-bit E3M2 micro-float (OCP MX v1.0): sign(1) + exponent(3) + mantissa(2), bias=3.
typedef unsigned char nk_e3m2_t; Stored as 0b00SEEEMM with 2 bits of padding. Range: ±28, no infinities or NaN. 64 total codes: 56 normal, 6 subnormal (exp=0, mant ≠ 0), 2 zeros (±0). 26 of 64 values (40.6%) fall in [−1, +1]. Subnormal values span [±0.0625, ±0.1875]. Losslessly promotable to E5M2 by rebiasing exponent +12 (normals) or normalizing (subnormals).
nk_e2m1x2_tPacked 4-bit E2M1 micro-float pair (2 × e2m1 in one byte), [high nibble : low nibble].
typedef unsigned char nk_e2m1x2_t; OCP MX v1.0 sub-format: sign(1) + exponent(2) + mantissa(1), bias=1. Range: ±6.0, no Inf or NaN. 16 total codes: 8 magnitudes {0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0} × 2 signs (two zeros). Used as the element type of MXFP4 (block=32, UE8M0 scales) and NVFP4 (block=16, UE4M3 scales). Dimension count must be a multiple of 2, the values per byte.
nk_ue8m0_tUnsigned 8-bit power-of-two scale (OCP MX v1.0): 8-bit biased exponent, no sign or mantissa.
typedef unsigned char nk_ue8m0_t; Encodes 2^(v - 127) for v ∈ [1, 254]; v = 0 is zero; v = 255 is the NaN-block sentinel. Used as the per-block scale byte for MXFP4, MXFP6, MXFP8, MXINT8.
nk_ue4m3_tUnsigned 8-bit E4M3 scale (NVFP4): sign-bit forced to 0, otherwise identical to E4M3.
typedef unsigned char nk_ue4m3_t; Range: [0, +448]. Used as the per-block scale byte for NVFP4 (block=16) alongside an f32 "tensor scale".
nk_i8_tSigned 8-bit integer.
nk_u8_tUnsigned 8-bit integer.
nk_i16_tSigned 16-bit integer.
nk_u16_tUnsigned 16-bit integer.
nk_i32_tSigned 32-bit integer.
nk_u32_tUnsigned 32-bit integer.
nk_i64_tSigned 64-bit integer.
nk_u64_tUnsigned 64-bit integer.
nk_f32_tSingle-precision (32-bit) IEEE 754 float.
nk_f64_tDouble-precision (64-bit) IEEE 754 float.
nk_dtype_tEnumeration of supported scalar data types.
enum nk_dtype_t Includes complex type descriptors which in C code would use the real counterparts, but the independent flags contain metadata to be passed between programming language interfaces.
Block-scaled formats are composites, element_dtype | scale_dtype: two bits set, so they never collide with each other or with a singleton. The scale dtype fixes the block, 16 for UE4M3 in NVFP4 and 32 for UE8M0 in the MX family.
Values
nk_dtype_unknown_k | 0 | Unknown data type. |
|---|---|---|
nk_u1_k | 1 << 1 | Single-bit values packed into 8-bit words. |
nk_i8_k | 1 << 2 | 8-bit signed integer. |
nk_i16_k | 1 << 3 | 16-bit signed integer. |
nk_i32_k | 1 << 4 | 32-bit signed integer. |
nk_i64_k | 1 << 5 | 64-bit signed integer. |
nk_u8_k | 1 << 6 | 8-bit unsigned integer. |
nk_u16_k | 1 << 7 | 16-bit unsigned integer. |
nk_u32_k | 1 << 8 | 32-bit unsigned integer. |
nk_u64_k | 1 << 9 | 64-bit unsigned integer. |
nk_f64_k | 1 << 10 | Double precision floating point. |
nk_f32_k | 1 << 11 | Single precision floating point. |
nk_f16_k | 1 << 12 | Half precision floating point. |
nk_bf16_k | 1 << 13 | Brain floating point. |
nk_e4m3_k | 1 << 14 | FP8 E4M3 floating point. |
nk_e5m2_k | 1 << 15 | FP8 E5M2 floating point. |
nk_i4_k | 1 << 16 | 4-bit signed integers packed into 8-bit words. |
nk_u4_k | 1 << 17 | 4-bit unsigned integers packed into 8-bit words. |
nk_e2m3_k | 1 << 18 | FP6 E2M3 floating point. |
nk_e3m2_k | 1 << 19 | FP6 E3M2 floating point. |
nk_f64c_k | 1 << 20 | Complex double precision floating point. |
nk_f32c_k | 1 << 21 | Complex single precision floating point. |
nk_f16c_k | 1 << 22 | Complex half precision floating point. |
nk_bf16c_k | 1 << 23 | Complex brain floating point. |
nk_e2m1_k | 1 << 24 | FP4 E2M1 floating point (element of MXFP4 and NVFP4). |
nk_ue8m0_k | 1 << 25 | UE8M0 unsigned pow-2 scale byte (MX family block scale). |
nk_ue4m3_k | 1 << 26 | UE4M3 unsigned E4M3 scale byte (NVFP4 block scale). |
nk_nvfp4_k | nk_e2m1_k | nk_ue4m3_k | NVIDIA NVFP4 (block=16, f32 tensor scale). |
nk_mxfp4_k | nk_e2m1_k | nk_ue8m0_k | OCP MXFP4 (block=32). |
nk_mxfp6e2m3_k | nk_e2m3_k | nk_ue8m0_k | OCP MXFP6 (E2M3 variant, block=32). |
nk_mxfp6e3m2_k | nk_e3m2_k | nk_ue8m0_k | OCP MXFP6 (E3M2 variant, block=32). |
nk_mxfp8e4m3_k | nk_e4m3_k | nk_ue8m0_k | OCP MXFP8 (E4M3 variant, block=32). |
nk_mxfp8e5m2_k | nk_e5m2_k | nk_ue8m0_k | OCP MXFP8 (E5M2 variant, block=32). |
nk_mxint8_k | nk_i8_k | nk_ue8m0_k | OCP MXINT8 (block=32). |
Spellings
char const * nk_dtype_name(nk_dtype_t dtype);nk_block_scaled_format_tDescriptor for a block-scaled tensor layout (OCP MX family + NVIDIA NVFP4).
struct nk_block_scaled_format_t Elements are grouped in fixed-size contiguous blocks; each block has its own scale_dtype scale byte stored in a separate scales buffer. An optional tensor_scale_dtype scalar multiplier applies to the whole tensor (NVFP4's per-tensor FP32 factor; absent for the MX family).
Plain (non-block-scaled) buffers are described by scale_dtype = nk_dtype_unknown_k, tensor_scale_dtype = nk_dtype_unknown_k, and block_size = 0 — use the nk_plain() factory.
Fields
element_dtype | nk_dtype_t | Per-element dtype: e2m1/e4m3/e5m2/e2m3/e3m2/i8 (or any for plain). |
|---|---|---|
scale_dtype | nk_dtype_t | Per-block scale: ue8m0 (MX) or ue4m3 (NVFP4); unknown for plain. |
tensor_scale_dtype | nk_dtype_t | Per-tensor multiplier: f32 (NVFP4) or unknown (MX, plain). |
block_size | nk_size_t | Elements per block: 16 (NVFP4) or 32 (MX); 0 for plain. |
block_bytes | nk_size_t | Bytes of codes per block, dividing a row stride into a scale row stride; 0 for plain. |
nk_nvfp4_cref_tA read-only NVFP4 scalar: its E2M1 code, its block's UE4M3 scale, and the tensor's F32 scale.
struct nk_nvfp4_cref_t Fields
elements | nk_e2m1x2_t const * | |
|---|---|---|
scales | nk_ue4m3_t const * | |
tensor_scale | nk_f32_t const * |
nk_nvfp4_ref_tThe writable twin of nk_nvfp4_cref_t.
struct nk_nvfp4_ref_t Fields
elements | nk_e2m1x2_t * | |
|---|---|---|
scales | nk_ue4m3_t * | |
tensor_scale | nk_f32_t * |
nk_mxfp4_cref_tA read-only MXFP4 scalar: its E2M1 code, its block's UE8M0 scale.
nk_mxfp4_ref_tThe writable twin of nk_mxfp4_cref_t.
nk_mxfp6e2m3_cref_tA read-only MXFP6 E2M3 scalar: its E2M3 code, its block's UE8M0 scale.
nk_mxfp6e2m3_ref_tThe writable twin of nk_mxfp6e2m3_cref_t.
nk_mxfp6e3m2_cref_tA read-only MXFP6 E3M2 scalar: its E3M2 code, its block's UE8M0 scale.
nk_mxfp6e3m2_ref_tThe writable twin of nk_mxfp6e3m2_cref_t.
nk_mxfp8e4m3_cref_tA read-only MXFP8 E4M3 scalar: its E4M3 code, its block's UE8M0 scale.
nk_mxfp8e4m3_ref_tThe writable twin of nk_mxfp8e4m3_cref_t.
nk_mxfp8e5m2_cref_tA read-only MXFP8 E5M2 scalar: its E5M2 code, its block's UE8M0 scale.
nk_mxfp8e5m2_ref_tThe writable twin of nk_mxfp8e5m2_cref_t.
nk_mxint8_cref_tA read-only MXINT8 scalar: its I8 code, its block's UE8M0 scale.
nk_mxint8_ref_tThe writable twin of nk_mxint8_cref_t.
nk_dtype_family_tThe kind of number a data type holds, as nk_dtype_family reports it.
enum nk_dtype_family_t Values
nk_dtype_family_unknown_k | 0 | |
|---|---|---|
nk_dtype_family_float_k | ||
nk_dtype_family_complex_float_k | ||
nk_dtype_family_int_k | ||
nk_dtype_family_uint_k |
nk_nvfp4_tAlias for the half-precision floating-point type on Arm.
struct nk_nvfp4_t Clang and GCC bring the float16_t symbol when you compile for AArch64. MSVC lacks it, and it's vld1_f16-like intrinsics are in reality macros, that cast to 16-bit integers internally, instead of using floats. Some of those are defined as aliases, so we use #define preprocessor directives instead of typedef to avoid errors.
Block-scaled composite POD types — one value is one whole block.
Each composite combines a packed element buffer with its per-block scale byte in a single POD struct. The struct IS the value: sizeof(nk_nvfp4_t) == 9 means one NVFP4 value, not one element. Storage in containers strides by sizeof(struct); logical element count per value is reported by nk_dimensions_per_value(composite_dtype) (16 for NVFP4, 32 for MX). Dimension count must be a multiple of that block size.
The NVFP4 per-tensor f32 tensor scale multiplier is not part of the block value — it lives on the enclosing tensor and is passed explicitly to encode/decode helpers.
nk_mxfp4_tOne OCP MXFP4 block: 32 E2M1 elements sharing a UE8M0 scale.
struct nk_mxfp4_t nk_mxfp6e2m3_tOne OCP MXFP6 E2M3 block: 32 E2M3 elements sharing a UE8M0 scale.
struct nk_mxfp6e2m3_t nk_mxfp6e3m2_tOne OCP MXFP6 E3M2 block: 32 E3M2 elements sharing a UE8M0 scale.
struct nk_mxfp6e3m2_t nk_mxfp8e4m3_tOne OCP MXFP8 E4M3 block: 32 E4M3 elements sharing a UE8M0 scale.
struct nk_mxfp8e4m3_t nk_mxfp8e5m2_tOne OCP MXFP8 E5M2 block: 32 E5M2 elements sharing a UE8M0 scale.
struct nk_mxfp8e5m2_t nk_mxint8_tOne OCP MXINT8 block: 32 I8 elements sharing a UE8M0 scale.
struct nk_mxint8_t nk_fui16_t16-bit union for f16/bf16/u16/i16 bit manipulation.
nk_fui32_t32-bit union for f32/u32/i32 bit manipulation.
nk_fui64_t64-bit union for f64/u64/i64 bit manipulation.
nk_f16c_tHalf-precision (32-bit) complex number — {real: f16, imag: f16}.
nk_bf16c_tBFloat16 (32-bit) complex number — {real: bf16, imag: bf16}.
nk_f32c_tSingle-precision (64-bit) complex number — {real: f32, imag: f32}.
nk_f64c_tDouble-precision (128-bit) complex number — {real: f64, imag: f64}.
nk_b32_vec_tSmall 4-byte memory slice viewable as different types.
nk_b64_vec_tSmall 8-byte memory slice viewable as different types.
nk_b128_vec_tSmall 16-byte memory slice viewable as different types.
nk_b256_vec_tSmall 32-byte memory slice viewable as different types.
nk_b512_vec_tSmall 64-byte memory slice viewable as different types.
union nk_b512_vec_t TODO: On GCC and Clang we use __transparent_union__ attribute to allow implicit conversions between the different vector types when passing them as function arguments. The most important side-effect of this is that the argument of such type is passed to functions using the calling convention of the first member of the union, which in our case is a register-based calling convention for SIMD types.
Fields
nk_scalar_buffer_tUnion for type-punned scalar values at language binding boundaries.
union nk_scalar_buffer_t Bridges different type systems (Python, JavaScript, etc.) where scalars arrive as f64 but need to be passed to kernels as typed pointers. Callers fill the appropriate union member based on the target dtype, then pass the union address as void const *.
Fields
Functions
nk_*_sqrt_best× 3Scalar square root, √x.
nk_f32_t nk_f32_sqrt_best(nk_f32_t x, nk_capability_t capabilities); Backends
nk_f32_sqrtserialneonhaswellrvvv128powervsxloongsonasxnk_f64_sqrtserialneonhaswellrvvv128powervsxloongsonasxnk_f16_sqrtserialneonhalfhaswellsapphire
Parameters
x | in | The input value. |
|---|---|---|
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
Returns
The square root of x.
nk_*_rsqrt_best× 3Scalar reciprocal square root, 1 / √x.
nk_f32_t nk_f32_rsqrt_best(nk_f32_t x, nk_capability_t capabilities); Backends
nk_f32_rsqrtserialneonhaswellrvvv128powervsxloongsonasxnk_f64_rsqrtserialneonhaswellrvvv128powervsxloongsonasxnk_f16_rsqrtserialneonhalfhaswellsapphire
Parameters
x | in | The input value. |
|---|---|---|
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
Returns
The reciprocal square root of x.
See also
- C++
std::rsqrt - Rust
f32::rsqrt
nk_*_saturating_add_best× 10Saturating addition clamped to the representable range of the type.
nk_u8_t nk_u8_saturating_add_best(
nk_u8_t a,
nk_u8_t b,
nk_capability_t capabilities); | Symbol | a, b | Backends |
|---|---|---|
nk_u8_saturating_add_best | nk_u8_t | 4 |
nk_i8_saturating_add_best | nk_i8_t | 4 |
nk_u16_saturating_add_best | nk_u16_t | 4 |
nk_i16_saturating_add_best | nk_i16_t | 4 |
nk_u32_saturating_add_best | nk_u32_t | 3 |
nk_i32_saturating_add_best | nk_i32_t | 3 |
nk_u64_saturating_add_best | nk_u64_t | 3 |
nk_i64_saturating_add_best | nk_i64_t | 3 |
nk_i4x2_saturating_add_best | nk_i4x2_t | 1 |
nk_u4x2_saturating_add_best | nk_u4x2_t | 1 |
Backends
nk_u8_saturating_addserialneonhaswellrvvnk_i8_saturating_addserialneonhaswellrvvnk_u16_saturating_addserialneonhaswellrvvnk_i16_saturating_addserialneonhaswellrvvnk_u32_saturating_addserialneonrvvnk_i32_saturating_addserialneonrvvnk_u64_saturating_addserialneonrvvnk_i64_saturating_addserialneonrvvnk_i4x2_saturating_addserialnk_u4x2_saturating_addserial
Parameters
a | in | First operand. |
|---|---|---|
b | in | Second operand. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
Returns
clamp(a + b, MIN, MAX).
nk_*_saturating_mul_best× 10Saturating multiplication clamped to the representable range of the type.
nk_u8_t nk_u8_saturating_mul_best(
nk_u8_t a,
nk_u8_t b,
nk_capability_t capabilities); | Symbol | a, b | Backends |
|---|---|---|
nk_u8_saturating_mul_best | nk_u8_t | 2 |
nk_i8_saturating_mul_best | nk_i8_t | 2 |
nk_u16_saturating_mul_best | nk_u16_t | 2 |
nk_i16_saturating_mul_best | nk_i16_t | 2 |
nk_u32_saturating_mul_best | nk_u32_t | 2 |
nk_i32_saturating_mul_best | nk_i32_t | 2 |
nk_u64_saturating_mul_best | nk_u64_t | 4 |
nk_i64_saturating_mul_best | nk_i64_t | 4 |
nk_i4x2_saturating_mul_best | nk_i4x2_t | 1 |
nk_u4x2_saturating_mul_best | nk_u4x2_t | 1 |
Backends
nk_u8_saturating_mulserialrvvnk_i8_saturating_mulserialrvvnk_u16_saturating_mulserialrvvnk_i16_saturating_mulserialrvvnk_u32_saturating_mulserialrvvnk_i32_saturating_mulserialrvvnk_u64_saturating_mulserialneonhaswellrvvnk_i64_saturating_mulserialneonhaswellrvvnk_i4x2_saturating_mulserialnk_u4x2_saturating_mulserial
Parameters
a | in | First operand. |
|---|---|---|
b | in | Second operand. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
Returns
clamp(a * b, MIN, MAX).
nk_*_order_best× 6Branchless sign-magnitude ordering for non-native floating-point scalars.
int nk_f16_order_best(
nk_f16_t a,
nk_f16_t b,
nk_capability_t capabilities); | Symbol | a, b | Backends |
|---|---|---|
nk_f16_order_best | nk_f16_t | 2 |
nk_bf16_order_best | nk_bf16_t | 1 |
nk_e4m3_order_best | nk_e4m3_t | 1 |
nk_e5m2_order_best | nk_e5m2_t | 1 |
nk_e2m3_order_best | nk_e2m3_t | 1 |
nk_e3m2_order_best | nk_e3m2_t | 1 |
Backends
nk_f16_orderserialsapphirenk_bf16_orderserialnk_e4m3_orderserialnk_e5m2_orderserialnk_e2m3_orderserialnk_e3m2_orderserial
Uses mask = -sign; ordered = value ^ mask — the constant offset cancels in subtraction. Returns negative if a < b, 0 if equal, positive if a > b.
Parameters
a | in | First operand. |
|---|---|---|
b | in | Second operand. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
Returns
Negative if a < b, zero if a == b, positive if a > b.
See also
std::strong_order, Rust total_cmp
Notes
NaN values are ordered at the extremes per IEEE 754 totalOrder (negative NaN < all finite < positive NaN). Callers requiring NaN-exclusion semantics must filter NaN before calling.
nk_f32_sin_serialApproximates the sine of an angle in radians within 3-ULP error on [-2π, 2π].
nk_f32_t nk_f32_sin_serial(nk_f32_t angle_radians); Backends
nk_f32_sinserial
Based on xfastsinf_u3500 in the SLEEF library.
Parameters
angle_radians | in | The input angle in radians. |
|---|
Returns
The approximate sine of the input angle in [-1, 1] range.
nk_f32_cos_serialApproximates the cosine of an angle in radians within 3-ULP error on [-2π, 2π].
nk_f32_t nk_f32_cos_serial(nk_f32_t angle_radians); Backends
nk_f32_cosserial
Based on xfastcosf_u3500 in the SLEEF library.
Parameters
angle_radians | in | The input angle in radians. |
|---|
Returns
The approximate cosine of the input angle in [-1, 1] range.
nk_*_atan_serial× 2Computes the arc-tangent of a value with 0-ULP error bound.
nk_f32_t nk_f32_atan_serial(nk_f32_t input); Backends
nk_f32_atanserialnk_f64_atanserial
Based on xatanf in the SLEEF library.
Based on xatan in the SLEEF library.
Parameters
input | in | The input value. |
|---|
Returns
The arc-tangent of the input value in [-π/2, π/2] radians range.
nk_*_atan2_serial× 2Computes the arc-tangent of (y/x) with 0-ULP error bound.
nk_f32_t nk_f32_atan2_serial(nk_f32_t y_input, nk_f32_t x_input); Backends
nk_f32_atan2serialnk_f64_atan2serial
Based on xatan2f in the SLEEF library.
Based on xatan2 in the SLEEF library.
Parameters
y_input | in | The input sine value. |
|---|---|---|
x_input | in | The input cosine value. |
Returns
The arc-tangent of y_input / x_input in [-π, π] radians range.
nk_f64_sin_serialComputes the sine of the given angle in radians with 0-ULP error bound in [-2π, 2π].
nk_f64_t nk_f64_sin_serial(nk_f64_t angle_radians); Backends
nk_f64_sinserial
Based on xsin in the SLEEF library.
Parameters
angle_radians | in | The input angle in radians. |
|---|
Returns
The approximate sine of the input angle.
nk_f64_cos_serialComputes the cosine of the given angle in radians with 0-ULP error bound in [-2π, 2π].
nk_f64_t nk_f64_cos_serial(nk_f64_t angle_radians); Backends
nk_f64_cosserial
Based on xcos in the SLEEF library.
Parameters
angle_radians | in | The input angle in radians. |
|---|
Returns
The approximate cosine of the input angle in [-1, 1] range.
nk_*_find_kernel× 2Finds the scalar kernel of kind for dtype, from the best of capabilities.
nk_status_t nk_scalar_find_kernel(
nk_kernel_kind_t kind,
nk_dtype_t dtype,
nk_capability_t capabilities,
nk_kernel_punned_t *kernel,
nk_capability_t *capability); | Symbol |
|---|
nk_scalar_find_kernel |
nk_cast_find_kernel |
Parameters
kind | in | The verb whose kernel to find. |
|---|---|---|
dtype | in | The input type the kernel reads. |
capabilities | in | The mask to pick the best capability from. |
kernel | out | The kernel, or null when no capability in capabilities has it. |
capability | out | The capability the kernel belongs to, or zero. |
Statuses
nk_missing_kernel_knk_missing_library_kHeader-only.
nk_cast_bestElementwise type-casting for arrays of entries, plain or block-scaled.
nk_status_t nk_cast_best(
void const *from,
nk_dtype_t from_dtype,
void *to,
nk_dtype_t to_dtype,
nk_size_t count,
nk_capability_t capabilities,
nk_stream_t stream); Backends
nk_castserialneonhaswellskylakeicelakesapphirervvpowervsxv128relaxedcudaampereadarocmmetal
A block-scaled dtype is one of the composites, like nk_mxfp8e4m3_k or nk_nvfp4_k, whose element dtype, scale dtype and block size nk_block_scaled_format_of_dtype derives:
| Source | Destination | Action |
|---|---|---|
| plain | plain | elementwise conversion |
| plain | block-scaled | encodes: per-block amax, derived scale, quantization |
| block-scaled | plain | decodes: reads the scale, dequantizes to the plain dtype |
| block-scaled | block-scaled | transcodes: decode → encode |
Codes and scales are contiguous runs. A destination NVFP4 tensor_scale holding a non-zero value is applied as is; holding zero, it receives the tensor scale that the kernel derives from the source data it encodes.
Parameters
from | in | The count source elements, or an nk_<format>_cref_t if block-scaled. |
|---|---|---|
from_dtype | in | The type of elements in the immutable source array. |
to | out | The count target elements, or an nk_<format>_ref_t if block-scaled. |
to_dtype | in | The type of elements in the mutable target array. |
count | in | Logical elements, a multiple of both block sizes if either is block-scaled. |
capabilities | in | One device's capabilities, like nk_cpu_capabilities_enabled reports. |
stream | in | Null on the CPU, or the GPU stream of that device to queue on. |
Statuses
nk_missing_kernel_kNo capability incapabilitieshas it.
nk_f16_to_f32_bestScalar conversion from f16 to f32, covering every IEEE 754 edge case.
void nk_f16_to_f32_best(
nk_f16_t const *src,
nk_f32_t *dest,
nk_capability_t capabilities); Backends
nk_f16_to_f32serialneonhaswellsapphirepowervsx
| Input | F16 Hex | F32 Hex | Description |
|---|---|---|---|
| +0 | 0x0000 | 0x00000000 | Positive zero |
| -0 | 0x8000 | 0x80000000 | Negative zero |
| +inf | 0x7C00 | 0x7F800000 | Positive infinity |
| -inf | 0xFC00 | 0xFF800000 | Negative infinity |
| NaN | 0x7E00 | 0x7FC00000 | Quiet NaN, payload preserved |
| Min normal | 0x0400 | 0x38800000 | 2⁻¹⁴ |
| Max normal | 0x7BFF | 0x477FE000 | 65504 |
| Min denorm | 0x0001 | 0x33800000 | 2⁻²⁴ |
| Max denorm | 0x03FF | 0x387FC000 | 2⁻¹⁴ - 2⁻²⁴ |
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- Stack Overflow on half-precision conversion: https://stackoverflow.com/a/60047308
- Half-float conversion gist: https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
- Libcanard float16 codec: https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
nk_bf16_to_f32_bestScalar conversion from bf16 to f32.
void nk_bf16_to_f32_best(
nk_bf16_t const *src,
nk_f32_t *dest,
nk_capability_t capabilities); Backends
nk_bf16_to_f32serial
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- Stack Overflow on f32 and bf16 conversion: https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
- Bfloat16 on Cloud TPUs: https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
nk_*_to_f32_best× 2Scalar conversion from FP8 e4m3 to f32.
void nk_e4m3_to_f32_best(
nk_e4m3_t const *src,
nk_f32_t *dest,
nk_capability_t capabilities); Backends
nk_e4m3_to_f32serialnk_e5m2_to_f32serial
E4M3 has 1 sign bit, 4 exponent bits biased by 7, and 3 mantissa bits. It spans [-448, +448] with no infinities and only two NaN encodings, 0x7F and 0xFF. Subnormals decode to the value (-1)ˢ × mantissa × 2⁻⁹, which is mantissa / 512.
| Input | E4M3 Hex | F32 Hex | Description |
|---|---|---|---|
| +0 | 0x00 | 0x00000000 | Positive zero |
| -0 | 0x80 | 0x80000000 | Negative zero |
| +NaN | 0x7F | 0x7FC00000 | Quiet NaN, exp = 15, mant ≠ 0 |
| -NaN | 0xFF | 0xFFC00000 | Quiet NaN, signed |
| +448 (max) | 0x7E | 0x43E00000 | Max normal = 448 |
| -448 | 0xFE | 0xC3E00000 | Min normal = -448 |
| 1.0 | 0x38 | 0x3F800000 | Normal, exp = 7, mant = 0 |
| Min denorm | 0x01 | 0x3B000000 | 1/512 = 2⁻⁹ |
| Max denorm | 0x07 | 0x3BE00000 | 7/512 = 7 × 2⁻⁹ |
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- FP8 Formats for Deep Learning: https://arxiv.org/pdf/2209.05433
- OCP 8-bit Floating Point Specification: https://www.opencompute.org/documents/ocp-8-bit-floating-point-specification-ofp8-revision-1-0-2023-12-01-pdf-1
- ONNX Float8 types: https://onnx.ai/onnx/technical/float8.html
nk_*_to_f32_best× 2Scalar conversion from FP6 e2m3 to f32.
void nk_e2m3_to_f32_best(
nk_e2m3_t const *src,
nk_f32_t *dest,
nk_capability_t capabilities); Backends
nk_e2m3_to_f32serialnk_e3m2_to_f32serial
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
nk_f32_to_f16_bestScalar conversion from f32 to f16, rounding to nearest, for all IEEE 754 inputs.
void nk_f32_to_f16_best(
nk_f32_t const *src,
nk_f16_t *dest,
nk_capability_t capabilities); Backends
nk_f32_to_f16serialneonhaswellsapphirepowervsx
| Input | F32 Hex | F16 Hex | Description |
|---|---|---|---|
| +0 | 0x00000000 | 0x0000 | Positive zero |
| -0 | 0x80000000 | 0x8000 | Negative zero |
| +inf | 0x7F800000 | 0x7C00 | Positive infinity |
| -inf | 0xFF800000 | 0xFC00 | Negative infinity |
| NaN | 0x7FC00000 | 0x7E00 | Quiet NaN, payload truncated |
| 1.0 | 0x3F800000 | 0x3C00 | Normal number |
| 65504 | 0x477FE000 | 0x7BFF | Max f16 normal |
| 65520+ | >0x477FE000 | 0x7C00 | Overflow → infinity |
| 2⁻¹⁴ | 0x38800000 | 0x0400 | Min f16 normal |
| 2⁻²⁴ | 0x33800000 | 0x0001 | Min f16 denormal |
| <2⁻²⁵ | <0x33000000 | 0x0000 | Underflow → zero |
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- Stack Overflow on half-precision conversion: https://stackoverflow.com/a/60047308
- Half-float conversion gist: https://gist.github.com/milhidaka/95863906fe828198f47991c813dbe233
- Libcanard float16 codec: https://github.com/OpenCyphal/libcanard/blob/636795f4bc395f56af8d2c61d3757b5e762bb9e5/canard.c#L811-L834
nk_f32_to_bf16_bestScalar conversion from f32 to bf16.
void nk_f32_to_bf16_best(
nk_f32_t const *src,
nk_bf16_t *dest,
nk_capability_t capabilities); Backends
nk_f32_to_bf16serial
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- Stack Overflow on f32 and bf16 conversion: https://stackoverflow.com/questions/55253233/convert-fp32-to-bfloat16-in-c/55254307#55254307
- Bfloat16 on Cloud TPUs: https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus
nk_f32_to_*_best× 2Scalar conversion from f32 to FP8 e4m3, rounding to nearest even per IEEE 754 and the OCP FP8 specification.
void nk_f32_to_e4m3_best(
nk_f32_t const *src,
nk_e4m3_t *dest,
nk_capability_t capabilities); Backends
nk_f32_to_e4m3serialnk_f32_to_e5m2serial
E4M3 has 1 sign bit, 4 exponent bits biased by 7, and 3 mantissa bits. It spans [-448, +448] with no infinities and only two NaN encodings. Values with |x| < 2⁻⁶ are encoded as subnormals.
| Input | F32 Hex | E4M3 Hex | Description |
|---|---|---|---|
| +0 | 0x00000000 | 0x00 | Positive zero |
| -0 | 0x80000000 | 0x80 | Negative zero |
| +inf | 0x7F800000 | 0x7E | Saturates to max, +448 |
| -inf | 0xFF800000 | 0xFE | Saturates to min, -448 |
| NaN | 0x7FC00000 | 0x7F | Quiet NaN |
| 1.0 | 0x3F800000 | 0x38 | Normal, exp = 7, mant = 0 |
| 448+ | >0x43E00000 | 0x7E | Overflow → max |
| 2⁻⁶ | 0x3E800000 | 0x08 | Min normal |
| ≤2⁻¹⁰ | ≤0x3A800000 | 0x00 | Underflow → zero, RNE boundary |
E5M2 has 1 sign bit, 5 exponent bits biased by 15, and 2 mantissa bits. Its range is ±57344, and it keeps IEEE 754 infinities and NaNs. Values with |x| < 2⁻¹⁴ are encoded as subnormals.
| Input | F32 Hex | E5M2 Hex | Description |
|---|---|---|---|
| +0 | 0x00000000 | 0x00 | Positive zero |
| -0 | 0x80000000 | 0x80 | Negative zero |
| +inf | 0x7F800000 | 0x7C | Positive infinity |
| -inf | 0xFF800000 | 0xFC | Negative infinity |
| NaN | 0x7FC00000 | 0x7D | Quiet NaN |
| 1.0 | 0x3F800000 | 0x3C | Normal, exp = 15, mant = 0 |
| 57344+ | >0x47600000 | 0x7C | Overflow → infinity |
| 2⁻¹⁴ | 0x38800000 | 0x04 | Min normal |
| ≤2⁻¹⁷ | ≤0x37000000 | 0x00 | Underflow → zero, RNE boundary |
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
See also
- FP8 Formats for Deep Learning: https://arxiv.org/pdf/2209.05433
- OCP 8-bit Floating Point Specification: https://www.opencompute.org/documents/ocp-8-bit-floating-point-specification-ofp8-revision-1-0-2023-12-01-pdf-1
- ONNX Float8 types: https://onnx.ai/onnx/technical/float8.html
nk_f32_to_*_best× 2Scalar conversion from f32 to FP6 e2m3, rounding to nearest even per IEEE 754.
void nk_f32_to_e2m3_best(
nk_f32_t const *src,
nk_e2m3_t *dest,
nk_capability_t capabilities); Backends
nk_f32_to_e2m3serialnk_f32_to_e3m2serial
E2M3FN has 1 sign bit, 2 exponent bits biased by 1, and 3 mantissa bits. It spans [-7.5, +7.5] with no infinities or NaNs, and saturates to the maximum on overflow. Values with |x| < 0.5 are encoded as subnormals.
E3M2FN has 1 sign bit, 3 exponent bits biased by 3, and 2 mantissa bits. It spans [-28, +28] with no infinities or NaNs, and saturates to the maximum on overflow. Values with |x| < 0.25 are encoded as subnormals.
Parameters
src | in | The scalar to convert. |
|---|---|---|
dest | out | Receives the converted scalar. |
capabilities | in | The CPU's capabilities, like nk_cpu_capabilities_enabled reports; serial always stays. |
nk_e2m1x2_to_f32x2_serialUnpacks a byte of two E2M1 nibbles into two f32 values: the high nibble lands in dest[0] and the low nibble in dest[1], as in nk_i4x2_t and nk_u4x2_t.
void nk_e2m1x2_to_f32x2_serial(nk_e2m1x2_t const *src, nk_f32_t *dest); Backends
nk_e2m1x2_to_f32x2serial
nk_f32x2_to_e2m1x2_serialPacks two f32 values into one byte of two E2M1 nibbles: src[0] becomes the high nibble and src[1] the low one, as in nk_i4x2_t and nk_u4x2_t.
void nk_f32x2_to_e2m1x2_serial(nk_f32_t const *src, nk_e2m1x2_t *dest); Backends
nk_f32x2_to_e2m1x2serial
nk_ue8m0_to_f32_serialConverts a UE8M0 power-of-two scale byte, as used by OCP MX, to f32.
void nk_ue8m0_to_f32_serial(nk_ue8m0_t const *src, nk_f32_t *dest); Backends
nk_ue8m0_to_f32serial
A zero byte decodes to 0, 0xFF to NaN as the block-NaN sentinel, and any other v to 2^(v - 127).
nk_f32_to_ue8m0_serialConverts an f32 magnitude to a UE8M0 power-of-two scale byte.
void nk_f32_to_ue8m0_serial(nk_f32_t const *src, nk_ue8m0_t *dest); Backends
nk_f32_to_ue8m0serial
Rounds to the nearest power of two, ties to even in log2 space, per the OCP MX, NVIDIA and AMD convention. Plain ceil or floor biases the block's dynamic range, as floor underestimates it, so the split sits at the geometric midpoint √2 × 2^e. NaN maps to 0xFF as the block-NaN sentinel, zero and subnormals map to 0x00, and overflow saturates to 0xFE.
nk_ue4m3_to_f32_serialConverts a UE4M3 byte, the NVFP4 scale that is an E4M3 with its sign bit forced to 0, to f32.
void nk_ue4m3_to_f32_serial(nk_ue4m3_t const *src, nk_f32_t *dest); Backends
nk_ue4m3_to_f32serial
nk_f32_to_ue4m3_serialConverts an f32 magnitude to a UE4M3 NVFP4 scale byte.
void nk_f32_to_ue4m3_serial(nk_f32_t const *src, nk_ue4m3_t *dest); Backends
nk_f32_to_ue4m3serial
Takes the absolute value first, as the sign bit is not representable, then rounds to nearest even like the underlying E4M3 encoder, matching the NVFP4 and OCP scale convention. NaN maps to the E4M3 NaN code 0x7F.
nk_nvfp4_to_f32x16_serialDecode one NVFP4 block (16 elements) to f32.
void nk_nvfp4_to_f32x16_serial(
nk_nvfp4_t const *src,
nk_f32_t tensor_scale,
nk_f32_t *dest); Backends
nk_nvfp4_to_f32x16serial
tensor_scale is the per-tensor multiplier.
nk_f32x16_to_nvfp4_serialEncode 16 f32 values into one NVFP4 block, deriving a UE4M3 scale via per-block amax.
void nk_f32x16_to_nvfp4_serial(
nk_f32_t const *src,
nk_f32_t tensor_scale,
nk_nvfp4_t *dest); Backends
nk_f32x16_to_nvfp4serial
nk_block_scaled_elements_sizeNumber of element storage bytes needed for count logical elements of format.
nk_size_t nk_block_scaled_elements_size(
nk_size_t count,
nk_block_scaled_format_t format); nk_block_scaled_scales_sizeNumber of scale storage bytes needed for count logical elements of format.
nk_size_t nk_block_scaled_scales_size(
nk_size_t count,
nk_block_scaled_format_t format); nk_nvfp4{nk_e2m1_k, nk_ue4m3_k, nk_f32_k, 16, 8} — NVIDIA NVFP4 (Blackwell-native).
nk_block_scaled_format_t nk_nvfp4(void); nk_mxfp4{nk_e2m1_k, nk_ue8m0_k, unknown, 32, 16} — OCP MXFP4.
nk_block_scaled_format_t nk_mxfp4(void); nk_mxfp6e2m3{nk_e2m3_k, nk_ue8m0_k, unknown, 32, 32} — OCP MXFP6 (E2M3 variant).
nk_block_scaled_format_t nk_mxfp6e2m3(void); nk_mxfp6e3m2{nk_e3m2_k, nk_ue8m0_k, unknown, 32, 32} — OCP MXFP6 (E3M2 variant).
nk_block_scaled_format_t nk_mxfp6e3m2(void); nk_mxfp8e4m3{nk_e4m3_k, nk_ue8m0_k, unknown, 32, 32} — OCP MXFP8 (E4M3 variant).
nk_block_scaled_format_t nk_mxfp8e4m3(void); nk_mxfp8e5m2{nk_e5m2_k, nk_ue8m0_k, unknown, 32, 32} — OCP MXFP8 (E5M2 variant).
nk_block_scaled_format_t nk_mxfp8e5m2(void); nk_mxint8{nk_i8_k, nk_ue8m0_k, unknown, 32, 32} — OCP MXINT8.
nk_block_scaled_format_t nk_mxint8(void); nk_plain{element_dtype, unknown, unknown, 0, 0} — plain scalar buffer of element_dtype.
nk_block_scaled_format_t nk_plain(nk_dtype_t element_dtype); nk_block_scaled_format_of_dtypeBuild a block-scaled format descriptor from a composite dtype enum value.
nk_block_scaled_format_t nk_block_scaled_format_of_dtype(
nk_dtype_t dtype); Returns nk_plain(dtype) when dtype is not a composite.
nk_dtype_is_block_scaledTrue when dtype encodes a composite block-scaled format.
int nk_dtype_is_block_scaled(nk_dtype_t dtype); nk_dtype_elementExtracts the element dtype from a composite; returns dtype unchanged for plain inputs.
nk_dtype_t nk_dtype_element(nk_dtype_t dtype); nk_dtype_scaleExtracts the scale dtype from a composite; returns nk_dtype_unknown_k for plain inputs.
nk_dtype_t nk_dtype_scale(nk_dtype_t dtype); nk_dtype_block_sizeBlock size implied by a composite dtype; 0 for plain inputs.
nk_size_t nk_dtype_block_size(nk_dtype_t dtype); nk_dtype_familyClassifies the family of the dtype.
nk_dtype_family_t nk_dtype_family(nk_dtype_t dtype); nk_dtype_bitsReturns the number of bits in a single scalar of a given type.
nk_size_t nk_dtype_bits(nk_dtype_t dtype); nk_accumulation_error_boundReturns the rounding error each term may add to a sum kept in dtype, relative to the terms' magnitudes: |result − exact| ≤ (roundings + 1) · bound · Σ|terms|.
nk_f64_t nk_accumulation_error_bound(nk_dtype_t dtype); Floats get their unit roundoff with two bits of slack for matrix units that truncate; integer sums are exact. Kernel families derive their bounds from it, like nk_dot_error_bound.
nk_dtype_namedInverse of nk_dtype_name over an explicit-length string; nk_dtype_unknown_k for unrecognized names.
nk_dtype_t nk_dtype_named(char const *name, nk_size_t length); nk_dimensions_per_valueReturns how many logical dimensions are packed into one storage value.
nk_size_t nk_dimensions_per_value(nk_dtype_t dtype); For sub-byte types multiple dimensions share a single byte container. For byte-or-larger types this is always 1.
Macros
NUMKONG_F64_INFInfinities as an overflowing product, since C names them portably only in <math.h>.
#define NUMKONG_F64_INF ((nk_f64_t)(1e300 * 1e300)) nk_min_of_twoThe smaller of two values of any comparable type; each argument is evaluated twice.
#define nk_min_of_two(first, second) ((first) <(second) ? (first) : (second)) nk_max_of_twoThe larger of two values of any comparable type; each argument is evaluated twice.
#define nk_max_of_two(first, second) ((first) <(second) ? (second) : (first))