何时在`std :: sqrt(x * x + y * y)上使用`std :: hypot(x,y)`
std :: hypot
文档表示:
计算x和y平方和的平方根,中间不会出现不适当的上溢或下溢
Computes the square root of the sum of the squares of x and y, without undue overflow or underflow at intermediate stages of the computation.
我很难设想一个测试用例,其中 std :: hypot
应该用于普通的 sqrt(x * x + y * y)
。
I struggle to conceive a test case where std::hypot
should be used over the trivial sqrt(x*x + y*y)
.
以下测试表明 std :: hypot
大约比朴素的计算慢20倍。
The following test shows that std::hypot
is roughly 20x slower than the naive calculation.
#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;
}
}
所以我要寻求指导,我什么时候必须使用 std :: hypot(x,y)
在更快的 std :: sqrt(x * x + y * y)上获得正确的结果
。
So I'm asking for guidance, when must I use std::hypot(x,y)
to obtain correct results over the much faster std::sqrt(x*x + y*y)
.
说明:我正在寻找 x时适用的答案
和 y
是浮点数。即比较:
Clarification: I'm looking for answers that apply when x
and y
are floating point numbers. I.e. compare:
double h = std::hypot(static_cast<double>(x),static_cast<double>(y));
至:
double xx = static_cast<double>(x);
double yy = static_cast<double>(y);
double h = std::sqrt(xx*xx + yy*yy);
答案在您引用的文档中
计算x和y的平方和的平方根,在计算的中间阶段不会出现不必要的上溢或下溢。
如果 x * x + y * y
溢出,则如果手动执行计算,则会得到错误的答案。但是,如果使用 std :: hypot
,则可以保证中间计算不会溢出。
If x*x + y*y
overflows, then if you carry out the calculation manually, you'll get the wrong answer. If you use std::hypot
, however, it guarantees that the intermediate calculations will not overflow.
您可以请参见此处。
如果您使用的数字不会超出您平台的相关表示,则可以很高兴使用朴素的版本。
If you are working with numbers which you know will not overflow the relevant representation for your platform, you can happily use the naive version.