toji / gl-matrix

Javascript Matrix and Vector library for High Performance WebGL apps
glmatrix.net
MIT License
5.4k stars 725 forks source link

Math.hypot is really slow #446

Closed platypii closed 2 years ago

platypii commented 2 years ago

Math.hypot is painfully slow on every modern javascript environment. To live up to the project's goal: "glMatrix is designed to perform vector and matrix operations stupidly fast" I suggest changing use of Math.hypot(x, y) to Math.sqrt(x * x + y * y) for significantly improved performance.

Is there an argument for continuing to use hypot? It is more accurate for very small and very large numbers (eg- 1e200) [1]. But I'm not sure those edge cases matter for a WebGL library that is meant to be fast.

If this is something that would be considered, I am happy to make a Pull Request with the change. Would love to hear your thoughts.

Benchmark results of hypot vs sqrt (smaller is better):

environment hypot sqrt
chrome 235 ms 12 ms
firefox 64 ms 12 ms
safari 390 ms 74 ms
node 248 ms 11 ms
test script ```js const size = 10000000 let sum = 0 let x = 1.1 const y = 2.2 const z = 3.3 console.time("hypot loop") for (let i = 0; i < size; i++) { sum += Math.hypot(x, y, z) x += 1 } console.timeEnd("hypot loop") console.time("sqrt loop") sum = 0 x = 1.1 for (let i = 0; i < size; i++) { sum += Math.sqrt(x * x + y * y + z * z) x += 1 } console.timeEnd("sqrt loop") ```
mreinstein commented 2 years ago

somewhat related, if we decide to keep using hypot it might be nice to not modify the Math prototype. Today:

if (!Math.hypot)
  Math.hypot = function () { ... }

better?:

export const hypot = Math.hypot || function () { ... }

Not modifying global browser objects would be better imo.

platypii commented 2 years ago

No need for a polyfill if you just use sqrt :-)

stefnotch commented 2 years ago

Quick note: Microbenchmarking Javascript is a tad trickier than that https://mathiasbynens.be/notes/javascript-benchmarking

Here is a more correct one (I hope) https://jsben.ch/ZksIx

But yeah, it seems like Math.hypot() is slower.

z3dev commented 2 years ago

@stefnotch I'm all in favor of the PR #449 as that keeps glmatrix and JSCAD math in sync. The performance improvements are real, as JSCAD heavily uses distance functions.

FYI, I tried to find some valid reason to use hypot() but failed. I'm not even sure why this function was added to the standard Math.