Skip to content

fractions Module Complexity

The fractions module provides support for rational number arithmetic, maintaining exact fractional values without floating-point rounding errors.

Complexity Reference

Operation Time Space Notes
Fraction() creation O(log n) O(1) GCD calculation via Euclidean algorithm, n = max(numerator, denominator)
Fraction arithmetic O(log n) O(1) GCD for result simplification
Fraction comparison O(1) O(1) Cross-multiplication (ad vs bc)
Fraction conversion O(log n) O(1) GCD for reduction
limit_denominator() O(k) O(1) k = max denominator

Basic Usage

Creating Fractions

from fractions import Fraction

# From integers - O(log n) for GCD
f1 = Fraction(3, 4)          # 3/4
f2 = Fraction(6, 8)          # Automatically reduces to 3/4
f3 = Fraction(2, 1)          # 2

# From string - O(log n) parsing and reduction
f4 = Fraction("1/3")         # 1/3
f5 = Fraction("0.25")        # 1/4

# From float - O(log n), may be imprecise
f6 = Fraction(0.5)           # 1/2
f7 = Fraction(0.1)           # 3602879701896397/36028797018963968 (approximation)

# From Decimal - O(log n)
from decimal import Decimal
f8 = Fraction(Decimal("0.25"))  # 1/4

# Copy - O(1)
f9 = Fraction(f1)            # 3/4

Properties

from fractions import Fraction

f = Fraction(7, 12)

# Numerator and denominator - O(1)
print(f.numerator)           # 7
print(f.denominator)         # 12

# Always in lowest terms
f2 = Fraction(14, 24)
print(f2.numerator)          # 7 (auto-reduced)
print(f2.denominator)        # 12

# Inverse - O(1)
f_inv = f.limit_denominator(1000)

Arithmetic Operations

Addition and Subtraction

from fractions import Fraction

f1 = Fraction(1, 2)  # 1/2
f2 = Fraction(1, 3)  # 1/3

# Addition - O(log n) for GCD and reduction
f3 = f1 + f2         # 5/6 (common denominator: 6)

# Subtraction - O(log n)
f4 = f1 - f2         # 1/6

# With integers - O(log n)
f5 = f1 + 2          # 5/2
f6 = 3 - f2          # 8/3

Multiplication and Division

from fractions import Fraction

f1 = Fraction(2, 3)  # 2/3
f2 = Fraction(3, 4)  # 3/4

# Multiplication - O(log n) for reduction
f3 = f1 * f2         # 6/12 = 1/2 (auto-reduced)

# Division - O(log n)
f4 = f1 / f2         # (2/3) / (3/4) = 8/9

# Power - O(log n) per multiplication
f5 = f1 ** 2         # 4/9
f6 = f2 ** -1        # 4/3 (reciprocal)

Modulo and Floor Division

from fractions import Fraction

f1 = Fraction(7, 2)  # 3.5
f2 = Fraction(2, 1)  # 2

# Floor division - O(log n)
result = f1 // f2    # 1 (7/2 // 2 = 1)

# Modulo - O(log n)
remainder = f1 % f2  # Fraction(3, 2) (1.5)

# Divmod - O(log n)
div, mod = divmod(f1, f2)
print(div)           # 1
print(mod)           # 3/2

Comparison Operations

Equality and Ordering

from fractions import Fraction

f1 = Fraction(1, 2)
f2 = Fraction(2, 4)  # Also 1/2
f3 = Fraction(1, 3)

# Equality - O(1) if already reduced (compares numerator and denominator)
print(f1 == f2)      # True (both 1/2)
print(f1 == f3)      # False

# Ordering - O(1) cross-multiplication comparison (a/b < c/d iff a*d < b*c)
print(f1 > f3)       # True (1/2 > 1/3)
print(f1 < f3)       # False
print(f1 <= f3)      # False

# With other types - may involve conversion
print(f1 == 0.5)     # True
print(f1 > 0.3)      # True

Conversion and Approximation

Convert to Other Types

from fractions import Fraction

f = Fraction(22, 7)  # π approximation

# To float - O(log n)
float_val = float(f)          # 3.142857...

# To int (floor division) - O(log n)
int_val = int(f)              # 3

# To string - O(log n)
str_val = str(f)              # '22/7'

# To tuple (numerator, denominator) - O(1)
num, denom = f.numerator, f.denominator

Limit Denominator

from fractions import Fraction

# Approximate with smaller denominator - O(k) where k = max_denominator
f = Fraction(22, 7)           # 22/7 ≈ 3.142857

# Limit to denominator 10
approx = f.limit_denominator(10)  # 22/7 (stays same)

