← Back to AILP Home

fix256 Math

fix256 provides a full suite of transcendental math functions implemented natively in Q128.128 fixed-point arithmetic. All results are bit-exact and platform-identical — no floating-point drift, no non-determinism.


Why fix256 Math?

Standard flt64 math (sin, sqrt, exp, etc.) can produce slightly different results on different hardware due to: - Intermediate 80-bit x87 registers on x86 - FMA vs. non-FMA code paths - Compiler optimization reordering

fix256 math produces the same bits on x86-64, ARM64, RISC-V, and CUDA — every time. This is critical for deterministic simulation, robotic control, reproducible physics, and consciousness substrate integrity.


Rounding and Truncation

Function Description
fix256_floor(a) Round toward −∞. floor(x) ≤ x always.
fix256_ceil(a) Round toward +∞. x ≤ ceil(x) always.
fix256_trunc(a) Round toward 0. Equivalent to floor for positive values.
fix256_round(a) Round to nearest; ties round away from zero.
fix256:x  = 3.7fix256;
fix256:f  = fix256_floor(x);   // 3.0
fix256:c  = fix256_ceil(x);    // 4.0
fix256:t  = fix256_trunc(x);   // 3.0

fix256:nx = -3.7fix256;
fix256:nf = fix256_floor(nx);  // -4.0
fix256:nt = fix256_trunc(nx);  // -3.0

Absolute Value and Sign

Function Description
fix256_abs(a) Absolute value. fix256_abs(ERR) == ERR.
fix256_neg(a) Negation. Equivalent to 0 - a.
fix256:pos = fix256_abs(-10.5fix256);  // 10.5
fix256:neg = fix256_neg(5.0fix256);    // -5.0

Note: fix256_abs(fix256_ERR()) propagates ERR — it does not produce a valid result.


Square Root

fix256:r = fix256_sqrt(a);

Implementation: Newton-Raphson iteration in Q128.128 space, converging to 128-bit fractional precision (~39 decimal digits). Approximately 15 iterations suffice for full precision.

Domain: a ≥ 0. For a < 0 or a == ERR, returns ERR.

fix256:two = fix256_sqrt(4.0fix256);   // 2.0 (exact)
fix256:s2  = fix256_sqrt(2.0fix256);   // 1.41421356237309... (Q128.128 precision)

Precision: Within 1 ULP of the true Q128.128 result for all non-ERR inputs.


Exponential and Logarithm

Function Description Domain
fix256_exp(a) eᵃ Any a (underflows to 0 for very negative a)
fix256_log(a) ln(a) — natural log a > 0

Implementation: Taylor series / CORDIC-inspired iteration in Q128.128 space with sufficient terms for ≥ 128-bit fractional accuracy.

fix256:e_val  = fix256_exp(1.0fix256);    // e ≈ 2.71828182845904...
fix256:ln2    = fix256_log(2.0fix256);    // ≈ 0.69314718055994...
fix256:ln_e   = fix256_log(fix256_exp(1.0fix256));  // 1.0 (round-trip)

Identity: fix256_log(fix256_exp(x)) == x for x in the representable range.

ERR triggers: - fix256_log(0) → ERR (mathematically −∞) - fix256_log(negative) → ERR - fix256_exp(x) for very large x → ERR (overflow)


Power

fix256:p = fix256_pow(base, exp);

Two code paths depending on exp:

exp type Strategy
Non-negative integer Repeated squaring (exact, O(log n))
Fractional / negative fix256_exp(exp * fix256_log(base))
fix256:p1 = fix256_pow(2.0fix256, 10.0fix256);   // 1024.0 (exact, integer exp)
fix256:p2 = fix256_pow(2.0fix256, 0.5fix256);    // √2 ≈ 1.41421... (fractional exp)
fix256:p3 = fix256_pow(10.0fix256, -2.0fix256);  // 0.01

ERR triggers: fix256_pow(negative, fractional_exp) → ERR (complex result not representable).


