Skip to content

Add fractions module: Rational number arithmetic #16

@youknowone

Description

@youknowone

Summary

Port Python's fractions.Fraction to Rust — arbitrary-precision rational number arithmetic.

In CPython, this is a pure Python implementation (Lib/fractions.py) that internally stores a (numerator: int, denominator: int) pair, GCD-normalized with a positive denominator.

Design

Type representation

pub struct Fraction<I> {
    numerator: I,
    denominator: I,  // always positive, coprime with numerator
}

Follow the existing _bigint feature pattern to support both num-bigint and malachite-bigint. Implement as generic over integer type or via trait bounds.

Feature flag

[features]
fractions = ["_bigint"]  # requires BigInt

Same pattern as cmath behind the complex feature.

Implementation plan

Phase 1: Core struct & construction

  • Fraction struct (numerator, denominator)
  • GCD normalization (sign normalization included: denominator always positive)
  • new(numerator, denominator) — primary constructor
  • from_integer(n) — construct from integer
  • from_float(f64) — using f64::integer_decode() or as_integer_ratio logic
  • from_coprime_ints(n, d) — direct construction from pre-normalized values (internal use)
  • String parsing: "3/4", "1.5", "1e-2", etc.

Phase 2: Arithmetic operations

  • Add, Sub, Mul, Div (Rust traits)
  • Neg, Abs
  • Floor division, modulo, divmod
  • Pow — integer exponent returns Fraction / non-integer returns f64

Arithmetic optimization: Knuth TAOCP 4.5.1 approach (pre-compute GCD in multiplication to avoid unnecessary blowup)

Phase 3: Comparison & conversion

  • Eq, Ord (cross-multiply comparison)
  • as_f64() — float conversion
  • trunc(), floor(), ceil(), round() — integer conversions
  • is_integer() — checks denominator == 1
  • as_integer_ratio() — returns (numerator, denominator) tuple

Phase 4: Special methods

  • limit_denominator(max_denominator) — best rational approximation via continued fraction algorithm
  • Hash: compatible with Python's _hash_algorithm (modular inverse based)
  • Display: "{numerator}/{denominator}" or "{numerator}" when integer
  • Format: float-style formatting (.2f, e, g, etc.)

Phase 5: Testing

  • Use the existing pyo3 proptest pattern from the project
  • Verify bit-identical results against fractions.Fraction
  • Edge cases: zero, negatives, very large numbers, float precision boundary values

Out of scope

  • Python numbers.Rational ABC (replaced by Rust traits)
  • Direct conversion with Decimal type (separate module scope)
  • Pickle/copy (Python runtime dependent)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions