_std::hypot
_ のドキュメントは次のように述べています:
計算の中間段階で過度のオーバーフローやアンダーフローを発生させることなく、xとyの2乗の合計の平方根を計算します。
些細なsqrt(x*x + y*y)
に対して_std::hypot
_を使用する必要があるテストケースを思いつくのに苦労しています。
次のテストは、_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;
}
}
_
ですから、私はガイダンスを求めています。はるかに高速なstd::hypot(x,y)
で正しい結果を得るには、いつstd::sqrt(x*x + y*y)
を使用する必要がありますか。
説明:x
とy
が浮動小数点数の場合に当てはまる答えを探しています。つまり比較:
_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の2乗の合計の平方根を計算します計算の中間段階で過度のオーバーフローまたはアンダーフローなし。
x*x + y*y
がオーバーフローした場合、手動で計算を実行すると、間違った答えが返されます。ただし、std::hypot
を使用すると、中間計算がオーバーフローしないことが保証されます。
この格差の例を見ることができます ここ 。
プラットフォームに関連する表現がオーバーフローしないことがわかっている数値を使用している場合は、ナイーブバージョンを喜んで使用できます。