🐍 Python

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.

🐍 Pythonmath_constants.py
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.

FunctionBehaviourExample InputResult
math.ceil(x)Rounds UP to the nearest integer, regardless of signmath.ceil(4.1)5
math.ceil(x) — negativeStill rounds toward positive infinitymath.ceil(-4.1)-4
math.floor(x)Rounds DOWN to the nearest integer, regardless of signmath.floor(4.9)4
math.floor(x) — negativeStill rounds toward negative infinitymath.floor(-4.1)-5
math.trunc(x)Discards the decimal part entirely (rounds toward zero)math.trunc(-4.9)-4
round(x) — built-in, not math moduleRounds to nearest, ties to even (banker's rounding)round(2.5)2
🐍 Pythonrounding_functions.py
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.

FunctionComputesExampleResult
math.sqrt(x)Square root of xmath.sqrt(64)8.0
math.pow(x, y)x raised to the power y (always returns a float)math.pow(2, 10)1024.0
math.exp(x)e raised to the power xmath.exp(1)2.718281828459045
math.log(x)Natural logarithm (base e) of xmath.log(math.e)1.0
math.log(x, base)Logarithm of x with a custom basemath.log(8, 2)3.0
math.log2(x)Base-2 logarithm (more precise than log(x, 2))math.log2(1024)10.0
math.log10(x)Base-10 logarithm (more precise than log(x, 10))math.log10(1000)3.0
math.isqrt(x)Integer square root, floor of the true root (ints only)math.isqrt(50)7
🐍 Pythonpower_log_functions.py
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().

▶️ Call math.sqrt(x)Or log, asin, acos, etc.
checks
❓ Is x within valid domain?e.g. x >= 0 for sqrt
valid
✅ Compute resultReturns a float
returns normally
🚫 Raise ValueError'math domain error'
propagates
🛠️ Caught by except ValueError?Depends on your code
caught
🏁 Handled gracefullyProgram continues
💥 Unhandled — program crashesTraceback printed

Code Execution Flow — from source to output

🐍 Pythondomain_error_example.py
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.

FunctionPurposeExampleResult
math.sin(x)Sine of x radiansmath.sin(math.pi / 2)1.0
math.cos(x)Cosine of x radiansmath.cos(0)1.0
math.tan(x)Tangent of x radiansmath.tan(math.pi / 4)0.9999999999999999
math.asin(x)Arcsine — returns radiansmath.asin(1)1.5707963267948966
math.acos(x)Arccosine — returns radiansmath.acos(1)0.0
math.atan(x)Arctangent — returns radiansmath.atan(1)0.7853981633974483
math.atan2(y, x)Arctangent of y/x, correctly handling all quadrantsmath.atan2(1, 1)0.7853981633974483
math.degrees(x)Converts radians to degreesmath.degrees(math.pi)180.0
math.radians(x)Converts degrees to radiansmath.radians(180)3.141592653589793
🐍 Pythontrig_functions.py
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.0

math.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.

🐍 Pythonnan_inf_checks.py
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.

FunctionComputesExampleResultSince
math.factorial(n)n! (n factorial)math.factorial(5)120Always available
math.comb(n, k)Number of ways to choose k items from n (order doesn't matter)math.comb(5, 2)10Python 3.8+
math.perm(n, k)Number of ways to arrange k items from n (order matters)math.perm(5, 2)20Python 3.8+
math.gcd(a, b, ...)Greatest common divisor of two or more integersmath.gcd(48, 18)6Multi-arg since 3.9
math.lcm(a, b, ...)Least common multiple of two or more integersmath.lcm(4, 6)12Python 3.9+
🐍 Pythoncombinatorics_functions.py
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.

Aspectmath (standard library)cmath (standard library)numpy (third-party)
Number types supportedint and float onlyComplex numbersArrays, ints, floats, complex numbers
Installation required?No — built inNo — built inYes — pip install numpy
Works on single values or arrays?Single values onlySingle values onlyVectorized — whole arrays at once
Performance on large datasetsRequires a Python loop — slowRequires a Python loop — slowHighly optimized, often 10-100x faster
sqrt(-1) behaviourRaises ValueErrorReturns 1j (a complex number)Returns nan with a runtime warning by default
Typical use caseSimple scripts, single calculationsSignal processing, complex-number mathData science, scientific computing, ML
Dependency weightNone — always availableNone — always availableAdds a real external dependency

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.

Constants
math.pi, math.e, math.taumath.inf, math.nan
Rounding & Truncation
math.ceil, math.floormath.trunc
Power & Logarithms
math.sqrt, math.isqrt, math.powmath.exp, math.log, math.log2, math.log10
Trigonometry
sin, cos, tan, asin, acos, atan, atan2degrees, radians
Combinatorics & Number Theory
factorial, comb, permgcd, lcm
Special Value Checks
isnan, isinf, isfiniteisclose

Architecture Diagram

Practice: A Small Geometry Toolkit Using math

This example combines constants, power functions, and trigonometry into a small, realistic geometry utility.

🐍 Pythongeometry_toolkit.py
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.0

Output

5.0 314.1592653589793 45.0

Practice 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.

✅ Advantages
Zero Installation RequiredPart of the standard library, available in every Python installation with a single import — no pip install needed.
Fast, C-Implemented FunctionsBecause math functions call directly into the underlying C library, they are significantly faster than equivalent pure-Python implementations.
Covers Nearly Every Common OperationRounding, logarithms, trigonometry, combinatorics, and special-value checks are all covered without needing any external dependency.
Precise Dedicated FunctionsFunctions like math.log2(), math.isqrt(), and math.isclose() exist specifically to avoid subtle floating-point precision pitfalls.
Predictable, Well-Documented BehaviourEvery function's domain and behaviour on edge cases is clearly documented, making it reliable for production use.
❌ Disadvantages
No Support for Complex Numbersmath.sqrt(-1) raises ValueError; you must switch to the separate cmath module for any complex-number work.
No Vectorized OperationsEvery function operates on a single value at a time; processing large datasets requires slow Python-level loops compared to numpy's array operations.
Radians-Only Trigonometry Trips Up BeginnersForgetting to convert degrees to radians before calling sin/cos/tan is one of the most common math-module mistakes.
Domain Errors Can Crash Unhandled CodeFunctions like sqrt and log raise ValueError outside their valid domain, which can crash a program if not explicitly caught.
Floating-Point Precision Limits ApplyLike all binary floating-point arithmetic, results can carry tiny rounding errors that require careful handling with isclose() rather than direct equality.

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)?

Medium

2. What does math.gcd(0, 5) return, and why?

Medium

3. Why does print(math.sqrt(2) ** 2 == 2) print False?

Hard

4. What is the correct way to check if a computed float value is a valid, usable number (not NaN and not infinite)?

Medium

5. What is math.factorial(0), and why is this the mathematically correct answer?

Easy

6. Why might math.log(1000, 10) return 2.9999999999999996 instead of exactly 3.0?

Hard

7. What does math.perm(5, 0) return, and why?

Medium

8. 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?

Easy

Conclusion — 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.

SituationRecommended Tool
Single real-number calculation in a script✅ math module
Square root or log of a negative number✅ cmath module
Processing thousands of values at once✅ numpy (vectorized operations)
Comparing two floats for 'equality'✅ math.isclose(), never ==
Checking for an undefined float result✅ math.isnan() / math.isfinite()
Exact integer square root of a huge number✅ math.isqrt(), not int(math.sqrt(x))
Trigonometry with a degree-based input✅ Convert first with math.radians()

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.

Frequently Asked Questions (FAQ)