Exact numbers: Rational, sqrt, pi

SymPy · Essentials · 9 min

Exactness is the reason to use a CAS; one stray float silently turns exact results into approximations.

SymPy has its own number types: Integer, Rational and arbitrary-precision Float, plus exact constants pi, E, I (the imaginary unit) and oo (infinity). Exact numbers stay exact: Rational(1, 3) + Rational(1, 6) is 1/2, and sqrt(8) is automatically rewritten as 2*sqrt(2).

The classic trap is Python division. In x + 1/2, Python evaluates 1/2 to the float 0.5 before SymPy ever sees it, so the expression contains a Float. Fixes:

  • Rational(1, 2), or S(1)/2: S(1) is SymPy's Integer(1), and dividing a SymPy integer by a Python int gives a Rational.
  • x/2 is fine because the symbol is on the left of the operator.
  • S("1/3") or sympify("1/3") parse a string exactly.

Floats are contagious: once a Float is in an expression, results involving it are approximate, and simplification has less to work with. Float itself carries a precision, so Float("0.1", 30) is more precise than the binary float 0.1.

Exact constants are symbolic objects: pi is not 3.14159..., it is the number pi. sin(pi) evaluates to 0 exactly, whereas math.sin(math.pi) gives 1.2246e-16. Convert to a decimal only at the end, with evalf() or N().

Example

from sympy import Rational, S, sqrt, pi, sin, symbols
import math

x = symbols("x")
print(x + 1/2)                         # x + 0.5   (a Python float sneaked in)
print(x + Rational(1, 2))              # x + 1/2
print(x + S(1)/2, x/2)                 # x + 1/2 x/2
print(Rational(1, 3) + Rational(1, 6)) # 1/2
print(sqrt(8), sqrt(2)**2)             # 2*sqrt(2) 2
print(sin(pi), math.sin(math.pi))      # 0 1.2246467991473532e-16
print(pi.evalf(30))                    # 3.14159265358979323846264338328

Remember

  • Rational(1, 2) or S(1)/2, never 1/2, for exact fractions
  • sqrt, pi, E, I and oo are exact symbolic objects
  • Convert to decimals only at the end

Watch out for

  • Writing Rational(0.1) and getting 3602879701896397/36028797018963968: pass a string or two ints instead.

Check yourself

  1. Which expression contains a Float?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.sympy.org/latest/tutorials/intro-tutorial/gotchas.html