<p>The function <code>hypot</code> offers <strong>another</strong> approximation of the mathematical expression √(x<sup>2</sup> + y<sup>2</sup>), just like the floating-point expression <code>sqrt(x*x + y*y)</code> is an approximation of this same mathematical expression.</p>

<p>The function <code>hypot</code> is recommended because it solves very noticeable defects that are present in the floating-point computation <code>sqrt(x*x + y*y)</code> with very large or small values. For instance, if <code>x</code> is only a bit larger than the square root of the maximum finite floating-point value, <code>sqrt(x*x + y*y)</code> always produces <code>+inf</code> because <code>x*x</code> produces <code>+inf</code>.</p>

<p>Compare:</p>

<pre><code>&gt;&gt;&gt; x, y = 95E200, 168E200
&gt;&gt;&gt; sqrt(x*x + y*y), hypot(x, y)
(inf, 1.93e+202)
&gt;&gt;&gt; z, t = 95E-200, 168E-200
&gt;&gt;&gt; sqrt(z*z + t*t), hypot(z, t)
(0.0, 1.93e-198)
</code></pre>

<p>For these two (respectively very large and very small) pairs of inputs, <code>hypot</code> is doing fine, whereas <code>sqrt(x*x + y*y)</code> is catastrophically wrong.</p>

<hr>

<p>When the naïve version <code>sqrt(x*x + y*y)</code> works reasonably well (when the values <code>x</code> and <code>y</code> are neither very large nor very small), it can be may be more or less accurate than the function <code>hypot</code> depending on the values of <code>x</code> and <code>y</code>. They can both be expected to produce a result that is a few ULPs away from the mathematical result. But since they are different approximations obtained by different methods, they may differ (in the worst case by twice “a few ULPs”).</p>

<p>One typical implementation for <code>hypot(x, y)</code> is first to swap <code>x</code> and <code>y</code> if necessary so that <code>x</code> has the largest magnitude, and then compute <code>x * sqrt(1 + (y/x)*(y/x))</code>. This solves the problem with <code>x*x</code> overflowing. As a side-effect, it means that <strong>even when there is no overflow</strong>, the result is slightly different from <code>sqrt(x*x + y*y)</code>.</p>

<p>Note that it's normal that <code>sqrt(x*x + y*y)</code> is more precise when you apply it to small integers (as you do in your test): when <code>x</code> and <code>y</code> are small integers, <code>x*x</code> and <code>y*y</code> and their sum can be computed exactly as floating-point values. If this sum is the square of an integer, the floating-point function <code>sqrt</code> can only compute this integer. In short, in this scenario the computations, despite being floating-point, are exact from beginning to end. In contrast, the typical <code>hypot</code> implementation above starts by computing <code>x/y</code> (in your test, <code>95.0/168.0</code>), and this result is not in general representable exactly as a floating-point value. The first step already incurs an approximation, and this approximation can result in the final result being wrong (as it is in your test)!</p>

<hr>

<p>There is no standard algorithm for <code>hypot</code>: it is only expected to compute a good approximation of the mathematical expression √(x<sup>2</sup> + y<sup>2</sup>) while avoiding the overflow and underflow problems. <a href="https://arxiv.org/pdf/1904.09481.pdf" rel="nofollow noreferrer">This article</a> shows different implementations, and points out that the popular implementation that I mentioned sacrifices accuracy to avoid overflow and underflow (but the article also provides a floating-point implementation for <code>hypot</code> that is <strong>more accurate</strong> than <code>sqrt(x*x + y*y)</code> even where <code>sqrt(x*x + y*y)</code> works).</p>
Why is sqrt(x*x + y*y) != math.hypot(x, y) in Python 3.8?
<p>I'm trying to run some tests on the shiny new Python 3.8 and noticed an issue with <a href="https://docs.python.org/3.8/library/math.html#math.hypot" rel="nofollow noreferrer"><code>math.hypot</code></a>. From the docs: </p>

<blockquote>
  <p>For a two dimensional point <code>(x, y)</code>, this is equivalent to computing
  the hypotenuse of a right triangle using the Pythagorean theorem,
  <code>sqrt(x*x + y*y)</code>.</p>
</blockquote>

<p>However, these are not equivalent in 3.8:</p>

<pre><code>&gt;&gt;&gt; from math import hypot, sqrt
&gt;&gt;&gt; x, y = 95, 168
&gt;&gt;&gt; sqrt(x*x + y*y), hypot(x, y), sqrt(x*x + y*y) == hypot(x, y)
(193.0, 193.00000000000003, False)
&gt;&gt;&gt; sqrt(x*x + y*y).is_integer(), hypot(x, y).is_integer()
(True, False)
</code></pre>

<p>In 3.7 both ways produce exactly the same result (<code>"193.0"</code>, which is considered an integer).</p>