Skip to content
Aniss Djellal
Go back

Finding the number of intersections between 100 random chords on a circle

3Blue1Brown recently posed a puzzle of the month ( You can check it here: https://youtube.com/shorts/wGffBCfrAsE ), where the task is to find the number of intersections between 100 random chords on a circle. Let’s solve it!

Solution for 2 pairs of chords

First, let’s try to calculate the probability of two chords intersecting. To make it easier, let’s draw it.

100 random chords circle

so as you can see, giving the chord AB, it splits the circle into 2 parts, which give us 3 use cases when dropping a new chord CD. Either both C and D lie on the top arc, in this case, there is not intersection, or they both lie on the bottom arc, in this case, there is not intersection too, and the final option is that one of them lies on the top arc and the other lies on the bottom one, which gives us 1 intersection. so based on the image, the probablity of 2 chords crossing each other is 1/3 right? It is tempting to look at those three cases and assume that because there are three options, the chance of a crossing is exactly 1/3. But in probability, outcomes aren’t always equally weighted! To confidently prove this, we need to measure exactly how likely that third scenario actually is.

Let’s elegantly prove it mathematically.

Anchor the Moving Targets

Dealing with four totally random points is chaotic. But because a circle is perfectly symmetrical, the absolute position of the first point doesn’t matter. We can lock point A at the very top of the circle (let’s call it angle 0).

Now, point B is our only moving target for the first chord. Let’s say it lands at some random angle θ\theta (which can be anywhere from 00 to 2π2\pi).

Measure the Arcs

Chord AB has now split our circle into two distinct arcs. If we want to drop a new point onto the circle, the probability of it landing on a specific arc is just the length of that arc divided by the total circumference.

Working in radians, the total circumference is 2π2\pi. This makes the probabilities beautifully simple:

Probability of landing on Arc 1: P1=θ2πP_1 = \frac{\theta}{2\pi}

Probability of landing on Arc 2: P2=1θ2πP_2 = 1 - \frac{\theta}{2\pi}

The Probability of a Crossing (for a fixed chord)

For our second chord (CD) to cross AB, point C must land on one arc, and point D must land on the other.

Since C could land on Arc 1 and D on Arc 2—or D could land on Arc 1 and C on Arc 2—we multiply the probabilities of those two independent events and double it to account for both orderings:

P(crossingθ)=2(θ2π)(1θ2π)P(\text{crossing} \mid \theta) = 2 \left( \frac{\theta}{2\pi} \right) \left( 1 - \frac{\theta}{2\pi} \right)

The Grand Average

That formula gives us the chance of an intersection if point B is frozen at a specific angle θ\theta. But B is totally random! To find the true, overall probability, we have to find the average value of this function across every possible angle from 00 to 2π2\pi.

In calculus, we do this by integrating our function over the interval and dividing by the length of that interval (2π2\pi):

Total Probability=12π02π2(θ2π)(1θ2π)dθ\text{Total Probability} = \frac{1}{2\pi} \int_{0}^{2\pi} 2 \left( \frac{\theta}{2\pi} \right) \left( 1 - \frac{\theta}{2\pi} \right) d\theta

If we expand the polynomial and pull out the constants, it looks like this:

1π02π(θ2πθ24π2)dθ\frac{1}{\pi} \int_{0}^{2\pi} \left( \frac{\theta}{2\pi} - \frac{\theta^2}{4\pi^2} \right) d\theta

Now, apply the power rule to integrate, evaluate from 00 to 2π2\pi, and watch the magic happen:

1π[θ24πθ312π2]02π\frac{1}{\pi} \left[ \frac{\theta^2}{4\pi} - \frac{\theta^3}{12\pi^2} \right]_{0}^{2\pi}

1π(4π24π8π312π2)\frac{1}{\pi} \left( \frac{4\pi^2}{4\pi} - \frac{8\pi^3}{12\pi^2} \right)

1π(π2π3)\frac{1}{\pi} \left( \pi - \frac{2\pi}{3} \right)

1π(π3)=13\frac{1}{\pi} \left( \frac{\pi}{3} \right) = \frac{1}{3}

The math flawlessly backs up our intuition. For any two random chords drawn on a circle, there is exactly a 1 in 3 chance that they will intersect!

Scaling Up to 100 Chords

Now for the real challenge: what happens when we drop 100 random chords onto the circle? What is the expected number of total intersections?

When faced with a tangled web of 100 lines, it is tempting to panic. My first intuition was that we shouldn’t try to calculate complex overlaps. Instead, if we know the probability of a single pair intersecting, we can just figure out how many possible pairs exist in a group of 100 chords, and multiply that total by our 1/3 chance.

It feels like a clean, logical shortcut, but is it mathematically valid?

The answer is yes, and it is entirely thanks to the Linearity of Expectation.

The Magic of Linearity of Expectation

In probability, the Linearity of Expectation states that the expected value of a sum of random events is simply the sum of their individual expected values.

Here is the most mind-blowing part of this theorem: it works even if the events are dependent on each other.

If you look at three chords (A, B, and C), the event of A crossing B is not strictly independent of A crossing C. In a normal probability problem, this dependency would make the math an absolute nightmare. But Linearity of Expectation gives us permission to completely ignore the overlapping chaos. We can treat every single pair of lines as if it exists in a vacuum.

The Final Calculation

To solve the puzzle, we just need to follow two simple steps:

  1. Count the pairs: How many distinct pairs of lines can we make out of 100 chords? This is a classic combinatorics problem (“100 choose 2”).

(1002)=100×992=4950 pairs\binom{100}{2} = \frac{100 \times 99}{2} = 4950 \text{ pairs}

  1. Multiply by the expected value: We know from our integral that the expected number of intersections for any individual pair is exactly 13\frac{1}{3}.

By applying the Linearity of Expectation, we simply multiply the total number of unique pairs by the expected value of a single pair:

4950×13=16504950 \times \frac{1}{3} = \mathbf{1650}

And there we have it! If you drop 100 random chords onto a circle, you can expect exactly 1,650 intersections. By starting with a single pair of lines and relying on the Linearity of Expectation, we bypassed a mathematically impossible web of dependencies and solved the whole thing with basic arithmetic.

PS: by running the following code ( Thank you claude :) ) we can simulate the results.

