Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nonanti/mathcore/llms.txt

Use this file to discover all available pages before exploring further.

Floating-point arithmetic accumulates rounding errors that are invisible until they cause real problems — a financial calculation that is off by a cent, a symbolic result that should be exactly 1/2 but prints as 0.49999999999. MathCore’s precision module solves this by providing PrecisionNumber, a three-variant enum that represents numbers as exact integers (BigInt), exact rationals (BigRational), or floating-point values — and the ArbitraryPrecision struct for computing transcendental constants to as many digits as you need.

Import

use mathcore::precision::{PrecisionNumber, ArbitraryPrecision};

PrecisionNumber

#[derive(Debug, Clone)]
pub enum PrecisionNumber {
    Exact(BigRational),   // exact rational: numerator / denominator
    Float(f64),           // floating-point fallback
    Integer(BigInt),      // exact integer
}
Operations between same-kind variants stay in that variant. Mixed-kind operations are automatically promoted to Exact(BigRational) so no precision is lost.

Construction

PrecisionNumber::from_str_with_precision(s: &str) -> Result<PrecisionNumber, MathError>

Parses a string into the most precise representation available:
Input formatResult variantExample
Plain integerInteger(BigInt)"42"Integer(42)
Rational n/dExact(BigRational)"1/3"Exact(1/3)
DecimalExact(BigRational)"0.25"Exact(1/4)
Other floatFloat(f64)"3.14"Float(3.14)
use mathcore::precision::PrecisionNumber;

let one_third  = PrecisionNumber::from_str_with_precision("1/3").unwrap();
let one_sixth  = PrecisionNumber::from_str_with_precision("1/6").unwrap();
let quarter    = PrecisionNumber::from_str_with_precision("0.25").unwrap();
let large_int  = PrecisionNumber::from_str_with_precision("99999999999999999999").unwrap();
Decimal strings like "2.5" are stored as BigRational (5/2), not f64. This means subsequent arithmetic on them remains exact.

PrecisionNumber::from_f64(value: f64) -> PrecisionNumber

Converts an f64 to a PrecisionNumber. If the value has no fractional part and is finite, it is stored as Integer; otherwise as Float.
let n = PrecisionNumber::from_f64(7.0);  // Integer(7)
let f = PrecisionNumber::from_f64(1.5);  // Float(1.5)

Arithmetic Methods

All arithmetic methods return a new PrecisionNumber; the originals are not mutated. Mixed-variant operations are promoted to Exact automatically.

add(&other) -> PrecisionNumber

let a = PrecisionNumber::from_str_with_precision("1/3").unwrap();
let b = PrecisionNumber::from_str_with_precision("1/6").unwrap();
let sum = a.add(&b);
println!("1/3 + 1/6 = {}", sum); // 1/2

subtract(&other) -> PrecisionNumber

let a = PrecisionNumber::from_str_with_precision("3/4").unwrap();
let b = PrecisionNumber::from_str_with_precision("1/4").unwrap();
let diff = a.subtract(&b);
println!("3/4 - 1/4 = {}", diff); // 1/2

multiply(&other) -> PrecisionNumber

let a = PrecisionNumber::from_str_with_precision("2/3").unwrap();
let b = PrecisionNumber::from_str_with_precision("3/4").unwrap();
let product = a.multiply(&b);
println!("2/3 × 3/4 = {}", product); // 1/2

divide(&other) -> Result<PrecisionNumber, MathError>

Division by zero returns Err(MathError::DivisionByZero).
let a = PrecisionNumber::from_str_with_precision("1/2").unwrap();
let b = PrecisionNumber::from_str_with_precision("1/4").unwrap();
let quotient = a.divide(&b).unwrap();
println!("(1/2) / (1/4) = {}", quotient); // 2

power(&exponent) -> Result<PrecisionNumber, MathError>

  • Integer ^ Integer (non-negative exponent): returns Integer
  • Integer ^ negative Integer: returns Exact (1/base^|exp|)
  • All others: promotes to Float
let base = PrecisionNumber::from_str_with_precision("2").unwrap();
let exp  = PrecisionNumber::from_str_with_precision("10").unwrap();
let result = base.power(&exp).unwrap();
println!("2^10 = {}", result); // 1024

factorial() -> Result<PrecisionNumber, MathError>

Computes exact factorial for non-negative integers. Returns Err for negative or non-integer inputs. Handles arbitrarily large values — 100! is computed exactly.
let n = PrecisionNumber::from_str_with_precision("20").unwrap();
let fact = n.factorial().unwrap();
println!("20! = {}", fact); // 2432902008176640000

sqrt() -> Result<PrecisionNumber, MathError>

