何时使用`std :: hypot(x,y)`而不是`std :: sqrt(x*x + y*y)`

Emi*_* L. 26 c++ floating-accuracy c++11

文件std::hypot说:

计算x和y的平方和的平方根,在计算的中间阶段没有过度溢出或下溢.

我很难设想一个std::hypot应该用于琐碎的测试用例sqrt(x*x + y*y).

以下测试表明,这std::hypot比天真计算慢大约20倍.

#include <iostream>
#include <chrono>
#include <random>
#include <algorithm>

int main(int, char**) {
    std::mt19937_64 mt;
    const auto samples = 10000000;
    std::vector<double> values(2 * samples);
    std::uniform_real_distribution<double> urd(-100.0, 100.0);
    std::generate_n(values.begin(), 2 * samples, [&]() {return urd(mt); });
    std::cout.precision(15);

    {
        double sum = 0;
        auto s = std::chrono::steady_clock::now();
        for (auto i = 0; i < 2 * samples; i += 2) {
            sum += std::hypot(values[i], values[i + 1]);
        }
        auto e = std::chrono::steady_clock::now();
        std::cout << std::fixed <<std::chrono::duration_cast<std::chrono::microseconds>(e - s).count() << "us --- s:" << sum << std::endl;
    }
    {
        double sum = 0;
        auto s = std::chrono::steady_clock::now();
        for (auto i = 0; i < 2 * samples; i += 2) {
            sum += std::sqrt(values[i]* values[i] + values[i + 1]* values[i + 1]);
        }
        auto e = std::chrono::steady_clock::now();
        std::cout << std::fixed << std::chrono::duration_cast<std::chrono::microseconds>(e - s).count() << "us --- s:" << sum << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我要求指导,何时我必须使用std::hypot(x,y)以更快地获得正确的结果std::sqrt(x*x + y*y).

澄清:我正在寻找时适用的答案xy是浮点数.即比较:

double h = std::hypot(static_cast<double>(x),static_cast<double>(y));
Run Code Online (Sandbox Code Playgroud)

至:

double xx = static_cast<double>(x);
double yy = static_cast<double>(y);
double h = std::sqrt(xx*xx + yy*yy);
Run Code Online (Sandbox Code Playgroud)

Tar*_*ama 25

答案在您引用的文档中

计算x和y的平方和的平方根,在计算的中间阶段没有过度溢出或下溢.

如果x*x + y*y溢出,那么如果你手动执行计算,你将得到错误的答案.std::hypot但是,如果使用,则可以保证中间计算不会溢出.

你可以在这里看到这种差异的一个例子.

如果您正在使用您知道不会溢出平台相关表示的数字,您可以愉快地使用天真版本.

  • @EmilyL.怎么样[这个](http://coliru.stacked-crooked.com/a/0c36801163209d24)? (4认同)
  • `std :: hypot`的参数是float-pont类型,所以如果你在这里使用int它也将被提升为浮点数. (3认同)
  • @艾米丽L。对于给定的平台,当然。更一般地说,当它超过“std::numeric_limits&lt;double&gt;::max()”时。 (2认同)