Skip to content

fix(gf16): reconcile production codec to standard (1+M/512), reclaim wasted mantissa bit - #94

Merged
gHashTag merged 2 commits into
mainfrom
claude/bold-austin-cf6ee3
Aug 7, 2026
Merged

fix(gf16): reconcile production codec to standard (1+M/512), reclaim wasted mantissa bit#94
gHashTag merged 2 commits into
mainfrom
claude/bold-austin-cf6ee3

Conversation

@gHashTag

@gHashTag gHashTag commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

The exported production GF16 codec (golden_float16.GF16, used by every gf16_* C-ABI binding) wasted a mantissa bit and diverged from every other GF16 encoding in the repo. This reconciles it to the standard (1 + M/512)·2^(E−31) form used by the spec-of-record, docs, and the gf_binary ladder — so there is exactly one GF16 codec.

The bug (confirmed with exact-bit tests)

golden_float16.GF16.fromF32 normalized to [0.5, 1.0) and stored (mant_f − 0.5)·512. Across a ~4,000-value sweep the 9-bit mantissa field never exceeded 255 — the top half (256–511) was dead → 8 effective mantissa bits, not 9.

It also produced different raw bits than everything else for the same value:

value old golden_float16 standard (gf_binary, spec, docs)
1.0 0x4000 0x3E00
1.5 0x4080 0x3F00
3.14159 0x4292 0x4124

The standard form was already used by specs/gf16.tri (from_f32_steps), docs/spec-gf16.md, gf_binary.GF16, and formats_root.f32ToGf16. Only golden_float16 and specs/ops.tri used the wasteful form — an internal spec contradiction. The gf16.tri test_vectors were separately bogus (IEEE-f16 hex, wrong under either convention).

Decision

Owner chose to fix to the standard (1 + M/512) normalization (vs. keeping the old wire format and documenting two encodings).

Changes

  • src/formats/golden_float16.zigGF16.fromF32/toF32 delegate to gf_binary.GF16; one codec, bit-identical by construction. Added an exact-bit test + a golden_float16 ≡ gf_binary reconciliation test.
  • testdata/gf_conformance.csv — added gf16 rows (previously excluded); the generic cross-language reader now pins them for Python/Rust/C++.
  • src/formats/gf_binary.zig — added gf16 to the exact-bit encoding-regression guard (it skipped gf16 before because the codec diverged).
  • specs/ops.tri0.5+M/5121+M/512 (and normalize range) to match specs/gf16.tri.
  • specs/gf16.tri — fixed the IEEE-f16 copy-paste test_vectors to correct [1:6:9] bits.
  • src/c/gf16.h — fixed the documented value formula.
  • specs/TRI-HASHES.md — resealed gf16.tri / ops.tri hashes (via shasum).

Reviewer notes

⚠️ Wire-format change: gf16_* now emits standard bits (1.0: 0x4000 → 0x3E00). No FPGA RTL exists in-repo and the FPGA docs already describe [1:6:9] b31, so this aligns the codec with the documented hardware convention rather than departing from it — but any serialized gf16 data matching the old output is incompatible and warrants a format-version bump on release.

ℹ️ Follow-up (not in this PR): tools/gen/check_tri_hashes.zig — the tool CLAUDE.md mandates for resealing — does not compile (JS-style destructuring + stale Zig APIs) and targets the wrong file. Hashes were resealed by hand via shasum (verified the table is plain shasum -a 256). A separate task tracks rewriting it.

Verification

  • zig build and zig build test pass (exit 0).
  • Freshly built libgoldenfloat.dylib emits every gf16 conformance row exactly (checked via ctypes).
  • zig fmt clean; TRI hashes recomputed and matched.

🤖 Generated with Claude Code

SSD DDD and others added 2 commits August 8, 2026 02:26
…mantissa bit

golden_float16.GF16 (the production gf16_* C-ABI codec used by every language
binding + FPGA path) normalized to [0.5, 1.0) and stored (mant_f - 0.5)*512, so
the top half of the 9-bit mantissa field (256..511) was never produced — ~8
effective mantissa bits instead of 9. It also diverged from every other GF16 in
the repo (1.0 -> 0x4000 vs the standard 0x3E00): specs/gf16.tri from_f32_steps,
docs/spec-gf16.md, gf_binary.GF16, and formats_root.f32ToGf16 all use the
standard implicit-leading-1 form. specs/ops.tri was the only spec agreeing with
the wasteful form, contradicting specs/gf16.tri.

Owner decision: fix to the standard (1 + M/512)·2^(E-31) normalization.

- golden_float16.GF16.fromF32/toF32 now delegate to gf_binary.GF16 — one codec,
  bit-identical by construction (guards against future re-drift).
- Add gf16 exact-bit vectors to testdata/gf_conformance.csv (was excluded) and
  to gf_binary's encoding-regression guard; add reconciliation + exact-bit tests
  in golden_float16.zig.
- Fix specs/ops.tri (0.5+M/512 -> 1+M/512) to match specs/gf16.tri; fix the
  bogus IEEE-f16 copy-paste test_vectors in gf16.tri; fix the value formula in
  src/c/gf16.h.
- Reseal specs/TRI-HASHES.md for gf16.tri and ops.tri (shasum).

WIRE FORMAT CHANGE: gf16_* now emits standard bits (1.0: 0x4000 -> 0x3E00).
No RTL exists in-repo and FPGA docs already describe [1:6:9] b31, so this aligns
the codec with the documented hardware convention. Serialized gf16 data matching
the old output is incompatible — warrants a format-version bump on release.

Verified: zig build + zig build test pass; the built libgoldenfloat.dylib emits
every gf16 CSV row exactly via ctypes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…6ee3

# Conflicts:
#	testdata/gf_conformance.csv
@gHashTag
gHashTag merged commit 760895f into main Aug 7, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant