0%

54- math & random Modules

Mathematical functions, constants, and random number generation. From basic arithmetic to complex trigonometry. From simple randomness to cryptographically secure secrets.

Numbers are the heart of programming. You have used basic arithmetic: addition, subtraction, multiplication, division. But sometimes you need more. Square roots, logarithms, trigonometric functions. Random numbers, shuffling, weighted choices. Python’s math and random modules provide these capabilities. The math module gives you mathematical functions and constants. The random module gives you pseudo-random number generation for simulations, games, and testing. This lesson covers both modules together because they are often used side by side. You will learn to calculate square roots, generate random integers, shuffle lists, and work with mathematical constants like π and e.

🕯️ Magic Note

The math module is implemented in C and is highly optimized. For most mathematical operations, using math functions is faster than writing your own Python equivalents. Trust the standard library.

The math Module: Constants
The math module provides important mathematical constants.

Python

import math

# Basic constants

print(f”π (pi) = {math.pi}”)

print(f”e = {math.e}”)

print(f”τ (tau, 2π) = {math.tau}”)

# Infinity and NaN

print(f”Infinity: {math.inf}”)

print(f”Negative Infinity: {-math.inf}”)

print(f”Not a Number: {math.nan}”)

# Checking special values

print(f”Is inf inf? {math.isinf(math.inf)}”)

print(f”Is nan nan? {math.isnan(math.nan)}”)

print(f”Is 42 finite? {math.isfinite(42)}”)

math: Rounding and Number Manipulation
Functions for rounding, ceiling, floor, and absolute values.

Python

import math

num = 3.7

print(f”ceil({num}) = {math.ceil(num)}”) # 4 (rounds UP)

print(f”floor({num}) = {math.floor(num)}”) # 3 (rounds DOWN)

print(f”trunc({num}) = {math.trunc(num)}”) # 3 (removes decimal, toward zero)

negative = -3.7

print(f”ceil({negative}) = {math.ceil(negative)}”) # -3

print(f”floor({negative}) = {math.floor(negative)}”) # -4

# Rounding to nearest integer (built-in round)

print(f”round(3.7) = {round(3.7)}”) # 4

print(f”round(3.2) = {round(3.2)}”) # 3

# Absolute value

print(f”fabs({negative}) = {math.fabs(negative)}”) # 3.7 (float version of abs)

print(f”abs({negative}) = {abs(negative)}”) # 3.7 (built-in)

# Modf: separate integer and fractional parts

fractional, integer = math.modf(3.7)

print(f”3.7 -> integer: {integer}, fractional: {fractional}”)

# Copysign: copy sign from one number to another

print(f”copysign(5, -3) = {math.copysign(5, -3)}”) # -5.0

💡 Use ceil() and floor() for integer rounding in a specific direction. Use round() for conventional rounding (halves round to nearest even).
math: Powers, Roots, and Logarithms
Exponentiation, square roots, cube roots, and logarithmic functions.

Python

import math

# Powers and roots

print(f”pow(2, 3) = {math.pow(2, 3)}”) # 8.0 (float)

print(f”2 ** 3 = {2 ** 3}”) # 8 (integer)

print(f”sqrt(16) = {math.sqrt(16)}”) # 4.0

print(f”cbrt(27) = {math.cbrt(27)}”) # 3.0 (cube root, Python 3.11+)

# Hypotenuse (Euclidean distance)

print(f”hypot(3, 4) = {math.hypot(3, 4)}”) # 5.0 (sqrt(3² + 4²))

print(f”hypot(3, 4, 5) = {math.hypot(3, 4, 5)}”) # 7.07 (multiple dimensions)

# Logarithms

print(f”log(e²) = {math.log(math.e ** 2)}”) # 2.0 (natural log, base e)

print(f”log10(1000) = {math.log10(1000)}”) # 3.0 (base 10)

print(f”log2(8) = {math.log2(8)}”) # 3.0 (base 2)

print(f”log(100, 10) = {math.log(100, 10)}”) # 2.0 (custom base)

# Exponential

print(f”exp(2) = {math.exp(2)}”) # e² ≈ 7.389

print(f”expm1(2) = {math.expm1(2)}”) # e² – 1 (more accurate for small values)

print(f”log1p(2) = {math.log1p(2)}”) # log(1 + 2)

🕯️ Magic Note