Returns Integer if the result is a perfect square, otherwise Float.

Conversion Methods

to_rational() -> BigRational

Converts any variant to BigRational. For Float, uses BigRational::from_float (may lose precision for irrational floats).
let n = PrecisionNumber::from_str_with_precision("3/7").unwrap();
let r: num_rational::BigRational = n.to_rational();
println!("numerator:   {}", r.numer());
println!("denominator: {}", r.denom());

to_f64() -> Option<f64>

Returns the value as an f64, or None if the number is too large to represent.

is_zero() -> bool

Returns true for integer zero, rational zero, or a Float within f64::EPSILON of zero.

ArbitraryPrecision

ArbitraryPrecision is a unit struct that provides static methods for computing well-known constants using rational series.

ArbitraryPrecision::compute_pi(precision: usize) -> PrecisionNumber

Computes π using the Bailey-Borwein-Plouffe (BBP) formula, summing precision terms of the series:
π = Σ_{k=0}^{∞} (1/16)^k · (4/(8k+1) − 2/(8k+4) − 1/(8k+5) − 1/(8k+6))
Each term is computed as a BigRational, so the result is an Exact rational approximation. More terms produce a more accurate rational.
use mathcore::precision::ArbitraryPrecision;

let pi = ArbitraryPrecision::compute_pi(50);
println!("π ≈ {}", pi);

// As f64 for comparison
use mathcore::precision::PrecisionNumber;
if let Some(pi_f64) = pi.to_f64() {
    println!("π ≈ {:.15}", pi_f64);
}
The precision argument is the number of BBP series terms, not the number of decimal digits. Roughly 15–20 terms are sufficient to exceed f64 precision. Use larger values (e.g. 100+) for applications requiring many significant figures.

ArbitraryPrecision::compute_e(precision: usize) -> PrecisionNumber

Computes Euler’s number e via the Taylor series Σ_^ 1/n!:
let e = ArbitraryPrecision::compute_e(30);
println!("e ≈ {}", e);

ArbitraryPrecision::compute_sqrt(n: &BigInt, precision: usize) -> PrecisionNumber

Computes the integer square root of n using Newton’s method with precision iterations. Returns Integer for perfect squares, otherwise the closest integer approximation.

Full Example

use mathcore::precision::{PrecisionNumber, ArbitraryPrecision};

fn main() {
    // --- Exact rational arithmetic ---
    let a = PrecisionNumber::from_str_with_precision("1/3").unwrap();
    let b = PrecisionNumber::from_str_with_precision("1/6").unwrap();
    let sum = a.add(&b);
    println!("1/3 + 1/6 = {}", sum); // 1/2

    let c = PrecisionNumber::from_str_with_precision("2.5").unwrap();
    let d = PrecisionNumber::from_str_with_precision("3.7").unwrap();
    let product = c.multiply(&d);
    println!("2.5 × 3.7 = {}", product); // 185/20 = 37/4

    // --- Large integer factorial ---
    let n = PrecisionNumber::from_str_with_precision("50").unwrap();
    let fact = n.factorial().unwrap();
    println!("50! = {}", fact);

    // --- Constants ---
    let pi = ArbitraryPrecision::compute_pi(100);
    println!("π ≈ {}", pi);

    let e = ArbitraryPrecision::compute_e(30);
    println!("e ≈ {}", e);
}

Use Cases

Financial calculations — avoid the classic 0.1 + 0.2 ≠ 0.3 trap:
let price    = PrecisionNumber::from_str_with_precision("19.99").unwrap();
let tax_rate = PrecisionNumber::from_str_with_precision("1/10").unwrap(); // 10%
let tax      = price.multiply(&tax_rate);
let total    = price.add(&tax);
println!("Total: {}", total); // exact rational
Symbolic results — keep fractions symbolic until the last moment:
let two_thirds = PrecisionNumber::from_str_with_precision("2/3").unwrap();
let three_halves = PrecisionNumber::from_str_with_precision("3/2").unwrap();
let result = two_thirds.multiply(&three_halves);
println!("{}", result); // 1  (exact, not 0.9999999...)
Scientific precision — compute physical constants with sufficient terms:
let pi = ArbitraryPrecision::compute_pi(200);
// Use in downstream exact computations

Performance Note

BigInt and BigRational arithmetic is significantly slower than f64. For Integer values, multiplication of two n-digit numbers takes O(n²) time with the current implementation (no Karatsuba or FFT multiplication). Reserve PrecisionNumber for calculations where correctness is more important than throughput — financial ledgers, symbolic proofs, constant generation — and use f64 for performance-critical numerical work.

Build docs developers (and LLMs) love