Rational — Arbitrary-Precision Rational Numbers

Overview

Rational is the arbitrary-precision rational number type in calx. Internally it stores a pair of (numerator Int, denominator Int), representing a value $x$ as:

$$x = \frac{p}{q}, \quad q > 0, \quad \gcd(p, q) = 1$$

The denominator is always positive, and the numerator and denominator are always kept in reduced form. A zero denominator is treated as NaN.

  • Arbitrary precision — Both numerator and denominator are Int, so there is no limit on the number of digits
  • Automatic reduction — After every operation, the result is reduced by GCD and kept in canonical form
  • NaN-safe — Division by zero returns NaN instead of crashing
  • Mixed operations with Int/int — Expressions like Rational + Int and Rational * int work naturally

Constructors

SignatureDescription
Rational()Default construction. Value is 0/1
Rational(int num, int den = 1)Construct from int numerator/denominator (automatically reduced)
Rational(const Int& num)Construct from Int (denominator = 1)
Rational(const Int& num, const Int& den, bool doReduce = true)Construct from Int numerator/denominator
Rational(Int&& num, Int&& den, bool doReduce = true)Move version
Rational(std::string_view str, int base = 10)Construct from string in "p/q" format
Rational(double value)Convert a double to an exact rational number
Rational(float value)Convert a float to an exact rational number
Rational(const Float& value)Convert a multi-precision float to an exact rational number

Specifying doReduce = false skips reduction (use when the caller guarantees the fraction is already in reduced form).

Accessors

Member FunctionDescription
const Int& numerator() constReturns the numerator
const Int& denominator() constReturns the denominator (always positive)
friend void swap(Rational& a, Rational& b) noexceptSwaps two Rational objects

Arithmetic Operators

Basic Arithmetic

OperatorDescription
Rational + RationalAddition ($\frac{a}{b} + \frac{c}{d} = \frac{ad+bc}{bd}$, reduced)
Rational - RationalSubtraction
Rational * RationalMultiplication ($\frac{a}{b} \times \frac{c}{d} = \frac{ac}{bd}$, reduced)
Rational / RationalDivision ($\frac{a}{b} \div \frac{c}{d} = \frac{ad}{bc}$, reduced)
Rational % RationalRemainder

Mixed operations with Int and int are fully supported:

  • Rational + Int, Int + Rational
  • Rational * int, int * Rational
  • Compound assignment: +=, -=, *=, /=

Code Example

Rational a(1, 3), b(1, 6);
Rational c = a + b;   // 1/2
Rational d = a * b;   // 1/18
Rational e = a / b;   // 2
Rational f = a - b;   // 1/6

Other Operations

OperationDescription
-rNegation
++r, r++Increment
--r, r--Decrement
r.pow(n)$r^n$ (int exponent)
pow(r, e)$r^e$ (Int exponent)
r << n$r \times 2^n$
r >> n$r / 2^n$

Comparison Operators

Supports C++20 three-way comparison (<=>). Returns std::partial_ordering (to account for NaN).

ComparisonDescription
Rational <=> RationalThree-way comparison
Rational == RationalEquality comparison
Rational <=> IntComparison with Int
Rational <=> intComparison with int

State Queries

Member FunctionDescription
isZero()Whether the value is 0
isNonZero()Whether the value is non-zero
isPositive()Whether the value is positive
isNegative()Whether the value is negative
isNonPositive()Whether the value is ≤ 0
isNonNegative()Whether the value is ≥ 0
isOne()Whether the value is 1
isInteger()Whether the denominator is 1 (i.e., an integer value)
isNaN()Whether the value is NaN
reduce()Manually reduce and normalize the fraction. Use this when you skipped reduction with doReduce=false in the constructor. Returns true if the value changed

Math Functions