For integer exponentiation, the built-in ** operator is faster than math.pow() and returns an integer. Use math.pow() when you want a float result.

math: Trigonometric Functions
Trigonometric functions for angles in radians.

Python

import math

# Angle conversion

degrees = 60

radians = math.radians(degrees)

print(f”{degrees}° = {radians} radians”)

print(f”{radians} radians = {math.degrees(radians)}°”)

# Basic trig functions

angle = math.radians(30)

print(f”sin(30°) = {math.sin(angle)}”) # 0.5

print(f”cos(60°) = {math.cos(math.radians(60))}”) # 0.5

print(f”tan(45°) = {math.tan(math.radians(45))}”) # 1.0

# Inverse trig functions

print(f”asin(0.5) = {math.degrees(math.asin(0.5))}°”) # 30°

print(f”acos(0.5) = {math.degrees(math.acos(0.5))}°”) # 60°

print(f”atan(1) = {math.degrees(math.atan(1))}°”) # 45°

# atan2 (y, x) – returns angle from origin to point (x, y)

print(f”atan2(1, 1) = {math.degrees(math.atan2(1, 1))}°”) # 45°

print(f”atan2(-1, -1) = {math.degrees(math.atan2(-1, -1))}°”) # -135°

# Hyperbolic functions

print(f”sinh(1) = {math.sinh(1)}”)

print(f”cosh(1) = {math.cosh(1)}”)

print(f”tanh(1) = {math.tanh(1)}”)

💡 The math.atan2(y, x) function is preferred over math.atan(y/x) because it handles the quadrant correctly and avoids division by zero.
math: Other Useful Functions
Additional mathematical utilities.

Python

import math

# Factorial

print(f”5! = {math.factorial(5)}”) # 120

print(f”10! = {math.factorial(10)}”) # 3628800

# Combinations and permutations

print(f”C(5, 2) = {math.comb(5, 2)}”) # 10 (choose 2 from 5)

print(f”P(5, 2) = {math.perm(5, 2)}”) # 20 (permutations)

# Greatest common divisor (GCD)

print(f”gcd(12, 18) = {math.gcd(12, 18)}”) # 6

print(f”gcd(100, 35) = {math.gcd(100, 35)}”) # 5

# Least common multiple (LCM, Python 3.9+)

print(f”lcm(12, 18) = {math.lcm(12, 18)}”) # 36

# Is close (floating point comparison)

a = 0.1 + 0.2

b = 0.3

print(f”0.1 + 0.2 == 0.3? {a == b}”) # False

print(f”isclose(0.1+0.2, 0.3)? {math.isclose(a, b)}”) # True

# Degree and radian conversion

print(f”radians(180) = {math.radians(180)}”) # π

print(f”degrees(π) = {math.degrees(math.pi)}”) # 180.0

🕯️ Magic Note

math.isclose() is the safe way to compare floating point numbers. It accounts for tiny rounding errors that accumulate in floating point arithmetic.

The random Module: Basic Random Numbers
Generate pseudo-random numbers for simulations, games, and testing.

Python

import random

# Random floats

print(f”Random [0.0, 1.0): {random.random()}”)

print(f”Random [0.0, 5.0): {random.uniform(0, 5)}”)

# Random integers

print(f”Random integer [1, 100]: {random.randint(1, 100)}”)

print(f”Random integer range [0, 100) step 10: {random.randrange(0, 100, 10)}”)

# Choosing random elements

colors = [“red”, “green”, “blue”, “yellow”, “purple”]

print(f”Random choice: {random.choice(colors)}”)

print(f”Multiple choices (with replacement): {random.choices(colors, k=3)}”)

print(f”Multiple choices (without replacement): {random.sample(colors, k=3)}”)

# Weighted choices

items = [“rare”, “uncommon”, “common”]

weights = [0.1, 0.3, 0.6]

print(f”Weighted choice: {random.choices(items, weights=weights, k=5)}”)

⚠️ The random module is suitable for simulations and games, but NOT for security (passwords, tokens, cryptography). Use secrets for security-critical applications.
random: Shuffling and Seeding
Shuffle sequences and control reproducibility with seeds.

Python

import random

# Seeding (for reproducible randomness)

random.seed(42)

print(f”Deterministic random 1: {random.randint(1, 100)}”)

print(f”Deterministic random 2: {random.randint(1, 100)}”)

# Reset seed to get same sequence again

random.seed(42)

