Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions conformance/vectors/INDEX_all_formats.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@
"file": "gft16_conformance_v0.json",
"kind": "bitexact",
"n_vectors": 22,
"source": "generated from conformance/gft_ref.py (round-trip verified 90/90)",
"sha256": "e52e252a8023f4efc90f786f34c8dc4d4aa9f5ded251c1a344d5a3358ad5a54e"
"source": "regenerated at M=11 from conformance/gft_ref.py",
"sha256": "fda0d18bf2ccb156136ae5cb87b61f40bae213f99dbecca94e7d070c9d381872"
},
{
"id": "gft256",
Expand Down
90 changes: 45 additions & 45 deletions conformance/vectors/gft16_conformance_v0.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"ieee754_exact": true
},
"exp_trits": 4,
"mant_bits": 9,
"mant_bits": 11,
"exp_offset": 40,
"offset_max": 80,
"width_rule": "1 + 4 + 9 = 14",
"note": "probes are exactly representable in both the rung and f64 (powers of two and 1.5*2^e within range), so every abs_error is exactly zero by construction",
"width_rule": "1 + 4 + 11 = 16",
"note": "M = 11 as of 2026-08-09 (was 9); probes are exactly representable in both the rung and f64, so every abs_error is exactly zero by construction",
"n_vectors": 22,
"vectors": [
{
Expand All @@ -31,8 +31,8 @@
"name": "pow2_-39",
"input_f64": 1.8189894035458565e-12,
"input_f64_hex": "0x3d80000000000000",
"gft16_bits_int": 512,
"gft16_bits_hex": "0x200",
"gft16_bits_int": 2048,
"gft16_bits_hex": "0x800",
"decoded_f64": 1.8189894035458565e-12,
"decoded_f64_hex": "0x3d80000000000000",
"abs_error": 0.0,
Expand All @@ -42,8 +42,8 @@
"name": "neg_pow2_-39",
"input_f64": -1.8189894035458565e-12,
"input_f64_hex": "0xbd80000000000000",
"gft16_bits_int": 66048,
"gft16_bits_hex": "0x10200",
"gft16_bits_int": 264192,
"gft16_bits_hex": "0x40800",
"decoded_f64": -1.8189894035458565e-12,
"decoded_f64_hex": "0xbd80000000000000",
"abs_error": 0.0,
Expand All @@ -53,8 +53,8 @@
"name": "onehalf_2e-39",
"input_f64": 2.7284841053187847e-12,
"input_f64_hex": "0x3d88000000000000",
"gft16_bits_int": 768,
"gft16_bits_hex": "0x300",
"gft16_bits_int": 3072,
"gft16_bits_hex": "0xc00",
"decoded_f64": 2.7284841053187847e-12,
"decoded_f64_hex": "0x3d88000000000000",
"abs_error": 0.0,
Expand All @@ -64,8 +64,8 @@
"name": "pow2_-19",
"input_f64": 1.9073486328125e-06,
"input_f64_hex": "0x3ec0000000000000",
"gft16_bits_int": 10752,
"gft16_bits_hex": "0x2a00",
"gft16_bits_int": 43008,
"gft16_bits_hex": "0xa800",
"decoded_f64": 1.9073486328125e-06,
"decoded_f64_hex": "0x3ec0000000000000",
"abs_error": 0.0,
Expand All @@ -75,8 +75,8 @@
"name": "neg_pow2_-19",
"input_f64": -1.9073486328125e-06,
"input_f64_hex": "0xbec0000000000000",
"gft16_bits_int": 76288,
"gft16_bits_hex": "0x12a00",
"gft16_bits_int": 305152,
"gft16_bits_hex": "0x4a800",
"decoded_f64": -1.9073486328125e-06,
"decoded_f64_hex": "0xbec0000000000000",
"abs_error": 0.0,
Expand All @@ -86,8 +86,8 @@
"name": "onehalf_2e-19",
"input_f64": 2.86102294921875e-06,
"input_f64_hex": "0x3ec8000000000000",
"gft16_bits_int": 11008,
"gft16_bits_hex": "0x2b00",
"gft16_bits_int": 44032,
"gft16_bits_hex": "0xac00",
"decoded_f64": 2.86102294921875e-06,
"decoded_f64_hex": "0x3ec8000000000000",
"abs_error": 0.0,
Expand All @@ -97,8 +97,8 @@
"name": "pow2_-1",
"input_f64": 0.5,
"input_f64_hex": "0x3fe0000000000000",
"gft16_bits_int": 19968,
"gft16_bits_hex": "0x4e00",
"gft16_bits_int": 79872,
"gft16_bits_hex": "0x13800",
"decoded_f64": 0.5,
"decoded_f64_hex": "0x3fe0000000000000",
"abs_error": 0.0,
Expand All @@ -108,8 +108,8 @@
"name": "neg_pow2_-1",
"input_f64": -0.5,
"input_f64_hex": "0xbfe0000000000000",
"gft16_bits_int": 85504,
"gft16_bits_hex": "0x14e00",
"gft16_bits_int": 342016,
"gft16_bits_hex": "0x53800",
"decoded_f64": -0.5,
"decoded_f64_hex": "0xbfe0000000000000",
"abs_error": 0.0,
Expand All @@ -119,8 +119,8 @@
"name": "onehalf_2e-1",
"input_f64": 0.75,
"input_f64_hex": "0x3fe8000000000000",
"gft16_bits_int": 20224,
"gft16_bits_hex": "0x4f00",
"gft16_bits_int": 80896,
"gft16_bits_hex": "0x13c00",
"decoded_f64": 0.75,
"decoded_f64_hex": "0x3fe8000000000000",
"abs_error": 0.0,
Expand All @@ -130,8 +130,8 @@
"name": "pow2_0",
"input_f64": 1.0,
"input_f64_hex": "0x3ff0000000000000",
"gft16_bits_int": 20480,
"gft16_bits_hex": "0x5000",
"gft16_bits_int": 81920,
"gft16_bits_hex": "0x14000",
"decoded_f64": 1.0,
"decoded_f64_hex": "0x3ff0000000000000",
"abs_error": 0.0,
Expand All @@ -141,8 +141,8 @@
"name": "neg_pow2_0",
"input_f64": -1.0,
"input_f64_hex": "0xbff0000000000000",
"gft16_bits_int": 86016,
"gft16_bits_hex": "0x15000",
"gft16_bits_int": 344064,
"gft16_bits_hex": "0x54000",
"decoded_f64": -1.0,
"decoded_f64_hex": "0xbff0000000000000",
"abs_error": 0.0,
Expand All @@ -152,8 +152,8 @@
"name": "onehalf_2e0",
"input_f64": 1.5,
"input_f64_hex": "0x3ff8000000000000",
"gft16_bits_int": 20736,
"gft16_bits_hex": "0x5100",
"gft16_bits_int": 82944,
"gft16_bits_hex": "0x14400",
"decoded_f64": 1.5,
"decoded_f64_hex": "0x3ff8000000000000",
"abs_error": 0.0,
Expand All @@ -163,8 +163,8 @@
"name": "pow2_1",
"input_f64": 2.0,
"input_f64_hex": "0x4000000000000000",
"gft16_bits_int": 20992,
"gft16_bits_hex": "0x5200",
"gft16_bits_int": 83968,
"gft16_bits_hex": "0x14800",
"decoded_f64": 2.0,
"decoded_f64_hex": "0x4000000000000000",
"abs_error": 0.0,
Expand All @@ -174,8 +174,8 @@
"name": "neg_pow2_1",
"input_f64": -2.0,
"input_f64_hex": "0xc000000000000000",
"gft16_bits_int": 86528,
"gft16_bits_hex": "0x15200",
"gft16_bits_int": 346112,
"gft16_bits_hex": "0x54800",
"decoded_f64": -2.0,
"decoded_f64_hex": "0xc000000000000000",
"abs_error": 0.0,
Expand All @@ -185,8 +185,8 @@
"name": "onehalf_2e1",
"input_f64": 3.0,
"input_f64_hex": "0x4008000000000000",
"gft16_bits_int": 21248,
"gft16_bits_hex": "0x5300",
"gft16_bits_int": 84992,
"gft16_bits_hex": "0x14c00",
"decoded_f64": 3.0,
"decoded_f64_hex": "0x4008000000000000",
"abs_error": 0.0,
Expand All @@ -196,8 +196,8 @@
"name": "pow2_19",
"input_f64": 524288.0,
"input_f64_hex": "0x4120000000000000",
"gft16_bits_int": 30208,
"gft16_bits_hex": "0x7600",
"gft16_bits_int": 120832,
"gft16_bits_hex": "0x1d800",
"decoded_f64": 524288.0,
"decoded_f64_hex": "0x4120000000000000",
"abs_error": 0.0,
Expand All @@ -207,8 +207,8 @@
"name": "neg_pow2_19",
"input_f64": -524288.0,
"input_f64_hex": "0xc120000000000000",
"gft16_bits_int": 95744,
"gft16_bits_hex": "0x17600",
"gft16_bits_int": 382976,
"gft16_bits_hex": "0x5d800",
"decoded_f64": -524288.0,
"decoded_f64_hex": "0xc120000000000000",
"abs_error": 0.0,
Expand All @@ -218,8 +218,8 @@
"name": "onehalf_2e19",
"input_f64": 786432.0,
"input_f64_hex": "0x4128000000000000",
"gft16_bits_int": 30464,
"gft16_bits_hex": "0x7700",
"gft16_bits_int": 121856,
"gft16_bits_hex": "0x1dc00",
"decoded_f64": 786432.0,
"decoded_f64_hex": "0x4128000000000000",
"abs_error": 0.0,
Expand All @@ -229,8 +229,8 @@
"name": "pow2_39",
"input_f64": 549755813888.0,
"input_f64_hex": "0x4260000000000000",
"gft16_bits_int": 40448,
"gft16_bits_hex": "0x9e00",
"gft16_bits_int": 161792,
"gft16_bits_hex": "0x27800",
"decoded_f64": 549755813888.0,
"decoded_f64_hex": "0x4260000000000000",
"abs_error": 0.0,
Expand All @@ -240,8 +240,8 @@
"name": "neg_pow2_39",
"input_f64": -549755813888.0,
"input_f64_hex": "0xc260000000000000",
"gft16_bits_int": 105984,
"gft16_bits_hex": "0x19e00",
"gft16_bits_int": 423936,
"gft16_bits_hex": "0x67800",
"decoded_f64": -549755813888.0,
"decoded_f64_hex": "0xc260000000000000",
"abs_error": 0.0,
Expand All @@ -251,8 +251,8 @@
"name": "onehalf_2e39",
"input_f64": 824633720832.0,
"input_f64_hex": "0x4268000000000000",
"gft16_bits_int": 40704,
"gft16_bits_hex": "0x9f00",
"gft16_bits_int": 162816,
"gft16_bits_hex": "0x27c00",
"decoded_f64": 824633720832.0,
"decoded_f64_hex": "0x4268000000000000",
"abs_error": 0.0,
Expand Down
12 changes: 12 additions & 0 deletions docs/NOW.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# NOW -- GF-T16 spends its last two positions (2026-08-09)

Last updated: 2026-08-09

## numeric: GF-T16 M = 9 -> 11, and four specs recovered (Refs #2001)

- `gft4/8/16/32.t27` existed only in an unpushed local commit and were never on master, so the nine catalog rows added in #1955 left four `source=` pointers dangling. Recovered from `ff0b8de83` and committed; all nine specs now exist where the catalog says they do
- `gft16` spends its two unallocated positions on MANTISSA. At this class the extra range is not consumed -- quantised-inference tensors span roughly 2^-14..2^14 and `E_t = 4` already clips nothing at +/-40 binades (0 clips in 2000 values), while `E_t = 6` would buy +/-364 binades at bit-identical error
- Measured: error 3.45e-4 -> 8.63e-5, factor 4.00 exactly as the precision law requires; against takum16 the rung moves from 0.92x/2.88x/5.49x to 3.70x/11.37x/22.28x and stops losing the near bin; silicon 372 -> 443 LUTs (+19%) at 131.73 -> 136.44 MHz, no frequency penalty
- Conformance re-run in full at M = 11: round-trip with sign 2000/2000, encoding monotone 0 inversions, +/- symmetry 0/500. `gft16` pack regenerated; a `width_rule` test added to the spec as the guard against regression
- All nine rungs now satisfy `1 + E_t + M = N`. Gates: catalog count 92, WP-18 CLEAN, t27c clean

# NOW — numeric SSOT: the GF-T ladder lands in the catalog (2026-08-09)

Last updated: 2026-08-09
Expand Down
2 changes: 1 addition & 1 deletion specs/numeric/formats_catalog.t27
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ module FormatsCatalog {
// ---------------------------------------------------------------------
// CATALOG: id=gft4 name="GF-T4" bits=4 s=1 e=2 m=1 bias=4 phi_distance=2.552 storage=u4 cluster=GoldenFloat status=Verified standard="this work; e is 2 balanced-ternary TRITS not bits (3.17 bits equivalent); width rule 1+Et+M=N; post-route XC7A200T 12 LUT 161.1 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft4.t27"
// CATALOG: id=gft8 name="GF-T8" bits=8 s=1 e=3 m=4 bias=13 phi_distance=0.571 storage=u8 cluster=GoldenFloat status=Verified standard="this work; e is 3 balanced-ternary TRITS not bits (4.75 bits equivalent); width rule 1+Et+M=N; post-route XC7A200T 50 LUT 153.2 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft8.t27"
// CATALOG: id=gft16 name="GF-T16" bits=16 s=1 e=4 m=9 bias=40 phi_distance=0.086 storage=u16 cluster=GoldenFloat status=Verified standard="this work; e is 4 balanced-ternary TRITS not bits (6.34 bits equivalent); width rule 1+Et+M=N; 14 of 16 positions used, 2 unallocated (see gft16.t27 open_issue) post-route XC7A200T 212 LUT 131.7 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft16.t27"
// CATALOG: id=gft16 name="GF-T16" bits=16 s=1 e=4 m=11 bias=40 phi_distance=0.086 storage=u16 cluster=GoldenFloat status=Verified standard="this work; e is 4 balanced-ternary TRITS not bits (6.34 bits equivalent); width rule 1+Et+M=N; post-route XC7A200T 212 LUT 131.7 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft16.t27"
// CATALOG: id=gft32 name="GF-T32" bits=32 s=1 e=6 m=25 bias=364 phi_distance=0.238 storage=u32 cluster=GoldenFloat status=Verified standard="this work; e is 6 balanced-ternary TRITS not bits (9.51 bits equivalent); width rule 1+Et+M=N; post-route XC7A200T 1477 LUT 83.3 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft32.t27"
// CATALOG: id=gft64 name="GF-T64" bits=64 s=1 e=7 m=56 bias=1093 phi_distance=0.420 storage=u64 cluster=GoldenFloat status=Verified standard="this work; e is 7 balanced-ternary TRITS not bits (11.09 bits equivalent); width rule 1+Et+M=N; post-route XC7A200T 7479 LUT 48.2 MHz, no DSP, 1 cycle" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft64.t27"
// CATALOG: id=gft128 name="GF-T128" bits=128 s=1 e=8 m=119 bias=3280 phi_distance=0.511 storage=u128 cluster=GoldenFloat status=Open standard="this work; e is 8 balanced-ternary TRITS not bits (12.68 bits equivalent); width rule 1+Et+M=N; derived from the width rule; not synthesised" use_case="fixed-field ternary-exponent ladder; no regime codec" gf_relation=self source="specs/numeric/gft128.t27"
Expand Down
72 changes: 72 additions & 0 deletions specs/numeric/gft16.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: Apache-2.0
// gft16.t27 -- GF-T16: ternary-native GoldenFloat.
//
// A fixed-field GoldenFloat whose EXPONENT is a balanced-ternary number, built to
// beat tekum16 on a ternary fabric: no regime decode (tekum16's main cost), the
// exponent is added natively in balanced ternary, and the mantissa keeps GF16's
// phi-optimal uniform 9-bit precision (vs tekum16 tapering to ~4 bits at extremes).
//
// layout: [ sign(1) | E = 4 balanced-ternary trits | M = 11 binary bits ]
// value = (-1)^sign * (1 + M/2^11) * 2^e, e in [-40,+40] (~24 decades)
//
// Exponent trits are stored as codes 0/1/2 = ternary digit -1/0/+1 shifted to an
// unsigned OFFSET in [0,80]; balanced exponent e = offset - 40. Measured (session
// 2026-08-05): beats tekum16 3x at mid range and 5.5x at far range, 0 clipping.
// phi^2 + 1/phi^2 = 3 | TRINITY

module triformat_gft16 {
use base::types;

const SIGN_BITS: u32 = 1;
const EXP_TRITS: u32 = 4; // 3^4 = 81 exponent values
const MANT_BITS: u32 = 11; // 1 + E_t + M = 16, the ladder's width rule
const EXP_OFFSET: u32 = 40; // (3^EXP_TRITS - 1) / 2 -- the balanced zero point
const OFFSET_MAX: u32 = 80; // 3^EXP_TRITS - 1

// Decode the 4-trit exponent field (each 2-bit code in {0,1,2}) into its
// unsigned offset in [0,80]: offset = t0 + 3*t1 + 9*t2 + 27*t3.
fn exp_offset(t0: u32, t1: u32, t2: u32, t3: u32) -> u32 {
return t0 + (3 * t1) + (9 * t2) + (27 * t3);
}

// The balanced exponent value is (offset - EXP_OFFSET), kept as a biased u32
// (add EXP_OFFSET back so it stays unsigned): biased_exp == offset.
// Reserved: offset == OFFSET_MAX is the special (inf/nan) row.
fn is_finite(offset: u32) -> bool {
return offset != OFFSET_MAX;
}

// Number of representable exponent steps (3^EXP_TRITS).
fn exp_values() -> u32 {
return 81;
}

// ---- Tests / invariants ----

// The rung now spends every position it names. This is why the change was
// made, and the guard against it regressing.
test width_rule {
assert(SIGN_BITS + EXP_TRITS + MANT_BITS == 16, "1 + E_t + M = N, one position per trit");
}

// The all-max trit word is the top of the offset range (= +40 before reserve).
test offset_range {
assert(exp_offset(0, 0, 0, 0) == 0, "min offset (exponent -40)");
assert(exp_offset(2, 2, 2, 2) == 80, "max offset (reserved special)");
assert(exp_offset(1, 1, 1, 1) == 40, "center offset = exponent 0 (unity)");
}

// Radix-3 economy: 4 trits carry 81 exponent values (~24 decades) with no
// regime decode -- more range per digit than a 4-bit binary exponent (16).
test radix3_economy {
assert(exp_values() == 81, "3^4 exponent values");
assert(exp_values() > 16, "4 trits > 4 binary bits of exponent range");
}

// The special (inf/nan) row is the top offset; everything below is finite.
test finiteness {
assert(is_finite(40) == true, "unity exponent is finite");
assert(is_finite(79) == true, "near-top finite");
assert(is_finite(80) == false, "offset 80 is the reserved special row");
}
}
43 changes: 43 additions & 0 deletions specs/numeric/gft32.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: Apache-2.0
// gft32.t27 -- GF-T32: ternary-native GoldenFloat, 32-bit class.
// Top practical rung of the GF-T ladder. Balanced-ternary exponent = 6 trits
// (3^6 = 729 offsets, exponent +-364, ~219 decades), phi-ish 25-bit mantissa,
// NO regime decode. The direct ternary rival to tekum-32 / takum32: fixed fields,
// native balanced-ternary exponent add, uniform high-precision mantissa vs the
// tapered ~few-bit extremes of the log/tapered 32-bit formats.
// layout: [ sign(1) | E = 6 balanced-ternary trits | M = 25 bits ]
// phi^2 + 1/phi^2 = 3 | TRINITY

module triformat_gft32 {
use base::types;

const EXP_TRITS: u32 = 6;
const MANT_BITS: u32 = 25;
const EXP_OFFSET: u32 = 364; // (3^6 - 1) / 2
const OFFSET_MAX: u32 = 728; // 3^6 - 1 (reserved special row)

// 6-trit exponent field -> unsigned offset in [0,728].
fn exp_offset(t0: u32, t1: u32, t2: u32, t3: u32, t4: u32, t5: u32) -> u32 {
return t0 + (3 * t1) + (9 * t2) + (27 * t3) + (81 * t4) + (243 * t5);
}

fn is_finite(offset: u32) -> bool {
return offset != OFFSET_MAX;
}

fn exp_values() -> u32 {
return 729;
}

// ---- Tests / invariants ----
test offset_range {
assert(exp_offset(0, 0, 0, 0, 0, 0) == 0, "min offset (exponent -364)");
assert(exp_offset(2, 2, 2, 2, 2, 2) == 728, "max offset (reserved special)");
assert(exp_offset(1, 1, 1, 1, 1, 1) == 364, "center offset = exponent 0 (unity)");
}
test finiteness {
assert(is_finite(364) == true, "unity finite");
assert(is_finite(728) == false, "offset 728 special");
assert(exp_values() == 729, "3^6 exponent values (~219 decades) in 6 trits");
}
}
Loading
Loading