import random
import math

def count_intersections(n_chords):
    # Generate n_chords random chords, each defined by 2 random angles on the circle
    chords = []
    for _ in range(n_chords):
        a = random.uniform(0, 2 * math.pi)
        b = random.uniform(0, 2 * math.pi)
        chords.append((a, b))

    def crosses(c1, c2):
        a, b = c1
        c, d = c2
        def in_arc(x, start, end):
            # is x within the arc going counterclockwise from start to end?
            if start < end:
                return start < x < end
            else:
                return x > start or x < end

        # Two chords (a,b) and (c,d) cross iff exactly one of c,d is inside arc(a,b)
        c_in = in_arc(c, a, b)
        d_in = in_arc(d, a, b)
        return c_in != d_in

    count = 0
    for i in range(len(chords)):
        for j in range(i + 1, len(chords)):
            if crosses(chords[i], chords[j]):
                count += 1
    return count

def run_trials(n_chords, n_trials):
    total = 0
    results = []
    for _ in range(n_trials):
        c = count_intersections(n_chords)
        results.append(c)
        total += c
    avg = total / n_trials
    return avg, results

if __name__ == "__main__":
    n_chords = 100
    n_trials = 20000

    avg, results = run_trials(n_chords, n_trials)
    expected = math.comb(n_chords, 2) / 3

    print(f"Chords per trial: {n_chords}")
    print(f"Number of trials: {n_trials}")
    print(f"Theoretical expected intersections: {expected}")
    print(f"Simulated average intersections:    {avg:.2f}")
    print(f"Difference: {abs(avg - expected):.2f} ({100 * abs(avg - expected) / expected:.2f}%)")

    results.sort()
    print(f"Min: {results[0]}, Max: {results[-1]}, Median: {results[len(results)//2]}")

Here is the output of the script:

Chords per trial: 100
Number of trials: 20000
Theoretical expected intersections: 1650.0
Simulated average intersections:    1649.37
Difference: 0.63 (0.04%)
Min: 1052, Max: 2233, Median: 1646

Share this post on:

Next Post
Trading MatMuls for SRAM Lookups: A 3-Bit Edge Architecture