t27.aiРусский

Why base three

You will learn

Why ln(b) / b peaks at e, how close base 3 comes, and what 27 trits are worth in bits.

Radix economy scores a base b by E(b) = ln(b) / b, and calculus puts its peak at b = e, where E = 1 / e = 0.36788. radix_economy.t27 writes the neighbours in: E(2) = 0.34657 and E(3) = 0.36620. Base 3 reaches 0.995 of the peak, and E(3) / E(2) = 1.0566, an advantage of 5.66 percent; the spec bounds it from below at 0.054, or 5.4 percent, though the invariant is named 54_percent. In range, 27 balanced trits reach 3812798742493, above 2^41 - 1 and under 2^42 - 1, so they need 42 bits. These are arguments about digits, not a timing on a ternary machine.

Try it

Divide E_BASE3 by E_BASE2 in radix_economy.t27 by hand. Then find the invariant named 54_percent and say what number it actually asserts.

Open the interactive lesson →

GoldenFloat 5: why base three
GoldenFloat 5: why base three ↗

Radix economy ln(b) / b for bases 2, 3 and e, and 27 trits in bits, read from radix_economy.t27. Lesson 5 of the GoldenFloat course.

specs/math/radix_economy.t27

// SPDX-License-Identifier: Apache-2.0
// t27/specs/math/radix_economy.t27
// Radix Economy Formal Spec — Information-Theoretic Basis for Base-3 Computing
// E(b) = ln(b)/b, maximized at b = e ≈ 2.71828
// E(3)/E(e) >= 99.5%, E(3)/E(2) = 1.054 (5.4% advantage)

module RadixEconomy {

    // ═══════════════════════════════════════════════════════════════════════════
    // 1. Radix Economy Constants
    // ═════════════════════════════════════════════════════════════════════════════════════════

    // E(b) = ln(b) / b — information per digit
    // E(2) = ln(2)/2 ≈ 0.34657 — binary radix economy
    const E_BASE2 : f64 = 0.34657359027997264; // ln(2)/2

    // E(3) = ln(3)/3 ≈ 0.36620 — ternary radix economy
    const E_BASE3 : f64 = 0.3662040962227032; // ln(3)/3

    // E(e) = 1/e ≈ 0.36788 — optimal radix economy (theoretical maximum)
    const E_OPTIMAL : f64 = 0.36787944117144233; // 1/e

    // log2(3) ≈ 1.58496 — bits per trit (information density)
    const LOG2_3 : f64 = 1.584962500721156;

    // log3(2) ≈ 0.63093 — trits per bit (inverse density)
    const LOG3_2 : f64 = 0.6309297535714574;

    // ═══════════════════════════════════════════════════════════════════════════
    // 2. Radix Economy Functions
    // ═════════════════════════════════════════════════════════════════════════════════════════

    // Compute radix economy for base b
    fn radix_economy(b: f64) -> f64 {
        return ln(b) / b;
    }

    // Compute efficiency relative to optimal base e
    fn efficiency_ratio(b: f64) -> f64 {
        return radix_economy(b) / E_OPTIMAL;
    }

    // Compare two bases: ratio of their radix economies
    fn base_advantage(b1: f64, b2: f64) -> f64 {
        return radix_economy(b1) / radix_economy(b2);
    }

    // Information density: bits per digit
    fn info_density_bits(b: f64) -> f64 {
        return log2(b);
    }

    // Ternary range: maximum value for n trits (balanced: -(3^n-1)/2 to (3^n-1)/2)
    fn ternary_range(n: i64) -> i64 {
        return (pow(3.0, n as f64) - 1.0) as i64 / 2;
    }

