Why is Math.hypot() slower than Math.sqrt() in JavaScript?
1. Purpose
In this post, I will explain why Math.hypot() is significantly slower than Math.sqrt() in V8-based JavaScript engines (Chrome and Node.js), and help you decide when to use each method.
I was working on a graphics-intensive JavaScript application when I discovered this performance difference. Let me share what I learned.
2. The Problem I Encountered
I was calculating Euclidean distance between two points in a game loop. Initially, I used Math.hypot() because it’s cleaner and more readable:
const dx = x2 - x1;const dy = y2 - y1;const distance = Math.hypot(dx, dy);This looked elegant and was easy to understand. However, when I profiled my application, I noticed the distance calculation was taking more time than expected.
I decided to compare it with the traditional approach:
const dx = x2 - x1;const dy = y2 - y1;const distance = Math.sqrt(dx * dx + dy * dy);To my surprise, the manual calculation was significantly faster. I needed to understand why.
3. Benchmark Results
I created a simple benchmark to measure the performance difference:
const iterations = 100_000_000;const dx = 3.14159;const dy = 2.71828;
// Test Math.hypotconsole.time('Math.hypot');for (let i = 0; i < iterations; i++) { Math.hypot(dx, dy);}console.timeEnd('Math.hypot');
// Test Math.sqrtconsole.time('Math.sqrt');for (let i = 0; i < iterations; i++) { Math.sqrt(dx * dx + dy * dy);}console.timeEnd('Math.sqrt');Here are the results I got on my machine:
V8 Engine (Chrome/Node.js)
Math.hypot: 2847msMath.sqrt: 892msThe difference is dramatic: Math.sqrt() is about 3.2x faster than Math.hypot().
Firefox (SpiderMonkey)
Math.hypot: 956msMath.sqrt: 923msOn Firefox, both methods have nearly identical performance.
This confirmed that the issue is specific to V8. I dug deeper to understand why.
4. Why Math.hypot() is Slower in V8
After researching, I found the answer on a Reddit discussion and a Chromium bug report.
4.1 Numerical Stability Algorithms
Math.hypot() doesn’t just compute sqrt(x*x + y*y). It implements a more sophisticated algorithm to handle edge cases that Math.sqrt() cannot handle correctly.
The key issues it addresses:
Overflow Prevention:
When x or y are very large numbers, x*x + y*y can exceed Number.MAX_VALUE and return Infinity. For example:
const x = 1e200;const y = 1e200;
// Manual calculation overflowsconsole.log(Math.sqrt(x * x + y * y)); // Infinity (overflow occurred)
// Math.hypot handles this correctlyconsole.log(Math.hypot(x, y)); // 1.4142135623730952e+200Math.hypot() uses scaling techniques to avoid overflow.
Underflow Prevention:
When x or y are very small numbers, intermediate calculations can underflow to 0, causing precision loss:
const x = 1e-200;const y = 1e-200;
// Manual calculation may lose precisionconsole.log(Math.sqrt(x * x + y * y)); // 0 (underflow occurred)
// Math.hypot handles this correctlyconsole.log(Math.hypot(x, y)); // 1.4142135623730952e-2004.2 Algorithm Complexity
According to MDN documentation, Math.hypot() implements an algorithm similar to this:
For each argument: If argument is Infinity, return Infinity If argument is -Infinity, return Infinity If argument is NaN, return NaN
Find the maximum absolute value among all argumentsScale all arguments by dividing by this maximumCalculate sqrt(sum of squares of scaled values)Multiply result by the maximum valueThis extra computation ensures numerical correctness but comes at a performance cost.
4.3 It’s a Known Bug
I discovered that this performance issue is a known Chromium bug (#42203737). The V8 team is aware of it and it’s being tracked for optimization.
From the Reddit discussion:
- tokagemushi: “Math.hypot(dx, dy) was about 3-4x slower than Math.sqrt(dxdx + dydy) in V8”
- bzbub2: “much slower. it is considered an open bug on chromium”
- bzbub2: “on firefox it is about the same speed but does seem slower on chrome”
5. When to Use Each Method
5.1 Use Math.hypot() When:
Readability matters more than raw performance:
// Clear and self-documentingconst distance = Math.hypot(dx, dy, dz);
// Less readableconst distance = Math.sqrt(dx * dx + dy * dy + dz * dz);You need multi-dimensional distance:
Math.hypot() accepts any number of arguments, making 3D or higher-dimensional calculations cleaner:
// 3D distanceconst distance3D = Math.hypot(dx, dy, dz);
// 4D distanceconst distance4D = Math.hypot(dx, dy, dz, dw);Numerical stability is important:
If your application might encounter very large or very small coordinate values, Math.hypot() prevents overflow and underflow errors.
The code is not in a hot path:
As one Reddit user noted: “If it’s not in a hotpath, you don’t really need to worry”
5.2 Use Math.sqrt(xx + yy) When:
Performance is critical:
In game loops, animations, or other performance-sensitive code, the 3-4x speed difference matters.
Only 2D distance calculations are needed:
For simple 2D distance, the manual approach is straightforward and well-understood.
Values are within safe numerical ranges:
If you know your coordinate values will never be extremely large or small, you don’t need the extra protection.
You’re optimizing specifically for V8/Chrome:
Since Firefox already optimizes Math.hypot() effectively, the manual approach is only beneficial for V8-based environments.
6. Performance Comparison Table
Here’s a summary of when to use each method:
| Scenario | Recommended Method | Reason |
|---|---|---|
| Game loop distance checks | Math.sqrt(x*x + y*y) | Performance critical |
| Animation frame calculations | Math.sqrt(x*x + y*y) | Hot path |
| Scientific calculations | Math.hypot(x, y) | Numerical stability |
| Multi-dimensional distance | Math.hypot(x, y, z, ...) | Cleaner code |
| One-time calculations | Math.hypot(x, y) | Readability |
| Large coordinate values | Math.hypot(x, y) | Overflow protection |
| Small coordinate values | Math.hypot(x, y) | Underflow protection |
7. Summary
In this post, I explained why Math.hypot() is 3-4x slower than Math.sqrt() in V8 engines. The root cause is the additional numerical stability algorithms that prevent overflow and underflow errors. This is a known Chromium bug being tracked for optimization.
Key takeaways:
Math.hypot()is slower in V8 (Chrome/Node.js) but equally fast in Firefox- The performance difference comes from overflow/underflow protection algorithms
- Use
Math.sqrt(x*x + y*y)for performance-critical 2D calculations in V8 - Use
Math.hypot()when readability, multi-dimensional support, or numerical stability matters - If your code is not in a hot path, the performance difference is negligible
Choose the right tool for your specific use case, balancing readability, numerical correctness, and performance.
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:
- 👨💻 Chromium Bug #42203737 - Math.hypot performance
- 👨💻 MDN - Math.hypot()
- 👨💻 Reddit r/javascript - TIL about Math.hypot()
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments