Skip to content

What is Math.hypot() in JavaScript? A Complete Guide

I was calculating the distance between two points in JavaScript. I wrote the obvious formula:

distance.js
function distance(x, y) {
return Math.sqrt(x * x + y * y);
}
console.log(distance(3, 4)); // 5 - looks good!

Then I tried it with larger numbers and got Infinity. My data was lost. The calculation overflowed before Math.sqrt was even called.

The Problem: Overflow in Naive Distance Calculation

I was processing GPS coordinates and scientific data when my distance calculations started returning Infinity:

overflow-demo.js
function distance(x, y) {
return Math.sqrt(x * x + y * y);
}
// Works fine for small numbers
distance(3, 4); // 5
// FAILS for large numbers
distance(1e200, 1e200); // Infinity - should be 1.414e200
distance(1e154, 1e154); // Infinity - intermediate overflow
// FAILS for very small numbers
distance(1e-200, 1e-200); // 0 - should be 1.414e-200

The problem is x * x for x = 1e200 produces 1e400, which exceeds JavaScript’s maximum safe floating-point value (Number.MAX_VALUE ≈ 1.8e308).

Even worse, I realized I had similar code scattered throughout my codebase:

scattered-calculations.js
// In collision detection
const dist = Math.sqrt(dx*dx + dy*dy);
// In 3D rendering
const depth = Math.sqrt(x*x + y*y + z*z);
// In color distance calculation
const colorDiff = Math.sqrt(r*r + g*g + b*b);
// All of these can overflow!

The Solution: Math.hypot()

JavaScript has a built-in function that handles this automatically:

hypot-solution.js
// Built into JavaScript since ES6
Math.hypot(3, 4); // 5
Math.hypot(1e200, 1e200); // 1.414e200 - correct!
Math.hypot(1e-200, 1e-200); // 1.414e-200 - correct!
// Works with any number of arguments (n-dimensional distance)
Math.hypot(3, 4, 12); // 13 (3D distance)
Math.hypot(1, 2, 3, 4); // 5.477... (4D distance)
Math.hypot(); // 0 (no arguments)
Math.hypot(5); // 5 (one argument)

Why Math.hypot() Works: The Algorithm

The naive approach squares all values first, then takes the square root:

Naive Algorithm (Problematic)
Step 1: Square each value
x * x + y * x
For x = 1e200: x * x = 1e400
Step 2: Sum and sqrt
Problem: 1e400 overflows before sqrt is called
Result: Infinity

Math.hypot() uses a smarter approach:

Math.hypot() Algorithm (Robust)
Step 1: Find the maximum absolute value M
M = max(|x|, |y|, ...)
Step 2: If M is 0 or Infinity, handle edge cases
Step 3: Scale all values by 1/M
x_scaled = x / M
y_scaled = y / M
Step 4: Calculate in scaled space
sum = x_scaled^2 + y_scaled^2 + ...
Step 5: Scale back
result = M * sqrt(sum)
Why this works:
- All scaled values are <= 1
- No overflow in intermediate squares
- Precision is maintained

Here’s a simplified implementation:

hypot-implementation.js
function myHypot(...args) {
// Filter out non-finite values
const values = args.filter(v => isFinite(v));
// Handle empty or zero case
if (values.length === 0) return 0;
// Find maximum absolute value
let max = 0;
for (const v of values) {
const abs = Math.abs(v);
if (abs > max) max = abs;
}
// Edge case
if (max === 0) return 0;
// Scale, sum, and unscale
let sum = 0;
for (const v of values) {
const scaled = v / max;
sum += scaled * scaled;
}
return max * Math.sqrt(sum);
}
// Test it
myHypot(1e200, 1e200); // 1.414e200 - works!

When to Use Math.hypot()

I found these patterns where Math.hypot() is the right choice:

1. 2D Distance Calculation

2d-distance.js
// Collision detection
function checkCollision(obj1, obj2) {
const dx = obj2.x - obj1.x;
const dy = obj2.y - obj1.y;
const distance = Math.hypot(dx, dy);
return distance < (obj1.radius + obj2.radius);
}

