gMath — Multi-Domain Fixed-Point Arithmetic Library
Zero-float, pure-Rust, consensus-safe precision arithmetic achieving 0 ULP accuracy across all 18 transcendental functions on all computation profiles.
Why gMath?
Most math libraries pick one number representation and accept its limitations. gMath routes each value to its optimal domain automatically: decimals stay exact in decimal, fractions stay exact in symbolic, powers of 2 stay exact in binary, and transcendentals compute at double-width precision. The result: 0 ULP (Units in Last Place) across every operation, every profile.
I started building this because I was working on an idea which needed a reliable, robust and preferable precise fixedpoint library in Rust for high throughput. And because I believe that parts of the knowledge we already possess currently sits in the shade of our human comprehension. This is ground - already uncovered - yet to be explored by people and AI, often in close collaboration.
LLMs flipped the script for millions of people - including myself, no longer is technical expertise a barrier to creation, today it can be overcome. AI enables everyone, of every creed and background, to study faster, iterate and prototype continuously and find solutions quicker than ever before.
I have caused my family considerable stress while developing this library - allnighters and generally obsessively bothering my wife with intricate math insights - if you wish to help me atone for that, consider donating to any of the addresses I listed at the bottom of this README.
If you are more interested in the development story, I suggest you give my blogpost on it a read on nierto.com. I prioritize delivering this opensource software over finishing the story of how it came to be, so check back in in a fortnight and it will be available.
THE VIBE IS STRONG WITH THIS ONE
Claude helped me provide substance to the vision I had for this library and I am forever grateful that it allowed me to build something that I can now share with the world. It is by no means finished, and there might be flawed, but it is only I and a legion of transformer-based LLMs that built this. All feedback and input is welcome!
Quick Start
use ;
// Arithmetic — auto-routes to optimal domain
let sum = evaluate.unwrap; // 4.0 (exact)
let product = evaluate.unwrap; // 1.0 (exact — symbolic)
let decimal = evaluate.unwrap; // 0.3 (exact — decimal domain)
// 18 transcendental functions — all at 0 ULP
let e = evaluate.unwrap; // 2.7182818284590452353...
let root2 = evaluate.unwrap; // 1.4142135623730950488...
let pi_sin = evaluate.unwrap; // ~0
Runtime Strings
gmath() accepts &'static str (string literals) for zero-cost deferred parsing. For runtime/dynamic strings, use gmath_parse():
use ;
// Static strings — zero-cost, parsing deferred until evaluate()
let a = gmath;
// Runtime strings — eagerly parsed, full mode routing support
let user_input = Stringfrom;
let b = gmath_parse.unwrap;
// Both work identically in expressions
let result = evaluate.unwrap;
// Read values from files, databases, user input, etc.
let values: = vec!;
let mut sum = gmath_parse.unwrap;
for v in &values
let total = evaluate.unwrap;
The auto:auto Advantage
gMath's default mode (auto:auto) combines the strength of four computation domains to deliver results no single domain can match:
Input "0.1" → Decimal domain → 0.1 is EXACT (not 0.100000000000000001)
Input "1/3" → Symbolic domain → 1/3 is EXACT (infinite precision rational)
Input "1024" → Binary domain → power-of-2, exact in binary
Input "exp()" → Binary compute → Tier N+1 strategy, 0 ULP
Forcing all inputs through a single domain produces approximate results — our comprehensive benchmark proves this across 288 mode routing test points:
| Mode | Exact | Approx | Lossy | Why |
|---|---|---|---|---|
| auto:auto | 24 | 0 | 0 | Each input routed to its natural domain |
| symbolic:symbolic | 24 | 0 | 0 | Infinite precision (but no transcendentals) |
| binary:binary | 17 | 7 | 0 | 1/3 is approximate in binary |
| decimal:decimal | 14 | 10 | 0 | 1/3 is 0.333...333 (truncated) |
| ternary:ternary | 20 | 4 | 0 | Ternary representation limits |
| ternary:decimal | 16 | 8 | 0 | Double conversion loss |
Canonical API
Entry Points
use ;
// Static strings (compile-time literals) — zero-cost, deferred parsing
let expr = gmath;
// Runtime strings — eager parsing, returns Result
let expr = gmath_parse?;
Input Formats
gMath recognizes several input syntaxes and routes each to the optimal domain:
| Syntax | Domain | Examples | Description |
|---|---|---|---|
"1/3", "22/7" |
Symbolic | gmath("1/3") |
Fractions — exact rational arithmetic |
"0.333..." |
Symbolic | gmath("0.142857...") |
Repeating decimals — converted to exact rational (1/7) |
"0x", "0b" |
Binary | gmath("0xFF"), gmath("0b1010") |
Hex and binary integer literals |
"0t" |
Ternary | gmath("0t1.5") |
Balanced ternary fixed-point |
"1.5", "0.001" |
Decimal | gmath("19.99") |
Decimal point — exact in decimal domain |
"pi", "e", "sqrt2" |
Symbolic | gmath("phi"), gmath("ln2") |
Named mathematical constants |
"42", "1024" |
Binary | gmath("1000000") |
Integers — binary fixed-point |
Named constants: pi, e, sqrt2, sqrt3, phi, ln2, ln10, gamma (also accepts uppercase and Unicode: PI, π, φ, √2, √3, γ).
Arithmetic (operator overloading)
let a = gmath + gmath; // Addition
let b = gmath * gmath; // Multiplication
let c = gmath - gmath; // Subtraction
let d = gmath / gmath; // Division
let e = -gmath; // Negation
let result = evaluate; // Triggers computation
println!; // Display with guaranteed decimals
Transcendental Functions (18 total, 0 ULP)
// Exponential family
gmath.exp // e^x
gmath.ln // ln(x)
gmath.sqrt // √x
gmath.pow // x^y
// Trigonometric
gmath.sin // sin(x)
gmath.cos // cos(x)
gmath.tan // tan(x)
// Inverse trigonometric
gmath.atan // atan(x)
gmath.asin // asin(x)
gmath.acos // acos(x)
gmath.atan2 // atan2(y, x)
// Hyperbolic
gmath.sinh // sinh(x)
gmath.cosh // cosh(x)
gmath.tanh // tanh(x)
// Inverse hyperbolic
gmath.asinh // asinh(x)
gmath.acosh // acosh(x)
gmath.atanh // atanh(x)
Chaining Results (zero precision loss)
use ;
// Feed previous results back in — full precision preserved
let rate = gmath;
let mut balance = evaluate.unwrap;
for year in 1..=5
Mode Routing (compute:output control)
use ;
// Force specific compute and output domains
set_gmath_mode.unwrap; // Compute in binary, output as decimal
let result = evaluate;
// Auto compute, specific output format
set_gmath_mode.unwrap; // Best compute domain, ternary output
// Reset to default (recommended)
reset_gmath_mode; // Back to auto:auto
Available modes: auto, binary, decimal, symbolic, ternary — any combination as compute:output.
Result Extraction
let val = evaluate.unwrap;
// Display — guaranteed decimals per profile
println!; // "1.0000000000000000000" (19 digits on embedded)
// Exact rational form
let rational = val.to_rational.unwrap;
// Decimal string with custom precision
let s = val.to_decimal_string; // "1.0000000000"
// Domain inspection
val.domain_type; // Some(DomainType::Symbolic)
val.is_error; // false
val.tier; // precision tier (1-8)
Error Handling
All fallible operations return Result<_, OverflowDetected>:
use ;
match evaluate
// gmath_parse returns Result too — handles invalid input gracefully
match gmath_parse
Precision Profiles
| Profile | Format | Storage | Compute | Guaranteed Decimals | Transcendentals |
|---|---|---|---|---|---|
| Embedded | Q64.64 | i128 |
I256 |
19 | 18/18 at 0 ULP |
| Balanced | Q128.128 | I256 |
I512 |
38 | 18/18 at 0 ULP |
| Scientific | Q256.256 | I512 |
I1024 |
77 | 18/18 at 0 ULP |
Select via environment variable before compilation:
GMATH_PROFILE=embedded GMATH_PROFILE=balanced GMATH_PROFILE=scientific
Important: clear the incremental cache when switching profiles. Each profile compiles entirely different code paths via cfg flags. Rust's incremental compilation cache can retain stale artifacts from the previous profile, causing build failures or crashes at runtime.
GMATH_PROFILE=scientific
This is a one-time step per switch — rebuilds within the same profile are fine.
Architecture
ZASC — Zero-Allocation Stack Computation
Expressions build lazily as trees, then evaluate on a fixed-size stack workspace. No heap allocation on the hot path.
gmath("value") → LazyExpr (tree builder, operator overloading)
→ StackEvaluator (thread-local, 4KB-64KB workspace)
→ StackValue (domain-tagged result)
UGOD — Universal Graceful Overflow Delegation
Automatic tier promotion on overflow. Operations start at the minimum required tier and promote upward as needed:
i8 → i16 → i32 → i64 → i128 → I256 → I512 → Symbolic Rational
Symbolic rational is the guaranteed-success fallback — no operation ever fails silently. For unbounded precision, enable the optional infinite-precision feature for BigInt tier 8.
Tier N+1 Precision Strategy
All transcendentals compute at one tier above storage, then downscale:
Embedded: Q64.64 (i128) → compute at Q128.128 (I256) → downscale to i128
Balanced: Q128.128 (I256) → compute at Q256.256 (I512) → downscale to I256
Scientific: Q256.256 (I512) → compute at Q512.512 (I1024) → downscale to I512
Result: the closest possible fixed-point integer to the true mathematical value — 0 ULP.
BinaryCompute Chain Persistence
Chained transcendentals like sin(ln(exp(x))) stay at compute tier throughout — only one downscale at final materialization, preventing cumulative precision loss.
Four Computation Domains
| Domain | Best For | Exactness | Example |
|---|---|---|---|
| Binary Fixed | Transcendentals, integers, powers of 2 | 19-77 decimals | 42, 1024, exp(1.0) |
| Decimal Fixed | Financial, exact decimals | 0 ULP exact | 0.1, 19.99, 0.001 |
| Balanced Ternary | Base-3 computation, geometric symmetry | Exact in base 3 | 0t1.0, 0t0.111 |
| Symbolic Rational | Fractions, repeating decimals, constants | Infinite precision | 1/7, 0.333..., pi |
Performance (Q64.64 embedded, x86_64)
| Category | Operation | Throughput | Latency (avg) |
|---|---|---|---|
| Arithmetic | binary add | 3.9M ops/s | 255ns |
| Arithmetic | symbolic add | 4.4M ops/s | 228ns |
| Arithmetic | decimal mul | 3.6M ops/s | 274ns |
| Transcendental | exp | 1.0M ops/s | 980ns |
| Transcendental | sin / cos | 820K ops/s | 1.2us |
| Transcendental | ln | 1.0M ops/s | 971ns |
| Transcendental | sqrt | 46K ops/s | 21.7us |
| Transcendental | atan | 34K ops/s | 29.3us |
| Mode routing | auto:* | 4.0M ops/s | 246ns |
Validation
The comprehensive benchmark suite validates across 60,000+ mpmath-verified reference points:
GMATH_PROFILE=embedded
Coverage:
- 60,860 arithmetic points across 4 domains x 4 operations (decimal, symbolic, binary, ternary, cross-domain)
- 16,974 transcendental points across 18 functions x 1,000+ reference values, validated against mpmath at 250-digit precision
- 288 mode routing points across 12 compute:output combinations x 24 test cases
- 0 lossy results across all mode combinations — domain limitations produce approximations, never data loss
Dependencies
Zero runtime dependencies by default. All arithmetic — including 18 transcendental functions — is implemented in pure Rust using native integers and custom wide types (I256, I512, I1024).
Optional: enable --features infinite-precision to activate BigInt tier 8 (pulls in num-bigint, num-traits, num-integer).
Build System
Pre-built lookup tables are included in the crate — builds complete in ~2 seconds. No table generation required.
If you want to verify or regenerate the tables from scratch:
Tables are generated algorithmically by build.rs with zero external data files:
- Pi: Machin's formula at 580-bit rational precision
- Exp/Ln tables: 3-stage x 1024 entries per tier
- Trig coefficients: Taylor series at arbitrary precision
- Prime table: 1,145 primes up to 10,000 (sieve of Eratosthenes)
Cross-Platform Determinism
- Bit-identical results across all architectures (x86, ARM, RISC-V)
- Zero floating-point contamination — f32/f64 forbidden in all internal logic
- Consensus-safe for blockchain, financial auditing, scientific reproducibility
Contributing
Contributions are welcome! Fork the repo, create a branch, and open a pull request. See CONTRIBUTING.md for development setup, code standards, and guidelines.
Bug reports and feature requests go to GitHub Issues.
Author
Niels Erik Toren
Support the Project
If gMath is useful to you, consider supporting its single dev by donating:
| Currency | Address |
|---|---|
| Bitcoin (BTC) | bc1qwf78fjgapt2gcts4mwf3gnfkclvqgtlg4gpu4d |
| Ethereum (ETH) | 0xf38b517Dd2005d93E0BDc1e9807665074c5eC731 |
| Monero (XMR) | 8BPaSoq1pEJH4LgbGNQ92kFJA3oi2frE4igHvdP9Lz2giwhFo2VnNvGT8XABYasjtoVY2Qb3LVHv6CP3qwcJ8UnyRtjWRZ5 |
Disclaimer
This software is provided "as is", without warranty of any kind, express or implied. Use of this library is entirely at your own risk. In no event shall the author or contributors be held liable for any damages, data loss, financial loss, or other consequences arising from the use or inability to use this software. By using gMath, you accept full responsibility for verifying its suitability for your use case.
See the license texts for the full legal terms.
License
Licensed under either of
at your option.