t27.aiРусский

GF64: a double

You will learn

The 64-bit GoldenFloat, 1 + 24 + 39, beside IEEE double, and how its encoder clamps the exponent.

GF64 has 64 bits: 1 sign, 24 exponent, 39 mantissa, bias 8388607. IEEE double spends 11 bits on the exponent and 52 on the mantissa; GF64 trades mantissa for a far wider range. Its spec has an encoder and a decoder: the mantissa divides by 2^39, and the exponent is clamped between 0 and 2^24 - 1.

Try it

Find EXP_BIAS, EXP_MAX and MANT_DIV in gf64.t27. Then open encode and find where the exponent is clamped.

Open the interactive lesson →

GoldenFloat 18: GF64, a double
GoldenFloat 18: GF64, a double ↗

GF64: 64 bits as the spec lays them out, read from gf64.t27. Lesson 18 of the GoldenFloat course.

specs/numeric/gf64.t27

// SPDX-License-Identifier: Apache-2.0
// t27/specs/numeric/gf64.t27
// GoldenFloat64 — 64-bit phi-structured floating point
// NUMERIC-STANDARD-001 — canonical double-precision member of the GoldenFloat family

module GF64 {
    // Import base format family + phi-ratio design rule
    use numeric::goldenfloat_family;
    use numeric::phi_ratio;

    // 1. Format Definition
    // GF64 bit layout: [S(1) | E(24) | M(39)]
    //   S: 1 bit  (sign)
    //   E: 24 bits (exponent)
    //   M: 39 bits (mantissa)
    // Split chosen by the family rule E/M -> 1/phi: 24/39 = 0.6154 (closest
    // split to 1/phi on the whole ladder; phi_distance = 0.00265).

    const BITS : u8 = 64;
    const SIGN_BITS : u8 = 1;
    const EXP_BITS : u8 = 24;
    const MANT_BITS : u8 = 39;

    // Bias for exponent: 2^(24-1) - 1 = 8388607
    const EXP_BIAS : u32 = 8388607;

    // phi-rounding bias (empirical per format, H_E; see docs/NUMERIC_FORMATS_SSOT.md).
    // For GF64 this equals EXP_MAX - BIAS = 16777215 - 8388607 = 8388608 = 2^23.
    const PHI_BIAS : u32 = 8388608;

    // phi-ratio: exp/mant = 24/39 ~ 0.6154 (phi_distance = 0.00265 — best on the ladder)
    const PHI_DISTANCE : f64 = 0.0026493553478736;

    // Derived masks
    const EXP_MAX  : u32 = 16777215;            // 2^24 - 1
    const MANT_DIV : f64 = 549755813888.0;      // 2^39
    const MANT_MASK : u64 = 549755813887;       // 2^39 - 1
    const EXP_FIELD_MASK : u64 = 16777215;      // (1<<24) - 1

    // 2. GoldenFloat64 Type
    struct GF64 {
        raw : u64,  // 64-bit raw value: [sign:1][exp:24][mant:39]
    }

    // 3. Encoding / Decoding
    fn encode(value: f64) -> GF64 {
        if (value == 0.0) {
            return GF64{ raw = 0 };
        }
        const sign = if (value < 0.0) { 1u64 } else { 0u64 };
        const abs_val = if (value < 0.0) { -value } else { value };

        const exp_unbiased = floor_log2(abs_val) as i32;
        const exp_biased = (exp_unbiased + EXP_BIAS as i32) as u32;
        const exp_clamped = clamp_u32(exp_biased, 0, EXP_MAX);

        const mant = extract_mantissa(abs_val, exp_unbiased, MANT_BITS);

        return GF64{
            raw = (sign << 63) |
                  ((exp_clamped as u64) << MANT_BITS) |
                  (mant as u64)
        };
    }

    fn decode(gf: GF64) -> f64 {
        const sign = (gf.raw >> 63) as u8;
        const exp_biased = ((gf.raw >> MANT_BITS) & EXP_FIELD_MASK) as u32;
        const mant = (gf.raw & MANT_MASK) as u64;

        if (exp_biased == 0 && mant == 0) {
            return 0.0;
        }
        const exp_unbiased = if (exp_biased == 0) {
            -(EXP_BIAS as i32) + 1
        } else {
            (exp_biased as i32) - EXP_BIAS as i32
        };
        const mant_normalized = if (exp_biased == 0) {
            (mant as f64) / MANT_DIV
        } else {
            1.0 + (mant as f64) / MANT_DIV
        };
        const value = mant_normalized * pow2(exp_unbiased);
        if (sign != 0) { return -value; }
        return value;
    }

    // 4. Format Properties
    fn max_value() -> f64 {
        const mant_max = 1.0 + (MANT_MASK as f64) / MANT_DIV;
        const exp_max = (EXP_MAX as i32) - (EXP_BIAS as i32);
        return mant_max * pow2(exp_max);
    }
    fn min_positive() -> f64 {
        const mant_min = 1.0 / MANT_DIV;
        const exp_min = -(EXP_BIAS as i32) + 1;
        return mant_min * pow2(exp_min);
    }
    fn epsilon() -> f64 {
        return 1.0 / MANT_DIV;
    }

    // Memory: 64 bits = 8 bytes (same as IEEE binary64)
    const MEMORY_RATIO_VS_FP64 : f64 = 1.0;

    // 5. Validation against the family descriptor
    fn validate_format() -> bool {
        const fmt = goldenfloat_family::get_format_by_name("GF64");
        return (fmt != null) &&
               (fmt.?.bits == BITS) &&
               (fmt.?.exp_bits == EXP_BITS) &&
               (fmt.?.mant_bits == MANT_BITS);
    }

    // 6. Use Cases
    // GF64 is the double-precision member of the family:
    // - 24-bit exponent (vs IEEE binary64's 11-bit) -> far wider dynamic range
    // - 39-bit mantissa (vs IEEE's 52-bit) -> coarser precision, traded for range
    // - Same 8-byte footprint as IEEE binary64, but phi-optimal E:M split
    // - Target: scientific / double-precision workloads on phi-structured silicon
    // Comparison with IEEE binary64:
    //   IEEE:  1 + 11 + 52, exp/mant = 0.212 (phi_distance = 0.406)
    //   GF64:  1 + 24 + 39, exp/mant = 0.615 (phi_distance = 0.00265)

    // 7. Helpers (family-standard; integer-backed)
    fn floor_log2(x: f64) -> i32 {
        if (x <= 0.0) { return -2147483648; }
        let exp : i32 = 0;
        while (x >= 2.0) { x = x / 2.0; exp = exp + 1; }
        while (x < 1.0)  { x = x * 2.0; exp = exp - 1; }
        return exp;
    }
    fn extract_mantissa(value: f64, exp: i32, mant_bits: u8) -> u64 {
        const normalized = value / pow2(exp);
        const frac = normalized - 1.0;
        const max_mant = (1u64 << mant_bits) - 1;
        return (frac * (max_mant as f64 + 1.0)) as u64;
    }
    fn clamp_u32(x: u32, min: u32, max: u32) -> u32 {
        if (x < min) { return min; }
        if (x > max) { return max; }
        return x;
    }
    fn pow2(e: i32) -> f64 {
        let result = 1.0;
        let n = if (e < 0) { -e } else { e };
        let acc = 2.0;
        let k = n;
        while (k > 0) {
            if (k % 2 == 1) { result = result * acc; }
            acc = acc * acc; k = k / 2;
        }
        if (e < 0) { return 1.0 / result; }
        return result;
    }

    // TDD-Inside-Spec: tests + invariants
    test gf64_decode_zero
        given gf = GF64{ raw = 0 }
        when value = decode(gf)
        then value == 0.0

    test gf64_encode_zero_roundtrip
        given original = 0.0
        and   encoded = encode(original)
        and   decoded = decode(encoded)
        then decoded == original

    test gf64_bits_sum_correct
        given total = SIGN_BITS + EXP_BITS + MANT_BITS
        then total == BITS

    test gf64_bias_formula
        given computed = (1u32 << (EXP_BITS - 1)) - 1
        then computed == EXP_BIAS

    test gf64_exp_max_formula
        given computed = (1u32 << EXP_BITS) - 1
        then computed == EXP_MAX

    test gf64_phi_bias_equals_exp_max_minus_bias
        // GF64 is the one format where PHI_BIAS coincides with EXP_MAX - BIAS
        given computed = EXP_MAX - EXP_BIAS
        then computed == PHI_BIAS

    test gf64_phi_distance_best_on_ladder
        given phi_dist = PHI_DISTANCE
        then phi_dist < 0.003

    test gf64_memory_ratio_equals_one
        given ratio = MEMORY_RATIO_VS_FP64
        then ratio == 1.0

    test gf64_validate_format_success
        given valid = validate_format()
        then valid == true

    invariant gf64_bits_constant
        assert BITS == 64

    invariant gf64_sign_bits_is_one
        assert SIGN_BITS == 1

    invariant gf64_exp_bits_is_twentyfour
        assert EXP_BITS == 24

    invariant gf64_mant_bits_is_thirtynine
        assert MANT_BITS == 39

    invariant gf64_bias_is_canonical
        assert EXP_BIAS == 8388607

    invariant gf64_phi_bias_is_canonical
        assert PHI_BIAS == 8388608

    invariant gf64_phi_distance_best_on_ladder
        assert PHI_DISTANCE < 0.003

    invariant gf64_exp_wider_than_ieee
        assert EXP_BITS > 11  // IEEE binary64 has 11-bit exponent

    invariant gf64_mant_narrower_than_ieee
        assert MANT_BITS < 52  // IEEE binary64 has 52-bit mantissa

    invariant gf64_max_ge_min_positive
        assert max_value() >= min_positive()
}

Open the lesson's spec in the player ↗

All lessons