Most places give you the formula and leave. Ten minutes on where it comes from is worth it, because the derivation tells you exactly when the formula stops working, and because the three versions of it each suit a different job.
The quick answer
y = y1 + (x − x1) × (y2 − y1) ÷ (x2 − x1)
The fraction on the right is the slope: how much y changes for each unit of x. Multiplying it by (x − x1) tells you how much y has changed by the time you get to your target. Adding y1 puts you back on the real scale.
Where it comes from
You have two points, (x1, y1) and (x2, y2), and you are assuming the values run in a straight line between them. A straight line has one property that defines it: the slope between any two points on it is the same as between any other two.
So the slope from your first point to the unknown point you want has to equal the slope from your first point to your second:
(y − y1) ÷ (x − x1) = (y2 − y1) ÷ (x2 − x1)Multiply both sides by (x − x1) to clear the left denominator, then add y1 to both sides:
y = y1 + (x − x1) × (y2 − y1) ÷ (x2 − x1)That is the whole derivation, and it contains exactly one assumption: the first sentence, that a straight line describes what happens between your two points. Every way this formula can fail you traces back to that sentence being untrue.
Three versions and when to use each
Point and slope
y = y1 + m(x − x1), where m = (y2 − y1) ÷ (x2 − x1)Use this when you have several targets coming from the same pair of points. Work out m once and reuse it. Also use it when the slope means something you care about, like a temperature coefficient or a price per kg, since this version puts that number front and centre.
Blend of the two values
y = (1 − t)y1 + t·y2, where t = (x − x1) ÷ (x2 − x1)Read this as mixing two numbers. If you are 40 percent of the way across, take 60 percent of the first value and 40 percent of the second. Because the two shares always add to 100 percent, your answer physically cannot land outside the two values you started with, which makes this the safest version to put in code.
It also generalises. Swap those two weights for more complicated functions of t and you get every other interpolation method, including Lagrange polynomials, where the weights are polynomials instead of straight percentages.
Check both versions against the courier prices, $18.40 at 5 kg and $26.00 at 10 kg, asking about 7 kg:
Point and slope: m = 7.60 ÷ 5 = 1.52; y = 18.40 + 1.52 × 2 = 21.44Blend: t = 0.4; y = 0.6 × 18.40 + 0.4 × 26.00 = 11.04 + 10.40 = 21.44
Symmetric
y = [ y1(x2 − x) + y2(x − x1) ] ÷ (x2 − x1)Each value gets weighted by how far away the other point is. Being close to point 1 means (x2 − x) is large, so y1 gets the bigger share. Both points are treated the same way, so it makes no difference which one you call "first". That property carries over neatly to bilinear interpolation on a grid.
Same numbers: [18.40 × (10 − 7) + 26.00 × (7 − 5)] ÷ 5 = [55.20 + 52.00] ÷ 5 = 21.44. Three for three.
How wrong is it?
Assuming the real relationship curves smoothly, the gap between the truth and your straight line is capped by:
|error| ≤ (h2 ÷ 8) × max |f″|, where h = x2 − x1Here h is the width of your gap and f″ is how sharply the real curve bends. Three things fall out of that.
The h is squared. Halve the spacing in your table and the worst-case error drops to a quarter. This is why a fine table barely needs anything smarter than a straight line.
Only the bending matters, not the values. A relationship that climbs steeply but perfectly straight interpolates exactly, with zero error. A shallow one that curves hard does not. Steepness is irrelevant here, which surprises people.
The divide by 8 is generous. Your worst case sits at the middle of the gap and is only an eighth of h squared times the bending. Straight-line interpolation is more forgiving than it looks.
Try it on something you can check. Interpolate x2 between (2, 4) and (4, 16), asking for x = 3:
4 + 0.5 × 12 = 10, while the true value is 32 = 9The error is 1. The formula predicts a cap of (22 ÷ 8) × 2 = 1, since x2 bends by a constant 2 everywhere. The cap is exactly right, as it always is for a parabola.
Writing it in code
The obvious version has a small flaw:
y = y1 + t * (y2 - y1)
It is fast, and it behaves predictably as t increases. But at t = 1 it does not always return exactly y2 in
floating point, because y1 + 1.0 * (y2 - y1) can round to something a hair off. If you are
animating something that must land precisely on its target, use the blend version instead:
That one returns exactly y1 at t = 0 and exactly y2 at t = 1, though it can wobble in the other direction for
some inputs. C++ handles the trade-off by having std::lerp pick between the two depending on the
arguments. For reading values out of an engineering table, you will never see the difference.
The guard matters more than either choice:
if (x2 == x1) return y1;Duplicate x values do turn up in real tables, especially ones that grow over time. Without this line you get a division by zero, and a NaN spreading quietly through a report is far harder to track down than an early return.
When the straight line assumption breaks
Go back to the derivation. It assumed the slope stays the same all the way across your gap. Anywhere that is badly untrue, the answer is badly wrong, and being careful with the arithmetic does not help.
The usual culprits are a coarse table over a sharply curved region, data that crosses a phase change or some other jump, and anything that grows exponentially.
That last one has a cheap fix worth remembering. For vapour pressure, sound intensity, bacterial counts, or anything that moves by orders of magnitude, take the logarithm of both y values, interpolate normally, then undo the log. Two extra keystrokes, and it often removes most of the error.
For everything else, a cubic spline is the usual next step. You can run the same points through both in the calculator and see how far apart the answers land.