Before a cricket match, the two captains meet at the centre of the pitch. The umpire flips a coin, and one captain calls "heads" or "tails" while it is still in the air. Nobody — not the umpire, not the captains, not the crowd — knows which way it will land. And yet, every player on the field has a rock-solid intuition about the situation: it's a fair fight, 50-50, either side is equally likely to win the call.
That intuition is probability. It is the branch of mathematics that takes situations where the outcome is uncertain and makes them precise — turning "maybe" and "probably" into an exact number. And it is not just a cricket-ground curiosity. Every time your phone shuffles a playlist, generates a 6-digit OTP for a UPI payment, deals cards in a mobile game of Ludo, or a spam filter decides whether an email is junk, there is a probability calculation running underneath. Computers use randomness and probability constantly — which means understanding probability is really the first step toward understanding how a huge class of software actually works. This chapter builds that understanding from the ground up: starting with coins and dice, and ending with the same ideas running inside real Python code.
From a coin toss to a "sample space"
Let's slow the coin toss down and describe it with precision. When you flip a fair coin, there are exactly two things that can happen: it lands heads, or it lands tails. In probability, we call the complete list of everything that can possibly happen the sample space, and we usually write it inside curly brackets:
Sample space for one coin toss = { Heads, Tails }
Each individual result inside that list — Heads, or Tails — is called an outcome. An event is any outcome (or group of outcomes) that we're actually interested in. "The coin lands heads" is an event made of exactly one outcome out of the two possible ones.
Now try a die instead of a coin — the kind you use in Ludo or Snakes and Ladders. Its sample space has six outcomes:
Sample space for one die roll = { 1, 2, 3, 4, 5, 6 }
Here, "the die shows an even number" is an event containing three outcomes out of six: {2, 4, 6}. Notice the pattern already forming — to talk about how likely an event is, we need to compare "how many outcomes make the event true" against "how many outcomes are possible in total." That comparison is the probability formula, and we're now ready to write it down properly.
The probability formula
For situations where every outcome is equally likely (a fair coin, an unbiased die, a well-shuffled deck), the probability of an event E is defined as:
P(E) = (number of outcomes favourable to E) / (total number of outcomes in the sample space)
Let's use it on a concrete, fully worked example. What is the probability of rolling an even number on a fair die?
- List the sample space: {1, 2, 3, 4, 5, 6}. Total outcomes = 6.
- List the outcomes that satisfy the event "even number": {2, 4, 6}. Favourable outcomes = 3.
- Apply the formula: P(even) = 3 / 6 = 1/2 = 0.5.
So there is a 0.5 (or 50%) chance of rolling an even number — exactly the same as the chance of rolling an odd number, which makes sense, since a die splits evenly between the two. Try a second one yourself before reading on: what is the probability of rolling a number greater than 4? The favourable outcomes are {5, 6}, so P = 2/6 = 1/3 ≈ 0.333, or about 33.3%.
Probability values always sit between two extremes. If an event can never happen — say, rolling a 7 on a standard die — it has 0 favourable outcomes, so P = 0/6 = 0. This is called an impossible event. If an event is guaranteed — rolling a number between 1 and 6 — every outcome is favourable, so P = 6/6 = 1. This is a certain event. Every probability you will ever calculate for a well-defined sample space is a number between 0 and 1 (or, as a percentage, between 0% and 100%). A "probability" of 1.4, or −0.2, is always a sign that something in the calculation went wrong — there's no such thing as more-than-certain or less-than-impossible.
Seeing the full sample space: two dice together
Single-die problems are simple enough to picture in your head, but many real problems involve combining outcomes from more than one source — two dice, a coin and a die, three attempts at a login PIN. The systematic way to handle this is to actually lay out every combined outcome in a grid, rather than trying to count in your head and risk missing some.
Consider rolling two dice together — Die A and Die B — and ask: what is the probability that the two numbers add up to exactly 7? There are 6 possible results for Die A and 6 for Die B, so by the multiplication counting principle there are 6 × 6 = 36 total equally-likely combined outcomes. The diagram below lays out all 36, with every combination summing to 7 highlighted.
Counting the highlighted cells: (1,6), (2,5), (3,4), (4,3), (5,2), and (6,1) — six outcomes out of 36 total. So P(sum = 7) = 6/36, which simplifies to 1/6 ≈ 0.167, or about 16.7%. Notice that this is the single most likely sum you can roll with two dice — every other total has fewer highlighted cells in its own diagonal (a sum of 2 or 12, for instance, has only one cell each: (1,1) and (6,6)). This is exactly why 7 is the number that shows up most often in dice games — not luck, but a straightforward outcome of how many ways there are to make it.
Independent events and the multiplication rule
What if two events don't happen in the same "round," but one after another — like tossing a coin and then separately rolling a die? These are called independent events: the result of one has zero effect on the result of the other. For independent events, the probability that both happen is simply the product of their individual probabilities:
P(A and B) = P(A) × P(B) [only valid when A and B are independent]
Worked example: what is the probability of tossing heads on a coin AND rolling a 6 on a die, in the same attempt?
- P(heads) = 1/2
- P(rolling a 6) = 1/6
- P(heads and 6) = 1/2 × 1/6 = 1/12 ≈ 0.083, or about 8.3%
This rule turns out to explain something you rely on every day without thinking about it: security through randomness. When a bank app asks for a 4-digit ATM PIN, there are 10 choices (0–9) for each of the 4 digits, so the total number of possible PINs is 10 × 10 × 10 × 10 = 10,000. If someone were guessing blindly, the probability of hitting your exact PIN on one attempt is 1/10,000 = 0.0001, or just 0.01%. A 6-digit UPI OTP has 10⁶ = 1,000,000 possible combinations, so a single blind guess succeeds with probability 1/1,000,000 — six times more digits doesn't just add security, it multiplies it, because each extra digit is an independent event being combined with all the others. This is precisely why OTPs got longer as digital payments grew: the multiplication rule is the mathematics behind that design decision.
Common misconception: "the die is due"
Here is a mistake even adults make constantly. Suppose you roll a die five times and get five 3s in a row — an unusual streak. Many people's gut instinct is: "the next roll is almost certainly not going to be a 3 — it's overdue for something else." This feeling is called the gambler's fallacy, and it is completely wrong.
Here's why: a fair die has no memory. Each roll is an independent event, exactly like the coin-and-die example above. The probability of rolling a 3 on the sixth roll is still exactly 1/6 — identical to what it was on roll one, two, three, four, and five. The die does not "know" it has produced four 3s already, and it does not adjust its behaviour to "balance out." The five previous 3s and the sixth roll are unrelated events, and P(A and B) = P(A) × P(B) only works precisely because independent events don't influence each other in either direction.
Where people go wrong is confusing two very different questions. "What is the probability of getting six 3s in a row, if I plan this in advance?" is genuinely tiny — (1/6)⁶ ≈ 0.0000214, less than 0.003%. But "given that I have already rolled five 3s, what is the probability the sixth is also a 3?" is just plain 1/6, because the first five rolls are no longer uncertain — they already happened. The rare event is the whole streak considered in advance, not any single roll considered after the fact. This same fallacy shows up in real life constantly: people believing a coin is "due" for tails after a heads streak, or that a slot machine that "hasn't paid out in a while" is more likely to pay out soon. It isn't — each play is independent of the last.
A second misconception: is your computer's "random" number really random?
When you shuffle a playlist, deal a hand of cards in a mobile game, or see random.randint(1, 6) in Python code, it feels like the computer is doing something like rolling a physical die. It is worth being precise about what's actually happening, because the honest answer surprises most students: ordinary computer "randomness" is not random at all — it is pseudo-random, produced by a completely deterministic algorithm called a Pseudo-Random Number Generator (PRNG).
A PRNG starts from a starting value called a seed, then runs a fixed mathematical formula over and over to churn out a long sequence of numbers that looks statistically random — passing every reasonable test for randomness — while being, underneath, 100% reproducible if you know the seed. Python's built-in random module uses an algorithm called the Mersenne Twister. Watch what happens when the seed is fixed:
import random
random.seed(42)
print([random.randint(1, 6) for _ in range(10)])
random.seed(42)
print([random.randint(1, 6) for _ in range(10)])
Running this produces:
[6, 1, 1, 6, 3, 2, 2, 2, 6, 1]
[6, 1, 1, 6, 3, 2, 2, 2, 6, 1]
The exact same sequence of "random" dice rolls came out twice, because both times the generator started from the identical seed (42) and ran the identical formula. That is the opposite of what a real die does — a real die genuinely doesn't produce the same sequence twice under the same starting conditions in any practical sense, but a PRNG algorithmically must, because it is just arithmetic. This is precisely why PRNGs are useful for testing and debugging (a bug that shows up with seed 42 will show up again every time you use seed 42, making it reproducible) but must never be used for anything security-critical on their own — banking systems and OTP generators use a separate class of algorithm called a Cryptographically Secure PRNG (CSPRNG), which pulls in unpredictable physical inputs (like tiny fluctuations in mouse movement, disk timing, or dedicated hardware noise) precisely so that the seed itself can't be guessed or reproduced by an attacker.
Experimental probability and the Law of Large Numbers
Everything calculated so far has been theoretical probability — reasoning about a fair die or coin using the formula, without actually rolling anything. Experimental probability, by contrast, is what you get by actually running trials and counting results:
Experimental P(E) = (number of times E actually occurred) / (total number of trials run)
A natural question: if you roll a real (or simulated) die thousands of times, does the experimental probability actually settle down near the theoretical value of 1/6? This code answers that directly by simulating 6,000 die rolls and tallying each face:
import random
random.seed(7)
counts = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
trials = 6000
for _ in range(trials):
roll = random.randint(1, 6)
counts[roll] += 1
for face in range(1, 7):
experimental_p = counts[face] / trials
print(face, counts[face], round(experimental_p, 4))
Running this actually produces:
1 1038 0.173
2 1020 0.17
3 1000 0.1667
4 969 0.1615
5 953 0.1588
6 1020 0.17
Every single face landed somewhere between about 0.159 and 0.173 — clustered tightly around the theoretical value of 1/6 ≈ 0.1667, even though no face hit that number exactly. This is not a coincidence; it is a real mathematical result called the Law of Large Numbers: as the number of independent trials grows, experimental probability converges toward theoretical probability. With only 6 rolls, getting all six faces exactly once each would be a fluke; with 6,000 rolls, the randomness of individual rolls averages out and the underlying 1/6 pattern becomes visible. This is exactly the principle behind Monte Carlo simulation — a technique used throughout computer science and engineering (from estimating financial risk to modelling how a rumour spreads on social media) where you simulate a random process thousands or millions of times on a computer specifically because running the real process (or solving it with pure algebra) is too expensive, slow, or impossible.
Counting sample spaces systematically: a card example
Dice and coins have small, easy-to-list sample spaces. A standard deck of playing cards has 52 — too many to picture instantly, so this is a good place to practise counting carefully rather than guessing. A deck has 4 suits (♠ spades, ♥ hearts, ♦ diamonds, ♣ clubs) with 13 cards each (13 × 4 = 52).
What is the probability of drawing a King from a well-shuffled deck? There is exactly one King per suit, and 4 suits, so there are 4 favourable outcomes out of 52 total: P(King) = 4/52 = 1/13 ≈ 0.077. What about drawing a red card (hearts or diamonds)? Two of the four suits are red, and each suit has 13 cards, so favourable outcomes = 26: P(red) = 26/52 = 1/2 — exactly what you'd expect, since the deck is split evenly between red and black. The recurring lesson across dice, coins, and cards is the same: identify the full sample space precisely, count how many outcomes satisfy your event precisely, and divide. Careless counting — miscounting the sample space, or double-counting favourable outcomes — is the single most common source of wrong answers in probability, far more often than the formula itself being misapplied.
Practice: test yourself before checking the answers
- A fair coin is tossed twice. List the full sample space, then find P(getting exactly one head).
- What is the probability of rolling a number less than 3 on a fair die?
- Using the two-dice grid from this chapter, find P(sum is 10 or more).
- A UPI app uses a 4-digit PIN. What is the probability that a random blind guess is correct on the very first try?
- You flip a fair coin 8 times and get heads every single time. What is the probability the 9th flip is heads? Explain why, in one sentence, using the term "independent event."
- Why does running a die-rolling simulation for 6,000 trials give results closer to the theoretical 1/6 than running it for just 6 trials?
- Explain the difference between a PRNG and true randomness in one or two sentences.
- From a standard 52-card deck, what is P(drawing an Ace or a King) in a single draw?
Answers: (1) Sample space {HH, HT, TH, TT}; P(exactly one head) = 2/4 = 1/2. (2) Favourable outcomes {1, 2}, so P = 2/6 = 1/3. (3) Sums of 10, 11, 12 — counting cells: sum=10 has 3 cells, sum=11 has 2 cells, sum=12 has 1 cell, total 6 cells, so P = 6/36 = 1/6. (4) 1/10,000 = 0.0001. (5) Still exactly 1/2 — each coin flip is an independent event, so the previous 8 outcomes have no influence on the 9th (this is the gambler's fallacy trap). (6) The Law of Large Numbers: more independent trials let random fluctuations average out, so the experimental probability converges toward the true theoretical probability. (7) A PRNG is a deterministic algorithm that produces a fixed, reproducible sequence of numbers from a starting seed — it only looks random; true randomness (used in security-critical CSPRNGs) draws from unpredictable physical sources that can't be reproduced even if you know the starting conditions. (8) 4 Aces + 4 Kings = 8 favourable outcomes out of 52, so P = 8/52 = 2/13 ≈ 0.154.
Summary
- A sample space is the complete list of every possible outcome; an event is any outcome or group of outcomes you care about.
- For equally likely outcomes, P(E) = (favourable outcomes) / (total outcomes), and this value always lies between 0 (impossible) and 1 (certain).
- When counting combined outcomes from two sources (two dice, a coin and a die), laying out the full grid systematically avoids missing or double-counting outcomes.
- For independent events, P(A and B) = P(A) × P(B) — this is the mathematics behind why longer PINs and OTPs are exponentially harder to guess.
- The gambler's fallacy is the mistaken belief that independent events "remember" past outcomes and self-correct — they don't; each trial keeps its own fixed probability regardless of history.
- Computer "randomness" from an ordinary PRNG (like Python's
randommodule) is actually a deterministic, reproducible algorithm driven by a seed — genuinely unpredictable randomness for security requires a separate CSPRNG built on real-world physical noise. - Experimental probability, measured by running many trials, converges toward theoretical probability as the number of trials grows — this is the Law of Large Numbers, and it's the foundation of Monte Carlo simulation used throughout computer science.