How Does the Dot Product Measure Similarity?
A step-by-step journey from vectors and the law of cosines to why the dot product of normalised vectors measures directional similarity.
I was studying Build a Large Language Model (From Scratch) the other day when I came across the idea of using dot products to calculate similarity between two normalised vectors.
I found that intriguing.
The dot product is simply the sum of the pairwise products of two vectors’ components. How would that indicate similarity?
This article is my research written up. To be honest, proving why this works isn’t necessary to use it. If you’re like me, however, you value understanding why things are the way they are. Knowledge for knowledge’s sake ;)
Before we go on this adventure, let’s start with some basics.
What do we mean by similarity?
A vector can be represented as a collection of numbers. Geometrically, we can think of it as an arrow with a magnitude (length) and a direction.
Take a vector called , defined as . This vector has two dimensions, although vectors can have many more. On a graph, vector looks like this:

Starting at the origin, it extends 4 steps along the x-axis and 5 steps along the y-axis.
Now imagine another vector, , defined as .

If I wanted to calculate how similar is to , a good first question would be: similar based on what metric?
I could, for instance, measure the distance between their endpoints. A smaller distance would indicate greater similarity. Notice what’s happening here, though: the lengths of the vectors matter, as well as their directions. If were shorter, that distance would change.
If I were interested only in direction, I could measure the angle (theta) between the vectors. That’s the approach we’ll use here.
On our two-dimensional graph, we could measure the angle with a protractor:
- At , the vectors point in the same direction.
- At , they’re orthogonal (perpendicular).
- At , they point in opposite directions.
Cosine turns these angles into a similarity score:
Plotting vectors and measuring angles isn’t a practical approach for computers, especially when vectors have hundreds of dimensions. We need a way to compute this score directly from their components.
Thankfully, maths can help us here.
giggles in trigonometry
Start with the law of cosines
There’s a mathematical rule that lets us calculate the cosine of an angle in a triangle, provided we know the lengths of all three sides. It’s called the law of cosines.
Here, , , and are the side lengths. The angle lies between the sides of lengths and , opposite the side of length .
The law of cosines generalises Pythagoras’ theorem:
Pythagoras’ theorem applies to right-angled triangles. When , the cosine term is zero, leaving us with the equation above.
How does this relate to our vectors and ? That’s what we’re about to find out.
Find the lengths of the vectors
We know the components of and , but we haven’t calculated their lengths yet.
For , the horizontal component is 4 and the vertical component is 5. Its length is the hypotenuse of the right triangle below.

Pythagoras’ theorem gives us a way to calculate that length:
Plugging in the components of :
We write the length of as , so:
More generally, we can write:
Here, and are the x and y components of . Keep this relationship in mind; we’ll use it again shortly.
The same calculation for gives .
Find the third side
Okay, now that we have and , how do we calculate the distance between their endpoints? Remember, we need all three side lengths to use the law of cosines.
It turns out there’s a neat way to do this. Subtract from to get a new vector, :
This vector connects the endpoint of to the endpoint of . That makes sense: to get from to , move 2 steps along the x-axis and 4 steps along the y-axis.
We can now use Pythagoras’ theorem to calculate its length, .

Let’s write the calculation in terms of the components, using and :
A brief clarification on the last step: remember the relationship I asked you to keep in mind?
That’s how we replace the sums of squared components with and .
Now we need to connect this result to the angle between the vectors.
Connect the two formulas
Remember the law of cosines:
For our triangle, the side lengths are , , and , so:
Since , we can rewrite this as:
We now have two expressions for . One uses the components of the vectors; the other uses their lengths and the angle between them. Because they describe the same quantity, we can set them equal:
Subtract from both sides, then divide by :
Look at the left-hand side of the last equation. That’s exactly the dot product!
For and , the dot product is . Therefore:
The dot product equals the length of multiplied by the length of , multiplied by the cosine of the angle between them.
Check it with our example
Let’s test the formula using our original vectors:
Now let’s check this with the law of cosines, keeping the squared lengths exact to avoid rounding too early:
We get the same answer.
Why normalisation makes the difference
If we’re dealing with normalised vectors—that is, vectors with a length of 1—the formula becomes:
This is really beautiful, actually.
The dot product of two normalised vectors equals their cosine similarity. Without normalisation, the lengths of the vectors also affect the dot product.
We don’t need to calculate the angle first, or find the vector connecting the endpoints of and .
Let’s normalise our original vectors. To normalise a non-zero vector, divide each component by the vector’s length:
Their dot product gives us:
The same angle again! We’ve kept the exact values in the calculation; using the rounded components would give a slightly different approximation.
That, my friends, is the beauty of mathematics.
Let me stop now because my head hurts, lol!
Do you have any thoughts, corrections or questions? I'd love to hear from you.
Get the next note
New notes when I publish. No schedule, no filler.