Python math Module — Complete Guide
A complete, professional guide to Python's built-in math module — constants, rounding, power and logarithm functions, trigonometry, combinatorics, and special-value handling for NaN and infinity.
Last Updated
March 2026
Read Time
27 min
Level
Intermediate
What is the math Module in Python?
The math module is one of Python's built-in standard library modules, providing access to the underlying C library's mathematical functions — square roots, logarithms, trigonometry, rounding, factorials, and a set of useful mathematical constants. Because it's part of the standard library, it requires no installation: a single import math statement at the top of any script makes the entire module available.
Unlike Python's built-in arithmetic operators (+, -, *, /, **), which work directly on numbers without any import, the math module exists for the specialized mathematical operations that aren't built into the language's core syntax — things like computing a square root, converting degrees to radians, or checking whether a floating-point number is actually valid. These functions are implemented in C for speed and operate almost exclusively on int and float values, deliberately excluding complex numbers (which live in the separate cmath module instead).
The math module is organized into a handful of clear functional groups: constants (pi, e, infinity), rounding and truncation functions, power and logarithm functions, trigonometric and hyperbolic functions, combinatorics (factorial, combinations, permutations), and special-value checks for NaN and infinity. Understanding these groups makes the module far easier to navigate than memorizing its roughly 50 individual functions one at a time.
Mathematical Constants in the math Module
The math module defines several precomputed constants as module-level attributes, accurate to the full precision of a Python float, saving you from hardcoding approximate values yourself.
import math
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.tau) # 6.283185307179586 (2 * pi, since Python 3.6)
print(math.inf) # inf (positive infinity)
print(-math.inf) # -inf (negative infinity)
print(math.nan) # nan (Not a Number)- ▶
math.pi — The ratio of a circle's circumference to its diameter, used constantly in geometry and trigonometry.
- ▶
math.e — Euler's number, the base of the natural logarithm, central to exponential growth and calculus.
- ▶
math.tau — Equal to 2π, representing one full turn in radians; introduced as a convenience for code that works in full-circle terms rather than half-circle terms.
- ▶
math.inf — A float representing positive infinity; useful as a starting 'worst case' value when searching for a minimum, since any real number compares as smaller than it.
- ▶
math.nan — Represents an undefined or unrepresentable numeric result ('Not a Number'); notably, nan is never equal to itself, so math.nan == math.nan evaluates to False.
Rounding and Truncation Functions
Python's built-in round() function handles common rounding, but the math module provides more precise directional control — always rounding up, always rounding down, or simply discarding the decimal part entirely.
import math
print(math.ceil(4.1)) # 5
print(math.ceil(-4.1)) # -4
print(math.floor(4.9)) # 4
print(math.floor(-4.1)) # -5
print(math.trunc(4.9)) # 4
print(math.trunc(-4.9)) # -4
# Note: math.ceil() and math.floor() always return an int, not a float,
# unlike Python's built-in round() which can return either depending on usage.A key distinction worth remembering: math.trunc() and math.floor() behave identically for positive numbers, but diverge for negative ones — trunc always moves toward zero, while floor always moves toward negative infinity.
Power and Logarithm Functions
While Python's ** operator handles basic exponentiation, the math module provides dedicated, faster functions for square roots and general power operations, along with a full family of logarithm functions.
import math
print(math.sqrt(64)) # 8.0
print(2 ** 0.5) # 1.4142135623730951 (built-in ** also works)
print(math.isqrt(50)) # 7 (exact integer floor of sqrt(50), no float rounding)
print(math.pow(2, 10)) # 1024.0 (always a float)
print(2 ** 10) # 1024 (built-in ** preserves int type)
print(math.log(100, 10)) # 1.9999999999999998 (small float imprecision!)
print(math.log10(100)) # 2.0 (dedicated function avoids that imprecision)The dedicated math.log2() and math.log10() functions exist specifically because computing those same logarithms via the general two-argument math.log(x, base) form can accumulate tiny floating-point rounding errors — using the specialized functions when you know the base in advance avoids this subtle imprecision entirely. Similarly, math.isqrt() (added in Python 3.8) computes an exact integer square root without ever converting through a float, avoiding precision loss for very large integers that math.sqrt() would introduce.
Handling Domain Errors in math Functions — Flowchart
Many math module functions have a restricted domain — a set of valid inputs outside of which the function is mathematically undefined. Calling them outside that domain raises a ValueError rather than silently returning something like NaN. This flowchart shows the decision process for a typical domain-restricted call like math.sqrt().
Code Execution Flow — from source to output
import math
try:
math.sqrt(-16)
except ValueError as e:
print(f"Cannot compute: {e}") # Cannot compute: math domain error
# For negative square roots, use the cmath module instead:
import cmath
print(cmath.sqrt(-16)) # 4j (a complex number)Trigonometric and Angle Conversion Functions
All of the math module's trigonometric functions work in radians, not degrees — a common source of confusion for beginners coming from contexts where degrees are the default. The module provides conversion helpers specifically to bridge this gap.
import math
angle_degrees = 90
angle_radians = math.radians(angle_degrees)
print(math.sin(angle_radians)) # 1.0
# atan2 is preferred over atan for real-world coordinate math,
# because it correctly determines the angle's quadrant from
# separate x and y values, avoiding division-by-zero issues.
print(math.atan2(1, 0)) # 1.5707963267948966 (90 degrees, straight up)
print(math.degrees(math.atan2(1, 0))) # 90.0math.atan2(y, x) deserves special attention: unlike plain math.atan(y/x), it takes the y and x coordinates as two separate arguments, which lets it correctly determine which quadrant the resulting angle falls in (something a single division ratio alone cannot express) and safely handles the case where x is zero, which a plain division would raise ZeroDivisionError on.
Handling NaN and Infinity Safely
Floating-point arithmetic can produce two special, non-ordinary values: NaN (Not a Number, resulting from undefined operations like 0/0 in float context) and infinity (resulting from overflow or explicit use of math.inf). The math module provides dedicated functions to check for these, because they behave in surprising, non-intuitive ways under normal comparison operators.
import math
x = float('nan')
print(x == x) # False! NaN is never equal to itself
print(math.isnan(x)) # True — the correct way to check for NaN
y = float('inf')
print(y > 10 ** 100) # True
print(math.isinf(y)) # True
# Comparing floats for 'equality' is unreliable due to precision errors:
a = 0.1 + 0.2
print(a == 0.3) # False! (0.30000000000000004)
print(math.isclose(a, 0.3)) # True — the correct way to compare floats- ▶
math.isnan(x)— Returns True if x is NaN. Never use x == float('nan') or x == x, since NaN famously does not equal itself under IEEE 754 rules. - ▶
math.isinf(x)— Returns True if x is positive or negative infinity. - ▶
math.isfinite(x)— Returns True if x is neither NaN nor infinite — i.e. a genuinely 'normal' finite number. - ▶
math.isclose(a, b, rel_tol=1e-9)— Returns True if two floats are approximately equal within a relative tolerance, correctly accounting for the tiny rounding errors inherent to binary floating-point representation.
Factorial, Combinations, and GCD/LCM
The math module also includes several integer-focused functions common in combinatorics, number theory, and probability calculations — many added or improved in recent Python versions.
import math
print(math.factorial(5)) # 120 (5 * 4 * 3 * 2 * 1)
print(math.comb(5, 2)) # 10 (ways to CHOOSE 2 from 5, order irrelevant)
print(math.perm(5, 2)) # 20 (ways to ARRANGE 2 from 5, order matters)
print(math.gcd(48, 18)) # 6
print(math.lcm(4, 6)) # 12
print(math.gcd(12, 18, 24)) # 6 (works with more than 2 arguments too)Before Python 3.8, developers had to compute combinations and permutations manually using factorial arithmetic (math.factorial(n) // (math.factorial(k) * math.factorial(n - k)) for combinations); math.comb() and math.perm() now provide these directly, are more efficient, and avoid the risk of overflow-related intermediate values in the manual formula.
math vs cmath vs numpy — Which Should You Use?
Python offers three different tools for mathematical work, each suited to a different scale and type of problem.
The general rule of thumb: reach for math for everyday, single-value calculations in ordinary scripts; reach for cmath specifically when your problem genuinely involves complex numbers (like square roots of negative numbers or certain signal-processing formulas); and reach for numpy once you're operating on entire arrays or large datasets of numbers at once, where its vectorized operations dramatically outperform looping over the math module function by function.
How the math Module Is Organized
Rather than memorizing all ~50 functions individually, it helps to think of the math module as six functional categories, each addressing a distinct kind of numeric problem.
Practice: A Small Geometry Toolkit Using math
This example combines constants, power functions, and trigonometry into a small, realistic geometry utility.
import math
def distance(x1, y1, x2, y2):
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
def circle_area(radius):
return math.pi * radius ** 2
def angle_between(x1, y1, x2, y2):
radians = math.atan2(y2 - y1, x2 - x1)
return math.degrees(radians)
print(distance(0, 0, 3, 4)) # 5.0
print(circle_area(10)) # 314.1592653589793
print(angle_between(0, 0, 1, 1)) # 45.0Output
5.0 314.1592653589793 45.0Practice This Code — Live Editor
Best Practices for Using the math Module
These practices help you use the math module correctly and avoid common floating-point pitfalls.
- ▶
Never compare floats with == — use math.isclose() instead — Binary floating-point representation makes exact equality unreliable; math.isclose() correctly accounts for small rounding errors.
- ▶
Use math.isnan() to check for NaN, never x == x — NaN famously does not equal itself under IEEE 754 rules, so equality checks silently give the wrong answer.
- ▶
Remember trigonometric functions expect radians, not degrees — Convert with math.radians() before calling sin/cos/tan if your input is in degrees, and math.degrees() to convert results back.
- ▶
Prefer math.log2()/math.log10() over math.log(x, base) when the base is known — The dedicated functions avoid tiny floating-point imprecision that the general two-argument form can introduce.
- ▶
Use math.isqrt() instead of int(math.sqrt(x)) for large integers — math.sqrt() converts through a float, which can lose precision for very large integers; math.isqrt() computes the exact integer result directly.
- ▶
Wrap domain-restricted calls in try/except ValueError — Functions like sqrt, log, and asin raise ValueError ('math domain error') outside their valid input range; handle this explicitly rather than letting it crash unexpectedly.
- ▶
Reach for math.atan2(y, x) over math.atan(y/x) for coordinate angles — atan2 correctly handles all four quadrants and avoids a ZeroDivisionError when x is zero.
- ▶
Switch to numpy once you're processing many values at once — Looping over the math module function by function across a large dataset is far slower than numpy's vectorized equivalents.
Advantages and Disadvantages of the math Module
The math module is fast and always available, but it has real, deliberate limitations compared to more specialized numeric tools.
Python math Module — Interview Questions
Frequently asked interview questions about the math module, floating-point behaviour, and common numeric pitfalls.
Practice Questions — Test Your Understanding
Work through these practice questions on the math module. Try to predict the output before checking the answer.
1. What is the output of math.ceil(-3.2) and math.floor(-3.2)?
Medium2. What does math.gcd(0, 5) return, and why?
Medium3. Why does print(math.sqrt(2) ** 2 == 2) print False?
Hard4. What is the correct way to check if a computed float value is a valid, usable number (not NaN and not infinite)?
Medium5. What is math.factorial(0), and why is this the mathematically correct answer?
Easy6. Why might math.log(1000, 10) return 2.9999999999999996 instead of exactly 3.0?
Hard7. What does math.perm(5, 0) return, and why?
Medium8. If you need to compute the square root of a negative number in a physics simulation involving complex impedance, which module should you use, and why?
EasyConclusion — Using the math Module Effectively
The math module is one of the most quietly essential parts of Python's standard library — a compact, fast, always-available toolkit covering everything from simple rounding to trigonometry to combinatorics. Its real value isn't just in providing these functions, but in providing precise, well-documented, edge-case-aware versions of them: dedicated log2/log10 functions to avoid precision drift, isqrt to avoid float rounding on large integers, isclose to correctly compare imprecise floats, and clear domain-error exceptions instead of silently wrong results.
The habits worth carrying forward: always work in radians for trigonometry (converting with radians()/degrees() as needed), always compare floats with math.isclose() rather than ==, always check for NaN with math.isnan() rather than equality, and know when to graduate from the math module to cmath (complex numbers) or numpy (vectorized, large-scale numeric work) as your problem's needs grow beyond single real-number calculations.
From here, natural next topics include the statistics module (mean, median, standard deviation, and other descriptive statistics built on top of similar principles), the random module for probability and simulation work, and numpy fundamentals for anyone moving toward data science or scientific computing where vectorized numeric operations become essential.