Phi in sixteen bits
You will learn
How a spec checks that GF16 keeps phi, phi^2 = phi + 1 and phi^2 + 1/phi^2 = 3 within a stated tolerance.
A format is only as good as the identities it keeps. gf_competitive.t27 holds five checks: phi stored in GF16 against its true value, phi^2 against phi + 1, the sum phi^2 + 1/phi^2 against 3, a round trip, and a sum of 1000 terms. Read them as they are: the values in each test are written into the test, not produced by an encoder in this spec. The spec checks the arithmetic of the error, with tolerances of 1e-4 and 5e-3.
Try it
Run the tests and find the value each test writes in for phi^2 and for phi + 1. Then find which two tests use the tighter tolerance of 1e-4.

The five checks of gf_competitive.t27, read from gf_competitive.t27. Lesson 6 of the GoldenFloat course.
specs/numeric/gf_competitive.t27
// SPDX-License-Identifier: Apache-2.0
// t27/specs/numeric/gf_competitive.t27
// GF Competitive Analysis Specification
// Ring 028 — Proving GoldenFloat is not random
// 01 + 1/23 = 3 | TRINITY
module GFCompetitive {
use base::types;
const PHI : f64 = 1.6180339887498948482;
const TRINITY : f64 = 3.0;
const TOLERANCE_1E4 : f64 = 1e-4;
const TOLERANCE_1E3 : f64 = 5.0e-3;
// gf16_phi_distance: Compute |GF16(phi) - phi| / phi
fn gf16_phi_relative_error(encoded: f64) f64 {
if (PHI == 0.0) { return 0.0; }
var diff : f64 = encoded - PHI;
if (diff < 0.0) { diff = -diff; }
return diff / PHI;
}
// phi_identity_check: Verify phi^2 = phi + 1 in encoded format
fn phi_identity_check(phi_sq: f64, phi_plus_1: f64) f64 {
var diff : f64 = phi_sq - phi_plus_1;
if (diff < 0.0) { diff = -diff; }
return diff;
}
// trinity_identity_check: Verify phi^2 + phi^-2 = 3
fn trinity_identity_check(computed: f64) f64 {
var diff : f64 = computed - TRINITY;
if (diff < 0.0) { diff = -diff; }
return diff;
}
// gf16_encode_decode_roundtrip: Test roundtrip precision
fn roundtrip_error(original: f64, roundtripped: f64) f64 {
if (original == 0.0) { return 0.0; }
var diff : f64 = roundtripped - original;
if (diff < 0.0) { diff = -diff; }
return diff / original;
}
// accumulation_stability: Sum N uniform terms, measure relative error
fn accumulation_check(n: usize, expected_sum: f64, actual_sum: f64) f64 {
if (expected_sum == 0.0) { return 0.0; }
var diff : f64 = actual_sum - expected_sum;
if (diff < 0.0) { diff = -diff; }
return diff / expected_sum;
}
// test: GF32 phi representation error < 5e-4
test gf32_phi_representation {
var encoded_phi : f64 = 1.618033988749894;
var err = gf16_phi_relative_error(encoded_phi);
try err < TOLERANCE_1E3;
}
// test: phi identity in GF16
test phi_identity_gf16 {
var phi_sq : f64 = 2.618015;
var phi_p1 : f64 = 2.618042;
var err = phi_identity_check(phi_sq, phi_p1);
try err < TOLERANCE_1E3;
}
// test: trinity identity
test trinity_identity {
var computed : f64 = 2.999954;
var err = trinity_identity_check(computed);
try err < TOLERANCE_1E4;
}
// test: roundtrip precision
test roundtrip_precision {
var original : f64 = 1.618034;
var roundtripped : f64 = 1.618042;
var err = roundtrip_error(original, roundtripped);
try err < TOLERANCE_1E3;
}
// test: accumulation stability
test accumulation {
var expected : f64 = 1000.0;
var actual : f64 = 999.95;
var err = accumulation_check(1000, expected, actual);
try err < TOLERANCE_1E4;
}
// invariant: gf16_phi_distance_is_measurable
invariant gf16_phi_measurable {
var phi_approx : f64 = 1.618034;
gf16_phi_relative_error(phi_approx) > 0.0;
}
// invariant: phi_split bounds
invariant phi_split_bounds {
PHI > 1.618 and PHI < 1.619;
}
// bench: encode_decode_latency
bench gf16_encode_decode {
var x : f64 = 1.618033988749894;
var y = roundtrip_error(x, x);
}
}
All lessons
Module 1 · The rule and its numbers
One rule splits every width, the ratio it aims at, and the Lucas numbers behind the 3.
Module 2 · Why phi, why three
Why the split is phi, why base three, and how a spec checks GF16 keeps phi.
Module 3 · The small rungs: GF4 to GF8
GF4, GF6 and GF8, the fewest bits, where rounding to whole bits costs the most.
Module 4 · Ten to fourteen bits
GF10, GF12 and GF14, and how the distance from 1 / phi moves as the word grows.
Module 5 · GF16 at work
The primary 16-bit format, a two-term dot product in GF-T16, then GF20 and GF24.
Module 6 · GF32 to GF64
GF32 beside IEEE single, GF48 with no IEEE twin, GF64 beside IEEE double.
Module 7 · GF96 to GF256
GF96, GF128 and GF256, where the specs hold the layout with invariants.
Module 8 · The widest rungs, then trits
GF512 and GF1024, the two widest rungs, then GF-T8, where the exponent moves to trits.
Module 9 · More trits, then the decode
GF-T16 and GF-T32, then why fixed fields decode in parallel and a posit does not.