# Limit to denominator 1 (nearest integer)
approx = Fraction(0.3).limit_denominator(1)  # 0/1

# Find simple fraction approximation
pi_approx = Fraction(3.14159).limit_denominator(100)
print(pi_approx)      # 355/113 (excellent π approximation)

# Approximate float
sqrt2 = Fraction(1.4142135623).limit_denominator(1000)
print(sqrt2)          # 1393/985

Common Patterns

Exact Decimal Computation

from fractions import Fraction

# Problem: floating-point arithmetic has rounding errors
prices = [0.1, 0.2, 0.3]
total_float = sum(prices)
print(total_float)    # 0.6000000000000001 (wrong!)

# Solution: use Fractions for exact arithmetic
prices_frac = [Fraction(1, 10), Fraction(2, 10), Fraction(3, 10)]
total_frac = sum(prices_frac)
print(total_frac)     # 3/5 (exact)
print(float(total_frac))  # 0.6

Continuous Fractions

from fractions import Fraction

def continued_fraction(value, depth=10):
    """Generate continued fraction representation"""

    coefficients = []
    x = Fraction(value)

    for _ in range(depth):
        a = int(x)
        coefficients.append(a)

        x = x - a
        if x == 0:
            break

        x = 1 / x

    return coefficients

# √2 continued fraction
sqrt2_cf = continued_fraction(1.41421356, depth=5)
print(sqrt2_cf)  # [1, 2, 2, 2, 2]

Rational Interpolation

from fractions import Fraction

class RationalFunction:
    """Simple rational function evaluation"""

    def __init__(self, numerator, denominator):
        self.num = numerator  # List of Fraction coefficients
        self.den = denominator

    def evaluate(self, x):
        """Evaluate at x - O(n) for polynomial evaluation"""

        # Evaluate numerator polynomial
        num_val = sum(
            coef * (x ** i)
            for i, coef in enumerate(self.num)
        )

        # Evaluate denominator polynomial
        den_val = sum(
            coef * (x ** i)
            for i, coef in enumerate(self.den)
        )

        # O(log n) for GCD reduction
        return Fraction(num_val, den_val)

# f(x) = (2x + 1) / (x - 1)
func = RationalFunction(
    [Fraction(1), Fraction(2)],      # numerator: 1 + 2x
    [Fraction(-1), Fraction(1)]      # denominator: -1 + x
)

result = func.evaluate(Fraction(3, 1))  # (1 + 6) / (3 - 1) = 7/2
print(result)  # 7/2

Performance Comparison

Fractions vs Float

from fractions import Fraction
import timeit

# Accumulation test
def test_float():
    result = 0.0
    for _ in range(1000):
        result += 0.1
    return result

def test_fraction():
    result = Fraction(0)
    for _ in range(1000):
        result += Fraction(1, 10)
    return result

# Float: faster, but inaccurate
float_result = test_float()
print(f"Float: {float_result}")  # 100.00000000000007

# Fraction: slower, but exact
frac_result = test_fraction()
print(f"Fraction: {frac_result}")  # 100

# Benchmark
float_time = timeit.timeit(test_float, number=1000)
frac_time = timeit.timeit(test_fraction, number=1000)

print(f"Float time: {float_time:.4f}s")      # Much faster
print(f"Fraction time: {frac_time:.4f}s")    # Slower

Denominator Representation Size

from fractions import Fraction

# Small denominators - fast
f1 = Fraction(1, 2)      # Small numbers
f2 = Fraction(1, 3)

result1 = f1 + f2        # O(log(small)) - fast
print(result1)           # 5/6

# Large denominators - slower
f3 = Fraction(1, 1000000)
f4 = Fraction(1, 999999)

result2 = f3 + f4        # O(log(large)) - slower
print(result2)           # 1999999/999999000000

Memory Efficiency

Denominator Growth

from fractions import Fraction

# Denominator can grow large with operations
f = Fraction(1, 2)

# After many operations
for _ in range(10):
    f = f + Fraction(1, 7)

print(f.denominator)  # Can become very large

# Denominator growth can be managed with limit_denominator
f_limited = f.limit_denominator(1000)
print(f_limited)      # Simplified approximation

When to Use Fractions

Good For

  • Financial calculations requiring exact arithmetic
  • Rational number mathematics
  • Avoiding floating-point errors in accumulation
  • Scientific computations with exact ratios
from fractions import Fraction

# Financial: exact currency operations
price1 = Fraction(10, 3)    # $3.33...
price2 = Fraction(20, 3)    # $6.66...
total = price1 + price2     # Exact $10

Avoid When

  • Performance-critical numerical code (use float)
  • Large-scale scientific computing (use NumPy)
  • Simple integer arithmetic
  • When floating-point precision is acceptable