2. 3D Distance Calculation

3d-distance.js
// 3D point distance
function distance3D(p1, p2) {
return Math.hypot(
p2.x - p1.x,
p2.y - p1.y,
p2.z - p1.z
);
}
// Depth calculation in rendering
function calculateDepth(camera, point) {
return Math.hypot(
point.x - camera.x,
point.y - camera.y,
point.z - camera.z
);
}

3. Vector Magnitude

vector-magnitude.js
// Vector operations
function magnitude(vector) {
return Math.hypot(...Object.values(vector));
}
// Normalize a vector
function normalize(vector) {
const mag = magnitude(vector);
const result = {};
for (const [key, value] of Object.entries(vector)) {
result[key] = value / mag;
}
return result;
}

4. Color Difference (RGB)

color-distance.js
// Color similarity
function colorDistance(color1, color2) {
return Math.hypot(
color2.r - color1.r,
color2.g - color1.g,
color2.b - color1.b
);
}

Edge Cases and Gotchas

Math.hypot() handles edge cases gracefully:

edge-cases.js
// NaN handling
Math.hypot(3, NaN); // NaN
Math.hypot(NaN, 4); // NaN
Math.hypot(3, 4, NaN); // NaN
// Infinity handling
Math.hypot(3, Infinity); // Infinity
Math.hypot(Infinity, 4); // Infinity
// Mixed values
Math.hypot(-3, 4); // 5 (absolute values used)
Math.hypot(0, 0, 0); // 0
Math.hypot(); // 0 (empty call)
// Very large array
Math.hypot(...new Array(10000).fill(1)); // 100 (works fine)

Performance Comparison

I benchmarked the naive approach vs Math.hypot():

benchmark.js
function benchmark() {
const iterations = 10_000_000;
// Test 1: Naive approach (small numbers)
console.time('Naive (small)');
for (let i = 0; i < iterations; i++) {
Math.sqrt(3*3 + 4*4);
}
console.timeEnd('Naive (small)');
// Test 2: Math.hypot (small numbers)
console.time('hypot (small)');
for (let i = 0; i < iterations; i++) {
Math.hypot(3, 4);
}
console.timeEnd('hypot (small)');
// Test 3: Large numbers (only hypot works)
console.time('hypot (large)');
for (let i = 0; i < iterations; i++) {
Math.hypot(1e200, 1e200);
}
console.timeEnd('hypot (large)');
}
benchmark();

Results:

Benchmark Results
Naive (small): ~45ms
hypot (small): ~55ms
hypot (large): ~60ms

Math.hypot() is slightly slower for small numbers due to the scaling algorithm, but the difference is negligible. The correctness gain is worth it.

Historical Context: Why This Function Exists

This isn’t a new problem. Fortran had HYPOT in the 1970s for exactly this reason:

Historical Timeline
1970s: Fortran introduces HYPOT
- Numerical stability was crucial for scientific computing
- Engineers knew the overflow problem
1990s: C/C++ add hypot() to math.h
- Standard library function
- Same overflow protection
2015: JavaScript ES6 adds Math.hypot()
- Same concept, JavaScript syntax
- Extended to support n dimensions (not just 2)

The algorithm has been battle-tested for decades. It’s not just convenience - it’s correctness.

Summary

I learned that Math.sqrt(x*x + y*y) is a landmine waiting to explode. When values are large, it overflows. When values are tiny, it underflows.

The fix is simple:

The Fix
// Change this:
const dist = Math.sqrt(x*x + y*y);
// To this:
const dist = Math.hypot(x, y);

Key points:

  • Math.hypot() calculates the square root of the sum of squares
  • It handles overflow and underflow automatically
  • It accepts any number of arguments for n-dimensional distance
  • It’s slightly slower than naive sqrt(x*x + y*y) but correct
  • Use it anywhere you calculate distance, magnitude, or vector length

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments