<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>284631</bug_id>
          
          <creation_ts>2024-12-13 07:17:11 -0800</creation_ts>
          <short_desc>Math.hypot() is significantly slower than Math.sqrt()</short_desc>
          <delta_ts>2025-03-22 18:56:46 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>JavaScriptCore</component>
          <version>WebKit Nightly Build</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          <see_also>https://bugs.webkit.org/show_bug.cgi?id=68318</see_also>
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Ashley Gullen">ashley</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>iKonnyaku40</cc>
    
    <cc>mark.lam</cc>
    
    <cc>webkit-bug-importer</cc>
    
    <cc>ysuzuki</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2081496</commentid>
    <comment_count>0</comment_count>
      <attachid>473562</attachid>
    <who name="Ashley Gullen">ashley</who>
    <bug_when>2024-12-13 07:17:11 -0800</bug_when>
    <thetext>Created attachment 473562
Performance benchmark

Steps to reproduce:

Math.hypot() appears to be significantly slower than Math.sqrt(). As it is a more convenient specialized method for calculating the hypotenuse, this makes it easy to write code that is accidentally less performant than expected. This affects our browser-based game engine Construct (https://www.construct.net) as well as third-party math libraries like glMatrix (who eventually realized the same thing and removed uses of Math.hypot(): https://github.com/toji/gl-matrix/commit/8962b2e7727594022e59e48e605049c69403da60)

See attachment for what I believe is a fair benchmark.

Note that optimizing the case where 2 or 3 arguments are passed should be sufficient to optimize the majority of performance-sensitive uses in game engines using 2D and 3D calculations.

Actual results:

On an Apple M1 Pro with Safari 18.1.1, after three runs, the Math.sqrt() benchmark completes in ~39ms, and the Math.hypot() benchmark completes in ~181ms (~4.6x slower).

Expected results:

Both benchmarks should complete in a similar time. If anything perhaps Math.hypot() should be faster, as more of the calculation is completed with a built-in method.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2082197</commentid>
    <comment_count>1</comment_count>
    <who name="Yusuke Suzuki">ysuzuki</who>
    <bug_when>2024-12-16 16:26:14 -0800</bug_when>
    <thetext>Right. We should lower Math.hypot into multiplication + sqrt.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2083297</commentid>
    <comment_count>2</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2024-12-20 07:18:13 -0800</bug_when>
    <thetext>&lt;rdar://problem/141821484&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2103747</commentid>
    <comment_count>3</comment_count>
    <who name="Keita Nonaka">iKonnyaku40</who>
    <bug_when>2025-03-17 07:25:50 -0700</bug_when>
    <thetext>Pull request: https://github.com/WebKit/WebKit/pull/42569</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2103748</commentid>
    <comment_count>4</comment_count>
    <who name="Ashley Gullen">ashley</who>
    <bug_when>2025-03-17 07:31:58 -0700</bug_when>
    <thetext>That PR looks like it only optimizes for constant parameters - unfortunately that won&apos;t bring any real-world performance improvement, as in practice it is always going to be called with non-constant parameters (as per the benchmark).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2103750</commentid>
    <comment_count>5</comment_count>
    <who name="Ashley Gullen">ashley</who>
    <bug_when>2025-03-17 07:34:21 -0700</bug_when>
    <thetext>Actually, I&apos;m not so sure. Apologies if I got that wrong! Would be interested to see benchmark results.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2104598</commentid>
    <comment_count>6</comment_count>
    <who name="Keita Nonaka">iKonnyaku40</who>
    <bug_when>2025-03-20 02:05:26 -0700</bug_when>
    <thetext>I dont think hypot() becomes as fast as sqrt() because hypot function has overhead to avoid overflow or underflow. 
sqrt() is faster because it avoids overflow and underflow calculation, so in some cases, sqrt() does not calculate well.
For example, 

```js
console.log(Math.hypot(1e308, 1e308, 1e308))                                               // 1.7320508075688772e+308 
console.log(Math.sqrt(1e308 * 1e308 +  1e308 * 1e308 + 1e308 * 1e308)) // Infinity
```

https://www.typescriptlang.org/play/?#code/MYewdgziA2CmB00QHMAUBZAhgFwBb1wE8AHEbVARlgGYAGADgBoACKup1mhgSm4ChQkGAiRoseeBACOAJ3JsGzAFSd2zANTNVilQvobt+3V3q8gA</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2104599</commentid>
    <comment_count>7</comment_count>
    <who name="Keita Nonaka">iKonnyaku40</who>
    <bug_when>2025-03-20 02:07:08 -0700</bug_when>
    <thetext>&gt; NOTE
&gt; Implementations should take care to avoid the loss of precision from overflows and underflows that are prone to occur in naive implementations when this function is called with two or more arguments.

https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.hypot</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2105363</commentid>
    <comment_count>8</comment_count>
    <who name="EWS">ews-feeder</who>
    <bug_when>2025-03-22 18:56:44 -0700</bug_when>
    <thetext>Committed 292549@main (bdf66e673c2c): &lt;https://commits.webkit.org/292549@main&gt;

Reviewed commits have been landed. Closing PR #42569 and removing active labels.</thetext>
  </long_desc>
      
          <attachment
              isobsolete="0"
              ispatch="0"
              isprivate="0"
          >
            <attachid>473562</attachid>
            <date>2024-12-13 07:17:11 -0800</date>
            <delta_ts>2024-12-13 07:17:11 -0800</delta_ts>
            <desc>Performance benchmark</desc>
            <filename>sqrt-hypot-perftest.html</filename>
            <type>text/html</type>
            <size>1218</size>
            <attacher name="Ashley Gullen">ashley</attacher>
            
              <data encoding="base64">PHNjcmlwdCB0eXBlPSJtb2R1bGUiPg0KDQpjb25zdCBJVEVSQVRJT05TID0gMTAwMDAwMDA7DQoN
CmZ1bmN0aW9uIFNxcnRUZXN0KCkNCnsNCglsZXQgc3VtID0gMDsNCglmb3IgKGxldCBpID0gMDsg
aSA8IElURVJBVElPTlM7ICsraSkNCgl7DQoJCWNvbnN0IGR4ID0gTWF0aC5yYW5kb20oKTsNCgkJ
Y29uc3QgZHkgPSBNYXRoLnJhbmRvbSgpOw0KCQljb25zdCBkeiA9IE1hdGgucmFuZG9tKCk7DQoJ
CXN1bSArPSBNYXRoLnNxcnQoZHggKiBkeCArIGR5ICogZHkgKyBkeiAqIGR6KTsNCgl9DQoJcmV0
dXJuIHN1bTsNCn0NCg0KZnVuY3Rpb24gSHlwb3RUZXN0KCkNCnsNCglsZXQgc3VtID0gMDsNCglm
b3IgKGxldCBpID0gMDsgaSA8IElURVJBVElPTlM7ICsraSkNCgl7DQoJCWNvbnN0IGR4ID0gTWF0
aC5yYW5kb20oKTsNCgkJY29uc3QgZHkgPSBNYXRoLnJhbmRvbSgpOw0KCQljb25zdCBkeiA9IE1h
dGgucmFuZG9tKCk7DQoJCXN1bSArPSBNYXRoLmh5cG90KGR4LCBkeSwgZHopOw0KCX0NCglyZXR1
cm4gc3VtOw0KfQ0KDQpmdW5jdGlvbiBSdW5UZXN0KGZuLCBkZXNjLCBudW1iZXIpDQp7DQoJY29u
c29sZS5sb2coYFJ1bm5pbmcgdGVzdCAnJHtkZXNjfScgIyR7bnVtYmVyfS4uLmApOw0KCWNvbnN0
IHN0YXJ0VGltZSA9IHBlcmZvcm1hbmNlLm5vdygpOw0KCQ0KCWNvbnN0IHJlc3VsdCA9IGZuKCk7
DQoJDQoJY29uc29sZS5sb2coYEZpbmlzaGVkLCB0b29rICR7cGVyZm9ybWFuY2Uubm93KCkgLSBz
dGFydFRpbWV9IG1zIFtyZXN1bHQgd2FzICR7cmVzdWx0fV1gKTsNCn0NCg0KZnVuY3Rpb24gUnVu
VGVzdHMoKQ0Kew0KCXdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IFJ1blRlc3QoU3FydFRlc3QsICJT
cXJ0IiwgMSksIDEwMCk7DQoJd2luZG93LnNldFRpbWVvdXQoKCkgPT4gUnVuVGVzdChTcXJ0VGVz
dCwgIlNxcnQiLCAyKSwgMjAwKTsNCgl3aW5kb3cuc2V0VGltZW91dCgoKSA9PiBSdW5UZXN0KFNx
cnRUZXN0LCAiU3FydCIsIDMpLCAzMDApOw0KCQ0KCXdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IFJ1
blRlc3QoSHlwb3RUZXN0LCAiSHlwb3QiLCAxKSwgNDAwKTsNCgl3aW5kb3cuc2V0VGltZW91dCgo
KSA9PiBSdW5UZXN0KEh5cG90VGVzdCwgIkh5cG90IiwgMiksIDUwMCk7DQoJd2luZG93LnNldFRp
bWVvdXQoKCkgPT4gUnVuVGVzdChIeXBvdFRlc3QsICJIeXBvdCIsIDMpLCA2MDApOw0KfQ0KDQpS
dW5UZXN0cygpOw0KPC9zY3JpcHQ+
</data>

          </attachment>
      

    </bug>

</bugzilla>