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 | 1× | 5–10× |
| sqrt | 1× | 50–200× |
| exp / log | 1× | 500–2000× |
| sin / cos | 1× | 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
- types/fix256.md — fix256 type reference (arithmetic, ERR, constants, conversions)
- types/dimensional.md — dimensional analysis with fix256
- standard_library/math.md — flt64 scalar math builtins
- types/flt.md — IEEE 754 floating-point (faster, non-deterministic)