Files
skills/docs/foundation/flow/cbor/src/encoder/half-float.md
2026-05-29 08:20:56 +01:00

2.3 KiB

half-float (encoder side)

Purpose

Encodes a JavaScript number as IEEE 754 binary16 (CBOR major 7 / value 25) when the round-trip is exact, and otherwise indicates non-representability so the caller can pick a wider format. Also exports selectFloatWidth, which chooses between float32 and float64 based on exact-representability — the encoder's deterministic path uses this to skip half-float without giving up shortest-exact behaviour at the float32 / float64 boundary.

Features

  • Full IEEE 754 binary16 coverage: ±0, ±Infinity, NaN, normal values, subnormals, smallest-normal / largest-normal boundaries.
  • tryEncodeFloat16(value) returns the 2-byte big-endian sequence on exact round-trip; returns undefined on overflow / underflow / inexact-precision.
  • selectFloatWidth(value) picks float32 (4 bytes) when getFloat32 round- trips the value exactly, otherwise float64 (8 bytes). NaN is treated as float32-exact since both float32 and float64 represent NaN.

Usage: Basic Example

import { tryEncodeFloat16 } from "@suaveplan/cbor/encoder";

const bytes = tryEncodeFloat16(1.5); // Uint8Array(2) [0x3e, 0x00]

Usage: Advanced Example

import { selectFloatWidth, tryEncodeFloat16 } from "@suaveplan/cbor/encoder";

function pickFloat(value: number): { tag: number; bytes: Uint8Array } {
  const f16 = tryEncodeFloat16(value);
  if (f16) return { tag: 0xf9, bytes: f16 };
  const { width, bytes } = selectFloatWidth(value);
  return { tag: width === 4 ? 0xfa : 0xfb, bytes };
}

API Reference

  • tryEncodeFloat16(value: number): Uint8Array | undefined — exact-only.
  • selectFloatWidth(value: number): { width: 4 | 8; bytes: Uint8Array }.
  • type FloatWidth = 4 | 8.

Implementation Notes

The exact-only contract is critical for deterministic encoding: a lossy half-float emission would produce different bytes for inputs that look "close" but differ in the last bit of the mantissa. The implementation verifies round-trip via reconstruction ((1 + mant/1024) * 2^(exp-15) for normals, mant * 2^-24 for subnormals) and rejects when the rebuild does not equal the input under ===. NaN is hard-coded to 7e00 (the canonical quiet-NaN form) — RFC 8949 §3.3 explicitly permits losing NaN payload bits, which JavaScript would do anyway since Number collapses payloads.