Skip to content

Python SymPy: How to Work with Continued Fractions in SymPy in Python

Learn how to use SymPy's continued fraction functions to convert rational numbers, generate optimal rational approximations for irrational values like π and √2, and analyze periodic patterns in square roots.

Continued fractions represent numbers through nested divisions, revealing optimal rational approximations and exposing hidden mathematical structures. For irrational numbers like pi or the square root of 2, continued fractions provide the "best" fractional approximations with the smallest possible denominators. Python's SymPy library offers a complete toolkit for converting between representations, computing convergents, and analyzing periodic patterns in square roots.

This guide covers every major function in SymPy's continued fraction module, from basic conversions to finding the best rational approximation for any real number.

Converting Rational Numbers to Continued Fractions

The continued_fraction() function converts a rational number into its continued fraction representation, returned as a list of integers:

from sympy import Rational
from sympy.ntheory.continued_fraction import continued_fraction

cf = continued_fraction(Rational(10, 7))
print(cf)

cf2 = continued_fraction(Rational(45, 16))
print(cf2)

Output:

[1, 2, 3]
[2, 1, 4, 3]

Each integer in the list represents a level of the nested fraction. The first element is the whole number part, and the remaining elements describe the successive reciprocals.

Converting Back to Fractions

Use continued_fraction_reduce() to convert a continued fraction list back into a rational number:

from sympy import Rational
from sympy.ntheory.continued_fraction import (
    continued_fraction,
    continued_fraction_reduce
)

cf_list = [1, 2, 3]
fraction = continued_fraction_reduce(cf_list)
print(f"[1, 2, 3] -> {fraction}")

original = Rational(355, 113)
cf = continued_fraction(original)
reconstructed = continued_fraction_reduce(cf)
print(f"{original} -> {list(cf)} -> {reconstructed}")

Output:

[1, 2, 3] -> 10/7
355/113 -> [3, 7, 16] -> 355/11

The round-trip conversion is exact. Any rational number can be converted to a continued fraction and back without any loss of precision.

Finding Convergents for Irrational Numbers

Convergents are the successive rational approximations that result from truncating a continued fraction at each step. They approach the true value more and more closely. For pi, these convergents reveal famous fractions like 22/7 and 355/113:

from sympy import pi
from sympy.ntheory.continued_fraction import (
    continued_fraction_iterator,
    continued_fraction_convergents
)

cf_iterator = continued_fraction_iterator(pi)

convergents = continued_fraction_convergents(cf_iterator)

approximations = [next(convergents) for _ in range(6)]

for approx in approximations:
    error = abs(float(approx) - float(pi))
    print(f"  {str(approx):>10}  =  {float(approx):.10f}  (error: {error:.2e})")

Output:

           3  =  3.0000000000  (error: 1.42e-01)
        22/7  =  3.1428571429  (error: 1.26e-03)
     333/106  =  3.1415094340  (error: 8.32e-05)
     355/113  =  3.1415929204  (error: 2.67e-07)
  103993/33102  =  3.1415926530  (error: 5.78e-10)
  104348/33215  =  3.1415926539  (error: 3.32e-10)

Periodic Continued Fractions for Square Roots

Square roots of non-perfect-square integers always produce periodic (repeating) continued fractions. SymPy can identify this repeating pattern using continued_fraction_periodic():

from sympy.ntheory.continued_fraction import continued_fraction_periodic


roots = [2, 3, 5, 7, 13]

for n in roots:
    result = continued_fraction_periodic(0, 1, n)
    print(f"  sqrt({n:>2}) = {result}")

Output:

  sqrt( 2) = [1, [2]]
  sqrt( 3) = [1, [1, 2]]
  sqrt( 5) = [2, [4]]
  sqrt( 7) = [2, [1, 1, 1, 4]]
  sqrt(13) = [3, [1, 1, 1, 1, 6]]

The first element is the integer part. The list inside the brackets is the repeating portion. For example, the square root of 2 has a continued fraction of [1, 2, 2, 2, 2, ...] where the 2 repeats forever.