FunctionDescription
abs(x)Absolute value $|x|$
inv(x)Reciprocal $1/x$
square(x)$x^2$
sgn(x)Sign ($-1, 0, 1$)
floor(x)$\lfloor x \rfloor$ (returns Int)
ceil(x)$\lceil x \rceil$ (returns Int)
trunc(x)Truncation toward zero (returns Int)
round(x)Rounding to nearest integer (returns Int)
frac(x)Fractional part $x - \lfloor x \rfloor$
height(x)Height $\max(|p|, |q|)$
gcd(x, y)GCD of rational numbers
mediant(a, b)Mediant $\frac{p_a + p_b}{q_a + q_b}$
r.doubled()$2r$
r.halved()$r/2$
r.reciprocal()Reciprocal $q/p$. $O(1)$. Reciprocal of zero returns NaN
conj(x)Conjugate (returns itself for real rationals; exists for compatibility with Complex<Rational>)

Continued Fractions

FunctionDescription
r.toContinuedFraction()Returns the continued fraction expansion $[a_0; a_1, a_2, \ldots]$
Rational::fromContinuedFraction(cf)Reconstructs a Rational from a continued fraction
Rational r(355, 113);
auto cf = r.toContinuedFraction();  // [3; 7, 16]
Rational r2 = Rational::fromContinuedFraction(cf);  // 355/113

Number-Theoretic Functions

FunctionDescription
harmonicNumber(n)Harmonic number $H_n = 1 + \frac{1}{2} + \cdots + \frac{1}{n}$
dedekindSum(h, k)Dedekind sum $s(h, k)$
reconstructRational(a, m, N, D)Reconstruct $p/q$ from $a \bmod m$ ($|p| \le N, 0 < q \le D$)
mod(x, m)Rational mod: $\frac{p}{q} \bmod m = p \cdot q^{-1} \bmod m$

Rational Enumeration

FunctionDescription
nextMinimal(x)Next positive rational in Stern-Brocot order
nextCalkinWilf(x)Next positive rational in the Calkin-Wilf sequence
fareyNeighbors(x, Q)Left and right neighbors in the Farey sequence $F_Q$
simplestBetween(a, b)Rational of smallest height in the open interval $(a, b)$

Mathematical Constants

The following constants are computed exactly as Rational values. Computed values are stored in a thread-safe static cache.

FunctionDescription
bernoulli(n)Bernoulli number $B_n$ (standard recurrence)
stirlingCoefficient(k)Stirling approximation coefficient $c_k$
Rational b0 = bernoulli(0);   // 1
Rational b1 = bernoulli(1);   // -1/2
Rational b2 = bernoulli(2);   // 1/6
Rational b4 = bernoulli(4);   // -1/30
Rational b6 = bernoulli(6);   // 1/42

Conversion

FunctionDescription
toDouble()Convert to double
toFloat()Convert to float
toMpFloat(precision)Convert to Float (with specified precision)
toString(base)String in "p/q" format
toDecimal(digits)Decimal string with specified number of digits
explicit operator int()Convert to int (truncated)
explicit operator double()Convert to double
Rational& operator=(double value)Assignment from double
Rational& operator=(float value)Assignment from float

Code Example

Rational r(22, 7);
double d = r.toDouble();       // 3.14285...
std::string s = r.toString();  // "22/7"
bool b = (Rational(1,3) < Rational(1,2));  // true

Stream I/O

Rational r(22, 7);
std::cout << r;  // Output: 22/7

Rational s;
std::cin >> s;   // Input: "3/4" -> Rational(3, 4)

Usage Example

#include <math/core/mp/Rational.hpp>
#include <iostream>
using namespace calx;

int main() {
    // Basic arithmetic (automatically reduced)
    Rational a(1, 3);   // 1/3
    Rational b(1, 6);   // 1/6
    std::cout << a + b << std::endl;  // 1/2

    // Bernoulli numbers
    for (int n = 0; n <= 10; n += 2)
        std::cout << "B(" << n << ") = " << bernoulli(n) << std::endl;

    // Continued fraction expansion
    Rational pi_approx(355, 113);
    auto cf = pi_approx.toContinuedFraction();  // [3; 7, 16]

    // Harmonic number
    Rational h10 = harmonicNumber(10);  // 7381/2520
    std::cout << "H(10) = " << h10 << " = " << h10.toDecimal(15) << std::endl;

    // NaN safety
    Rational nan = Rational(1, 0);
    std::cout << nan << std::endl;  // NaN
}