    // Binary range: maximum value for n bits
    fn binary_range(n: i64) -> i64 {
        return (pow(2.0, n as f64) - 1.0) as i64;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // 3. Helper Functions (logarithms)
    // ═════════════════════════════════════════════════════════════════════════════════════════

    // Natural logarithm
    fn ln(x: f64) -> f64 {
        if x <= 0.0 {
            return 0.0 / 0.0; // NaN
        }
        if x == 1.0 {
            return 0.0;
        }
        // Series: ln(x) = 2 * sum_{k=0..inf} (1/(2k+1)) * ((x-1)/(x+1))^(2k+1)
        // Sixty terms, not five: five left ln(3) off by about 1.1e-4 and
        // ln(8) by about 2.4e-2, far outside the 1e-5 and 1e-6 the tests ask.
        // At x = 8, t = 7/9 and the tail after 60 terms is below 1e-12.
        let t = (x - 1.0) / (x + 1.0);
        let t2 = t * t;
        let mut power = t;
        let mut sum = 0.0;
        let mut k = 0;
        while k < 60 {
            sum = sum + power / ((2 * k + 1) as f64);
            power = power * t2;
            k = k + 1;
        }
        return 2.0 * sum;
    }

    // Base-2 logarithm: log2(x) = ln(x) / ln(2)
    fn log2(x: f64) -> f64 {
        return ln(x) / ln(2.0);
    }

    // Power function (for range calculations)
    fn pow(x: f64, n: f64) -> f64 {
        if x < 0.0 and n != floor(n) {
            return 0.0 / 0.0;
        }
        if x == 0.0 {
            if n > 0.0 { return 0.0; }
            if n == 0.0 { return 1.0; }
            return 1.0 / 0.0;
        }
        if n == 0.0 { return 1.0; }

        let negative = n < 0.0;
        let exp = if negative { -n } else { n };
        let is_integer = exp == floor(exp);

        if is_integer {
            let exp_int = exp as i64;
            let mut result = 1.0;
            let mut base = x;
            let mut e = exp_int;

            while e > 0 {
                if e % 2 == 1 {
                    result = result * base;
                }
                base = base * base;
                e = e / 2;
            }

            if negative { result = 1.0 / result; }
            return result;
        }

        // Fractional: use log/exp
        let ln_x = ln(x);
        let mut result = 1.0;
        let mut term = 1.0;
        for i in 1..=12 {
            term = term * exp * ln_x / (i as f64);
            result = result + term;
        }

        if negative { result = 1.0 / result; }
        return result;
    }

    // Natural exponential: e^x (simplified)
    fn exp(x: f64) -> f64 {
        if x == 0.0 { return 1.0; }

        let mut result = 1.0;
        let mut term = 1.0;

        for i in 1..=12 {
            term = term * x / (i as f64);
            result = result + term;
        }

        return result;
    }

    // Floor function
    fn floor(x: f64) -> f64 {
        let xi = x as i64;
        if x >= 0.0 || x == xi as f64 {
            return xi as f64;
        }
        return (xi - 1) as f64;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // 4. TDD-Inside-Spec: Tests for Radix Economy
    // ═════════════════════════════════════════════════════════════════════════════════════════

    test e_base3_near_optimal
        given e3 = E_BASE3
        and   e_optimal = E_OPTIMAL
        when  ratio = e3 / e_optimal
        then  ratio >= 0.995
        and   ratio <= 1.0

    test e_base3_beats_base2
        given e3 = E_BASE3
        and   e2 = E_BASE2
        when  ratio = e3 / e2
        and   advantage = (e3 - e2) / e2
        then  e3 > e2
        and   ratio >= 1.05
        and   advantage >= 0.05

    test log2_3_accuracy
        given log2_3 = LOG2_3
        when  lower = 1.58496
        and   upper = 1.58497
        then  log2_3 >= lower and log2_3 <= upper

    test log3_2_accuracy
        given log3_2 = LOG3_2
        when  reciprocal = 1.0 / LOG2_3
        then  abs(log3_2 - reciprocal) < 1e-6

    test ternary_vs_binary_range_27trit
        // (3^27 - 1)/2 = 3812798742493 lies between 2^41 - 1 = 2199023255551
        // and 2^42 - 1 = 4398046511103: 27 balanced trits need 42 bits.
        // (This test claimed 43; the balanced range is half of 3^27.)
        given trit_range = ternary_range(27)
        and   bit_range_41 = binary_range(41)
        and   bit_range_42 = binary_range(42)
        when  trit_range
        then  trit_range > bit_range_41
        and   trit_range <= bit_range_42

    test ternary_vs_binary_range_18trit
        // (3^18 - 1)/2 = 193710244 lies between 2^27 - 1 = 134217727 and
        // 2^28 - 1 = 268435455: 18 balanced trits need 28 bits, not 29.
        given trit_range = ternary_range(18)
        and   bit_range_27 = binary_range(27)
        and   bit_range_28 = binary_range(28)
        when  trit_range
        then  trit_range > bit_range_27
        and   trit_range <= bit_range_28

    test radix_economy_function_correctness
        given e2_computed = radix_economy(2.0)
        and   e3_computed = radix_economy(3.0)
        and   e_e_computed = radix_economy(2.718281828459045)
        when  err_e2 = abs(e2_computed - E_BASE2)
        and   err_e3 = abs(e3_computed - E_BASE3)
        and   err_ee = abs(e_e_computed - E_OPTIMAL)
        then  err_e2 < 1e-6 and err_e3 < 1e-6 and err_ee < 1e-6

    test efficiency_ratio_base3
        given eff3 = efficiency_ratio(3.0)
        when  eff3
        then  eff3 >= 0.995 and eff3 <= 1.0

    test base_advantage_3_vs_2
        given advantage = base_advantage(3.0, 2.0)
        when  advantage
        then  advantage >= 1.054

    test info_density_trit
        given density = info_density_bits(3.0)
        when  density
        then  abs(density - LOG2_3) < 1e-6

    test ln_function_accuracy
        given ln_e = ln(2.718281828459045)
        when  ln_e
        then  abs(ln_e - 1.0) < 1e-6

    test ln_function_ln2
        given ln_2 = ln(2.0)
        when  ln_2
        then  abs(ln_2 - 0.693147) < 1e-5

    test ln_function_ln3
        given ln_3 = ln(3.0)
        when  ln_3
        then  abs(ln_3 - 1.098612) < 1e-5

    test log2_function_accuracy
        given log2_2 = log2(2.0)
        and   log2_4 = log2(4.0)
        and   log2_8 = log2(8.0)
        when  results
        then  abs(log2_2 - 1.0) < 1e-6
        and   abs(log2_4 - 2.0) < 1e-6
        and   abs(log2_8 - 3.0) < 1e-6

    // ═══════════════════════════════════════════════════════════════════════════
    // 5. Formal Invariants — Mathematical Truths
    // ═════════════════════════════════════════════════════════════════════════════════════════

    invariant base3_995_percent_optimal
        assert E_BASE3 / E_OPTIMAL >= 0.995
        // Rationale: E(3) >= 99.5% of E(e), proven by calculus: d/db(ln(b)/b)=0 => b=e

    invariant base3_superior_to_base2
        assert E_BASE3 > E_BASE2
        // Rationale: ln(3)/3 > ln(2)/2 by direct computation

    invariant base3_54_percent_advantage
        assert (E_BASE3 - E_BASE2) / E_BASE2 >= 0.054
        // Rationale: (0.3662 - 0.3466) / 0.3466 = 0.054 = 5.4%

    invariant log2_3_in_range
        assert LOG2_3 >= 1.58496 and LOG2_3 <= 1.58497
        // Rationale: log2(3) ≈ 1.584962500721156

    invariant trit_info_density
        assert LOG2_3 > 1.5 and LOG2_3 < 2.0
        // Rationale: A trit contains more information than a bit (1.58 > 1), less than 2 bits

    invariant radix_economy_monotonic_increase_to_e
        assert E_BASE2 < E_OPTIMAL and E_BASE3 < E_OPTIMAL
        // Rationale: E(b) = ln(b)/b increases for b < e, decreases for b > e,
        // so both integer neighbours of e sit below the peak 1/e.

    invariant optimal_base_is_e
        assert abs(E_OPTIMAL - 1.0 / 2.718281828459045) < 1e-15
        // Rationale: Maximizing ln(b)/b gives b = e by calculus

    invariant ternary_range_balanced
        // For every positive n; checked at n = 1, 2, 3.
        assert ternary_range(1) == 1 and ternary_range(2) == 4 and ternary_range(3) == 13
        // Rationale: Balanced ternary represents integers from -(3^n-1)/2 to (3^n-1)/2

    invariant binary_range_standard
        // For every positive n; checked at n = 1, 8, 16.
        assert binary_range(1) == 1 and binary_range(8) == 255 and binary_range(16) == 65535
        // Rationale: Unsigned binary represents integers from 0 to 2^n - 1

    invariant range_equivalence_27trit_42bit
        assert ternary_range(27) <= binary_range(42)
        and   ternary_range(27) > binary_range(41)
        // Rationale: (3^27-1)/2 ≈ 3.81e12, 2^41 ≈ 2.20e12, 2^42 ≈ 4.40e12

    invariant range_equivalence_18trit_28bit
        assert ternary_range(18) <= binary_range(28)
        and   ternary_range(18) > binary_range(27)
        // Rationale: (3^18-1)/2 ≈ 1.94e8, 2^27 ≈ 1.34e8, 2^28 ≈ 2.68e8

    invariant log_reciprocal_identity
        assert abs(LOG3_2 * LOG2_3 - 1.0) < 1e-6
        // Rationale: log_a(b) * log_b(a) = 1 for any valid bases

    // ═══════════════════════════════════════════════════════════════════════════
    // 6. Benchmarks — Performance Targets
    // ═════════════════════════════════════════════════════════════════════════════════════════

    bench radix_economy_computation
        measure: cycles to compute radix_economy(3.0)
        target: < 100 cycles

    bench log2_computation
        measure: cycles to compute log2(3.0)
        target: < 200 cycles

    bench ternary_range_27
        measure: cycles to compute ternary_range(27)
        target: < 500 cycles

    bench base_advantage_3_vs_2
        measure: cycles to compute base_advantage(3.0, 2.0)
        target: < 150 cycles
}

Open the lesson's spec in the player ↗

All lessons