You are given n points on a 2D plane, and you need to check whether every point lies on the same straight line.
Engineering takeaway. This is one of those "easy" problems where the obvious math is correct but the machine isn't. JavaScript stores numbers as IEEE-754 doubles, and division is rarely exact. When a real system depends on geometry — map overlays, drawing tools, collision checks — a naive slope calculation will eventually fail on edge cases. The fix is a classic: avoid division entirely and use cross-multiplication instead.
Intuition
Any straight line can be written as x = ay + b, where (x, y) are points on the line. If we can pin down a and b from two known points, we can verify every other point against the same equation.
Take two points (x, y) and (x', y'):
x = ay + b
x' = ay' + bSubtracting the second from the first gives x - x' = (y - y')a, so a = (x - x') / (y - y') and b = x - ay.
That looks clean — so let's code it.
The naive solution (and where it fails)
function checkStraightLine(coordinates: number[][]): boolean {
const [deltaX, deltaY] = [
coordinates[0][0] - coordinates[1][0],
coordinates[0][1] - coordinates[1][1],
];
const a = deltaX / deltaY;
const b = coordinates[0][0] - a * coordinates[0][1];
for (let i = 2; i < coordinates.length; i++) {
if (deltaX === 0) {
if (coordinates[i][0] !== coordinates[i - 1][0]) return false;
} else if (deltaY === 0) {
if (coordinates[i][1] !== coordinates[i - 1][1]) return false;
} else if (coordinates[i][0] !== a * coordinates[i][1] + b) {
return false;
}
}
return true;
}This passes 63 of 80 test cases, then fails at case 64:
[[8,78],[2,18],[-1,-12],[-5,-52],[-4,-42],[-8,-82],[3,28],[9,88]]Let's run the numbers by hand:
deltaX = 8 - 2 = 6
deltaY = 78 - 18 = 60
a = deltaX / deltaY = 6 / 60 = 0.1
b = x - ay = 8 - 0.1 * 78 = 0.2Now add a console.log(a, b) and the result is:
0.1 0.1999999999999993There it is: floating-point precision. 6 / 60 isn't exactly 0.1 in binary, and the tiny error propagates through b. Every comparison against the line is now off by a few e-16, and one point falls on the wrong side of the !== check. (Or, as I like to joke, switch to C++ or Java — but only if you really must.)
The fix: cross-multiplication
We don't actually need the slope. Back to the two-point reasoning:
x = ay + b x' = ay' + b x'' = ay'' + bSubtracting gives us two ratio identities, and instead of dividing them, we cross-multiply:
(x - x')(y - y'') = (y - y')(x - x'')That equality uses only subtraction and multiplication — both exact for integers, and immune to the precision trap.
function checkStraightLine(coordinates: number[][]): boolean {
const [deltaX, deltaY] = [
coordinates[0][0] - coordinates[1][0],
coordinates[0][1] - coordinates[1][1],
];
for (let i = 2; i < coordinates.length; i++) {
const [deltaX2, deltaY2] = [
coordinates[i][0] - coordinates[0][0],
coordinates[i][1] - coordinates[0][1],
];
if (deltaX * deltaY2 !== deltaY * deltaX2) {
return false;
}
}
return true;
}No division, no 0.1, no 0.1999999999999993. Just a clean geometric invariant.
Complexity
- Time:
O(n)— a single pass over the points. - Space:
O(1)— a constant number of variables.
The lesson
Whenever you find yourself dividing in an equality check, ask: can I cross-multiply? Floating-point is a silent killer — the math is right, the answer is wrong, and the test that catches it comes at 64 out of 80. In production, prefer integer-exact arithmetic for comparisons wherever the domain allows it.