print(f”Same sequence again: {random.randint(1, 100)}”)

# Get current internal state (for saving/restoring)

state = random.getstate()

print(f”Current random: {random.random()}”)

random.setstate(state)

print(f”Same random again: {random.random()}”)

# Shuffling sequences (in place)

cards = list(range(1, 11))

print(f”Original: {cards}”)

random.shuffle(cards)

print(f”Shuffled: {cards}”)

# Create a shuffled copy (without modifying original)

original = [1, 2, 3, 4, 5]

shuffled = random.sample(original, len(original))

print(f”Original: {original}”)

print(f”Shuffled copy: {shuffled}”)

🕯️ Magic Note

Setting the random.seed() is essential for reproducibility. In data science, set a seed so others can reproduce your results. In games, use a seed to generate consistent random worlds.

random: Distributions
Generate numbers from various statistical distributions.

Python

import random

# Normal (Gaussian) distribution

mean = 0

std_dev = 1

print(f”Normal distribution: {random.gauss(mean, std_dev)}”)

# Triangular distribution

print(f”Triangular (0, 10, 5): {random.triangular(0, 10, 5)}”)

# Exponential distribution

print(f”Exponential: {random.expovariate(1.0)}”)

# Beta distribution

print(f”Beta(2, 5): {random.betavariate(2, 5)}”)

# Gamma distribution

print(f”Gamma(1, 2): {random.gammavariate(1, 2)}”)

Practical Examples Combined
Real-world examples using both math and random together.

Python

import math

import random

# Example 1: Monte Carlo simulation for π

def estimate_pi(num_points=100000):

inside_circle = 0

for _ in range(num_points):

x = random.uniform(-1, 1)

y = random.uniform(-1, 1)

if x*x + y*y <= 1:

inside_circle += 1

return 4 * inside_circle / num_points

print(f”Estimated π: {estimate_pi(100000)}”)

print(f”Actual π: {math.pi}”)

# Example 2: Random point on a sphere (uniform distribution)

def random_point_on_sphere(radius=1):

theta = random.uniform(0, 2 * math.pi)

phi = math.acos(2 * random.random() – 1)

x = radius * math.sin(phi) * math.cos(theta)

y = radius * math.sin(phi) * math.sin(theta)

z = radius * math.cos(phi)

return (x, y, z)

print(f”Random point on sphere: {random_point_on_sphere()}”)

# Example 3: Random password generator

import string

def random_password(length=12):

characters = string.ascii_letters + string.digits + “!@#$%&*”

return “”.join(random.choice(characters) for _ in range(length))

print(f”Random password: {random_password()}”)

# Example 4: Distance between two random points

p1 = (random.uniform(0, 10), random.uniform(0, 10))

p2 = (random.uniform(0, 10), random.uniform(0, 10))

distance = math.hypot(p1[0] – p2[0], p1[1] – p2[1])

print(f”Distance between {p1} and {p2}: {distance:.2f}”)

Common Mistakes with math and random
  • Using random for security-critical applications (use secrets)
  • Comparing floats with == instead of math.isclose()
  • Forgetting that random.random() returns a number in [0.0, 1.0) (not inclusive of 1.0)
  • Using math.pow() when ** is more appropriate for integers
  • Not seeding random for reproducibility when needed
  • Forgetting to convert degrees to radians for trig functions
Check Your Understanding
  • How do you generate a random integer between 1 and 10 inclusive?
  • What function would you use to safely compare two floating point numbers?
  • Write code that shuffles a list of strings randomly.
  • How do you calculate the square root of a number?
  • What is the difference between random.choice() and random.sample()?
  • Why should you set a random seed when developing simulations?

⚡ Whisper

Numbers dance to your command with math and random. The square root awaits. The logarithm listens. π and e stand ready. Random numbers spill from an endless well. The module does the heavy lifting. It calculates in C, faster than you can blink. You do not need to implement your own sine function or random generator. You import math and random. Then the power is yours. Simulations become possible. Games become interesting. Data science becomes practical. The math module gives you precision. The random module gives you chance. Together, they give you the tools to model, simulate, and explore. Use them wisely. Respect floating point imprecision. Compare with isclose(). Seed your random for reproducibility. Keep secrets secure with the secrets module. And remember: the standard library is vast. Before writing a mathematical function yourself, check if math already has it. Often, it does. And it is better than anything you would write. Trust it. Use it. Create.

Related posts