math, random & statistics

Three standard-library modules cover most everyday numeric needs: math for rounding, roots, logarithms and trigonometry; random for simulations, games and sampling; and statistics for averages and spread. (For security-sensitive randomness, there's secrets.)

The math module

PY math_basics.py
import math

print(math.floor(4.7), math.ceil(4.2), math.trunc(-4.7))
print(math.sqrt(144), math.isqrt(150), math.cbrt(27))
print(math.pow(2, 10), 2 ** 10)
print(math.factorial(6), math.comb(5, 2), math.perm(5, 2))
print(math.gcd(48, 18), math.lcm(4, 6))
print(math.prod([1, 2, 3, 4]), math.fsum([0.1] * 10))
Output
4 5 -4
12.0 12 3.0
1024.0 1024
720 10 20
6 12
24 1.0
  • floor rounds down, ceil rounds up, trunc drops the decimal part (towards zero).
  • isqrt is the exact integer square root; comb and perm count combinations and permutations.
  • fsum adds floats more accurately than sum — sum([0.1] * 10) gives 0.9999999999999999.

Constants, logs and trigonometry

PY math_more.py
import math

print(round(math.pi, 5), round(math.e, 5), math.inf > 1e308)
print(math.log(math.e), math.log10(1000), math.log2(1024), math.log(8, 2))

angle = math.radians(30)
print(round(math.sin(angle), 3), round(math.degrees(math.atan2(1, 1)), 1))
print(math.hypot(3, 4), math.dist((0, 0), (6, 8)))
print(math.isclose(0.1 + 0.2, 0.3), math.isnan(float("nan")))
Output
3.14159 2.71828 True
1.0 3.0 10.0 3.0
0.5 45.0
5.0 10.0
True True

Trigonometric functions work in radians — convert with radians() and degrees(). Always compare floats with isclose(), not ==.

Random numbers

PY random_basics.py
import random

random.seed(42)

print(random.random())
print(random.randint(1, 6))
print(random.uniform(1.5, 2.5))
print(random.randrange(0, 100, 10))
print(random.choice(["rock", "paper", "scissors"]))
Output
0.6394267984578837
1
2.241550499759833
30
rock
FunctionReturns
random()Float in [0.0, 1.0)
randint(a, b)Integer from a to b, both included
uniform(a, b)Float between a and b
randrange(start, stop, step)Like range, but one random value
choice(seq)One random item

random.seed(42) makes the sequence repeatable — the same seed always produces the same "random" numbers, which is invaluable for tests and reproducible simulations.

Shuffling and sampling

PY sampling.py
import random

random.seed(7)
deck = list(range(1, 11))

random.shuffle(deck)
print(deck)
print(random.sample(range(1, 50), 6))
print(random.choices(["win", "lose"], weights=[1, 9], k=10).count("win") <= 10)
Output
[9, 4, 2, 5, 8, 1, 10, 7, 3, 6]
[33, 14, 3, 6, 28, 27]
True
  • shuffle reorders a list in place.
  • sample(population, k) picks k different items (like drawing lottery numbers).
  • choices(population, weights, k) picks k items with replacement, optionally weighted.

A quick simulation

PY simulation.py
import random

random.seed(2026)
trials = 100_000
sixes = sum(1 for _ in range(trials) if random.randint(1, 6) == 6)
print(f"Rolled a six {sixes / trials:.1%} of the time (expected 16.7%)")
Output
Rolled a six 16.5% of the time (expected 16.7%)

secrets: randomness for security

The random module is predictable by design and must never be used for passwords, tokens or anything security-related. Use secrets instead:

PY secrets_demo.py
import secrets
import string

token = secrets.token_urlsafe(16)
alphabet = string.ascii_letters + string.digits
password = "".join(secrets.choice(alphabet) for _ in range(12))

print(len(token) > 16, len(password))
Output
True 12

The statistics module

PY stats.py
import statistics as st

scores = [72, 88, 95, 61, 88, 79, 84]

print(st.mean(scores), st.median(scores), st.mode(scores))
print(round(st.stdev(scores), 2), round(st.pstdev(scores), 2))
print(st.quantiles(scores, n=4))
print(round(st.correlation([1, 2, 3, 4], [2, 4, 5, 9]), 3))
Output
81 84 88
11.46 10.61
[72.0, 84.0, 88.0]
0.965

stdev is the sample standard deviation and pstdev the population version. For heavier number-crunching on large arrays, NumPy is much faster — see the NumPy course.

Try it yourself

Try it yourself
Console output