A Practical Guide to the Inclusion-Exclusion Principle
You reach for the inclusion-exclusion principle when you need the size of a union of sets, and direct counting gets messy fast. It is one of those tools that looks simple on paper and then becomes a pain to manage when you actually have five or six sets to deal with. Here is how it works, where it breaks, and what to do instead when the formula stops being useful. The formal name is the inclusion-exclusion principle. It is a counting method that starts by adding the sizes of individual sets, subtracts the sizes of all pairwise intersections, adds back in the triple intersections, subtracts the quadruple intersections, and continues alternating until you have accounted for every possible overlap. The basic formula for two sets is straightforward: |A B| = |A| + |B| - |A B|. For three sets it expands to |A B C| = |A| + |B| + |C| - |A B| - |A C| - |B C| + |A B C|. Each additional set doubles the number of terms you need to compute, which is the first thing that trips people up.
I remember working through a problem a few years back where I needed to count valid identifiers in a system using five different exclusion rules. The naive application required computing all 31 non-empty subset intersections. I had the individual set sizes and the pairwise intersections, but the triple, quadruple, and quintuple intersections were not stored anywhere. I ended up switching to a recursive decomposition approach where I split the problem into smaller subproblems and only computed the intersections I actually needed. That cut the work from something exponential to roughly linear in the number of elements involved. The key insight most people miss is that inclusion-exclusion is not primarily a calculation tool. It is a structural framework. The real value shows up when you use it to derive generating functions, compute probabilities in urn problems, or prove identities. When you are just trying to get a number for two or three sets, direct counting or a Venn diagram often gets you there faster. Here is a common pitfall. People assume that computing all the intersection terms is always the bottleneck, but in practice the bottleneck is almost always deciding what those intersections actually represent in your problem domain. A combinatorics problem about coloring a grid is very different from a probability problem about overlapping events, even though the formula looks identical. You have to translate the set-theoretic structure into something you can actually compute before you write down a single term.
Another thing nobody warns you about is numerical stability. If you are working with large sets and floating point arithmetic, the alternating sum can suffer from catastrophic cancellation. You add huge numbers, subtract almost equally huge numbers, and the result loses precision. I ran into this when computing the probability that a random permutation has at least one fixed point across several overlapping event classes. The individual terms were on the order of 10^6, the final answer was around 0.632, and I was losing digits with every subtraction. Switching to arbitrary precision arithmetic or reformulating the problem as 1 minus the probability of no matches (which is the derangement formula) completely sidestepped the issue.
Get the Full Details

When To Use It And When To Walk Away
Two or three sets with known intersection sizes. This is the sweet spot. You can write it out by hand and verify each term without losing track. Four or five sets is manageable if your sets have a lot of structure you can exploit, like disjointness or nesting. Beyond that, you should probably look for an alternative. If your sets are nested, inclusion-exclusion still works but it is overkill. Use the chain rule for probabilities or simple subset relations instead. If your sets are independent in a probabilistic sense, multiply the complements and subtract from one. That gives you the union probability directly without any intersection terms. I once tried to apply inclusion-exclusion to a data deduplication problem with roughly forty feature vectors that could overlap in arbitrary ways. The formula would have required computing 2^40 - 1 intersection terms. That is not a practical approach. I switched to a min-hash based sketching method, which gave me an approximate Jaccard similarity across all pairs in roughly O(nk) time where k is the number of hash functions. The answer was good enough for the use case, and it ran in minutes instead of requiring a server cluster.
A Worked Example
Let us say you want to count integers between 1 and 1000 that are divisible by at least one of 2, 3, or 5. You define A as multiples of 2, B as multiples of 3, and C as multiples of 5 within that range. |A| = floor(1000/2) = 500. |B| = floor(1000/3) = 333. |C| = floor(1000/5) = 200. |A B| = floor(1000/6) = 166. |A C| = floor(1000/10) = 100. |B C| = floor(1000/15) = 66. |A B C| = floor(1000/30) = 33. The union is 500 + 333 + 200 - 166 - 100 - 66 + 33 = 764. So 764 integers in that range are divisible by at least one of those three numbers. You can verify this by brute force in a script, and it matches.
The formula generalizes cleanly to any number of sets. For n sets, you sum over all non-empty subsets S of {1, 2, ..., n}, and each term has sign (-1)^(|S|-1) multiplied by the size of the intersection of the sets indexed by S. It is exact, not approximate, and it works regardless of how the sets overlap.

Advanced Nuances
One useful variation is the probabilistic form. If you are working with events rather than set sizes, the same alternating sum applies to probabilities. P(A1 A2 ... An) = P(Ai) - P(Ai Aj) + P(Ai Aj Ak) - ... This is especially handy in reliability engineering and queueing theory. There is also a connection to the Möbius function on the lattice of subsets. If you view the power set ordered by inclusion as a poset, the inclusion-exclusion principle is essentially the Möbius inversion formula applied to that poset. Understanding this relationship helps when you move beyond simple set counts to more structured objects like partitions or subspaces. The principle also has a generating function version. If you assign a weight to each element based on which sets it belongs to, the inclusion-exclusion sum can be extracted from a product formula. This is how you derive things like the formula for Euler's totient function, (n) = n · _{d|n} (d)/d, where is the Möbius function.
For anyone actually implementing this, my advice is to write a small test harness that verifies your intersection computations against a brute force enumeration on a small domain before you scale up. I learned that the hard way when I once coded a solution that gave the wrong answer for a six-set problem, and the bug was a subtle off-by-one error in how I computed the floor function for one of the intersection terms. The formula was correct. The implementation was not. Also, if your sets have a recursive or self-similar structure, look for a recurrence relation first. Inclusion-exclusion on a fractal-like domain or a problem with repeated substructure often collapses into a much simpler recursive formula. The principle is still there underneath it, but you do not need to evaluate all the terms explicitly to get the answer.