The function parameters represent the form (a + b * sqrt(c)). For a simple square root of n, use continued_fraction_periodic(0, 1, n).

Generating Approximations for Square Roots

You can combine the continued fraction iterator with the convergent generator to produce rational approximations for any square root:

from sympy import sqrt
from sympy.ntheory.continued_fraction import (
    continued_fraction_iterator,
    continued_fraction_convergents
)

sqrt2_iter = continued_fraction_iterator(sqrt(2))
sqrt2_convergents = continued_fraction_convergents(sqrt2_iter)

actual = float(sqrt(2))

print("Rational approximations for sqrt(2):")
for i, approx in enumerate(sqrt2_convergents):
    if i >= 8:
        break
    error = abs(float(approx) - actual)
    print(f"  {str(approx):>12}  =  {float(approx):.10f}  (error: {error:.2e})")

Output:

Rational approximations for sqrt(2):
             1  =  1.0000000000  (error: 4.14e-01)
           3/2  =  1.5000000000  (error: 8.58e-02)
           7/5  =  1.4000000000  (error: 1.42e-02)
         17/12  =  1.4166666667  (error: 2.45e-03)
         41/29  =  1.4137931034  (error: 4.20e-04)
         99/70  =  1.4142857143  (error: 7.22e-05)
       239/169  =  1.4142011834  (error: 1.24e-05)
       577/408  =  1.4142156863  (error: 2.12e-06)

Each convergent is the best possible rational approximation with a denominator of that size or smaller.

Practical Application: Best Rational Approximation with a Denominator Limit

A common practical problem is finding the best rational approximation to a value where the denominator cannot exceed a certain limit. Convergents make this straightforward:

from sympy import pi, E, sqrt
from sympy.ntheory.continued_fraction import (
    continued_fraction_iterator,
    continued_fraction_convergents
)

def best_approximation(value, max_denominator):
    """Find the best rational approximation within a denominator limit."""
    cf_iter = continued_fraction_iterator(value)
    convergents = continued_fraction_convergents(cf_iter)

    best = None
    for approx in convergents:
        if approx.q > max_denominator:
            break
        best = approx

    return best


approx_pi = best_approximation(pi, 1000)
print(f"Best pi approximation (denom <= 1000): {approx_pi}")
print(f"  Value:    {float(approx_pi):.10f}")
print(f"  Actual:   {float(pi):.10f}")

print()

approx_e = best_approximation(E, 100)
print(f"Best e approximation (denom <= 100):  {approx_e}")
print(f"  Value:    {float(approx_e):.10f}")
print(f"  Actual:   {float(E):.10f}")

Output:

Best pi approximation (denom <= 1000): 355/113
  Value:    3.1415929204
  Actual:   3.1415926536

Best e approximation (denom <= 100):  193/71
  Value:    2.7183098592
  Actual:   2.7182818285

Function Reference

Function Purpose Example
continued_fraction() Convert a rational to a CF list continued_fraction(Rational(22, 7))
continued_fraction_reduce() Convert a CF list back to a rational continued_fraction_reduce([3, 7, 15])
continued_fraction_iterator() Create an iterator for infinite CFs continued_fraction_iterator(pi)
continued_fraction_convergents() Generate successive approximations Wraps an iterator from above
continued_fraction_periodic() Find the periodic CF for square roots continued_fraction_periodic(0, 1, 5)

Summary

SymPy's continued fraction module provides exact symbolic tools for working with one of the most powerful representations in number theory.

  • Use continued_fraction() and continued_fraction_reduce() for exact round-trip conversion of rational numbers.
  • Use continued_fraction_iterator() paired with continued_fraction_convergents() to generate successively better rational approximations of any real number, including irrational constants like pi and e.
  • Use continued_fraction_periodic() to discover the repeating patterns in the continued fractions of square roots.
  • Always use Rational() instead of Python float division to prevent rounding errors from corrupting your results.
Navigation