Skip to content
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