Trigonometry

All angles are in radians. The functions operate natively in Q128.128 space using polynomial approximations tuned for the full Q128.128 precision range.

Function Description
fix256_sin(a) Sine
fix256_cos(a) Cosine
// Approximation of PI in Q128.128
fix256:pi = 3.14159265358979323846fix256;

fix256:s0 = fix256_sin(0.0fix256);       // 0.0 (exact)
fix256:s90 = fix256_sin(pi / 2.0fix256); // 1.0
fix256:c0 = fix256_cos(0.0fix256);       // 1.0 (exact)
fix256:c90 = fix256_cos(pi / 2.0fix256); // ≈ 0.0 (within 1 ULP)

Pythagorean identity: fix256_sin(x)² + fix256_cos(x)² equals 1.0fix256 within 2⁻¹²⁰ for well-representable x.

Precision: Results are accurate to ≥ 110 fractional bits for x in [−2π, 2π]. Precision degrades for very large arguments due to argument reduction; use fix256_fmod (when available) to reduce first.


ERR Sentinel Propagation

All fix256 math functions propagate ERR:

fix256:bad = fix256_ERR();
fix256:r   = fix256_sin(bad);   // ERR
fix256:r2  = fix256_sqrt(bad);  // ERR
fix256:r3  = fix256_exp(bad);   // ERR

An ERR input always yields ERR output. Use ok() to test before calling math functions on untrusted values:

if (ok(x) == 0) {
    // handle error before calling math
}
fix256:result = fix256_sqrt(x);

Dimensional Analysis Variants (v0.55.5.3)

fix256 math functions respect dimensional types where mathematically valid:

Operation Input Dimension Output Dimension
fix256_sqrt(x) fix256<D> (all exponents even) fix256<D^½>
fix256_abs(x) fix256<D> fix256<D> (preserved)
fix256_floor/ceil/trunc/round(x) fix256<D> fix256<D> (preserved)
fix256_neg(x) fix256<D> fix256<D> (preserved)
fix256_sin/cos/exp/log(x) Dimensionless only Dimensionless
// Area in m²  →  length in m
fix256<Meters*Meters>:area = 16.0fix256;
fix256<Meters>:side = fix256_sqrt(area);  // 4.0 m

// Compile error: can't take sin of dimensioned value
fix256<Meters>:bad = fix256_sin(side);  // ❌ compile-time error

Precision Summary

Function Precision Notes
fix256_floor/ceil/trunc/round Exact No approximation
fix256_abs/neg Exact No approximation
fix256_sqrt ≥ 127 fractional bits Newton-Raphson, ~15 iterations
fix256_exp ≥ 120 fractional bits Taylor series
fix256_log ≥ 120 fractional bits Newton-Raphson via exp
fix256_pow ≥ 110 fractional bits Via exp(n·log(x)) for fractional n
fix256_sin/cos ≥ 110 fractional bits Polynomial approx., reduced range

For comparison, flt64 provides only ~52 fractional bits. fix256 math gives roughly 2.5× more fractional precision than IEEE 754 double.


Performance vs. flt64

fix256 math is slower than flt64 — all arithmetic is software-emulated:

Operation flt64 (relative) fix256 (relative)
floor / abs 5–10×
sqrt 50–200×
exp / log 500–2000×
sin / cos 500–2000×

Guidance: Use fix256 math when bit-exact determinism across platforms is required. Use flt64 for performance-critical code where cross-platform drift is acceptable.


GPU Support

All fix256 math functions have PTX equivalents implemented in fix256_gpu.cu, enabling deterministic math in CUDA kernels:

// GPU kernel — all math is deterministic
gpu:kernel:compute = void(fix256[]:data, int32:n) {
    int32:tid = thread_id();
    fix256:val = data[tid];
    data[tid] = fix256_sin(val) * fix256_sin(val) + fix256_cos(val) * fix256_cos(val);
    // Guaranteed to equal 1.0fix256 on all GPUs
};

Related