3
$\begingroup$

I've checked the information on cppreference.com and found that there are only 2 and 3 input hypot function. I am wondering why not implement the variadic version of hypot function in standard library as below.

//  hypot Template Function Implementation
template<typename... Args>
auto hypot(Args... args)
{
    return std::sqrt((std::pow(args, 2.0) + ...));
}
$\endgroup$
8
  • $\begingroup$ The naïve algorithm runs the risk of overflow/underflow. In the documentation, it mentions that the 2-argument and 3-argument versions are designed to resist undue over-/underflow, so it would probably be significantly more difficult/slower to implement a variadic version with this behaviour. $\endgroup$ Commented Dec 25, 2024 at 16:51
  • 1
    $\begingroup$ Because 2 and 3 argument versions are used vastly more often. $\endgroup$ Commented Dec 25, 2024 at 20:05
  • $\begingroup$ As I often pointed out when asked why a one-line method was not in the .NET BCL -- it's hardly worth the effort to spec, implement, test, document and maintain forever a method that the user can write in a minute when they need it! $\endgroup$ Commented Dec 29, 2024 at 1:58
  • 2
    $\begingroup$ @EricLippert: The one line implementation of hypot is no good, since the whole point of the function is to give precise results in cases where the trivial implementation would suffer overflow or loss of precision in intermediate steps. Writing a good version of hypot even for two inputs is not straightforward, let alone n inputs. $\endgroup$ Commented Dec 29, 2024 at 8:09
  • 1
    $\begingroup$ For instance, openbsd's implementation is about 80 lines: github.com/openbsd/src/blob/master/lib/libm/src/e_hypot.c $\endgroup$ Commented Dec 29, 2024 at 8:13

1 Answer 1

3
$\begingroup$

The Proposal to Introduce a 3-Argument Overload to std::hypot gave the following justification:

We considered proposing a variadic overload of std::hypot, so that it could be further generalized to compute the Euclidean norm of a vector of arbitrary dimension. However, the general utility of such a feature is not immediately clear; we judge it best (at least for now) to relegate such a feature to domain-specific libraries, like the GNU Scientific Library [GSL].

They further justified the need for a three-argument hypothenuse:

The std::hypot function, adopted for C++11 via [N1836] and later [N2009], has proven to be a useful general math utility function. One major application of this function is the calculation of the distance between 2 points in a 2-dimensional space. However, this is not useful enough, as many scientific and engineering applications (e.g. n-body simulations) model points in 3- dimensional space. [...] Using only the current definition of std::hypot, the distance between 2 points in a 3- dimensional space can at best be calculated as such:

auto d = std::hypot(x2-x1, std::hypot(y2-y1, z2-z1));

This code is far from optimal because it involves 2 function calls to std::hypot as well as an extra square-root and power operation.

The obvious implementation of the variadic hypothenuse iterates the two-argument hypothenuse, collapsing two numbers into one with each iteration. My implementation is included below. For three arguments, it is equivalent to the solution the authors described as "far from optimal" in their proposal.

namespace std
{
    template<typename Arg1, typename Arg2, typename... Args>
    auto hypot(Arg1 arg1, Arg2 arg2, Args... args)
    {
        return hypot(hypot(arg1, arg2), args...);
    }
}

Your implementation with std::pow and std::sqrt is inaccurate and prone to overflow.


In summary:

  • There is a strong need for a good two-argument and three-argument hypothenuse.
  • The obvious variadic implemenations are either slow or inaccurate, so special cases for two and three arguments are needed anyway.
  • There is little need for a hypothenuse with four or more arguments.
  • There is need for a vector norm (begin + end iterators, C++20 ranges) but that's a different beast.
$\endgroup$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.