web-dev-qa-db-ja.com

`std :: sqrt(x * x + y * y)`よりも `std :: hypot(x、y)`を使用する場合

_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)を使用する必要がありますか。

説明:xyが浮動小数点数の場合に当てはまる答えを探しています。つまり比較:

_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);
_
28
Emily L.

答えはあなたが引用したドキュメントにあります

Xとyの2乗の合計の平方根を計算します計算の中間段階で過度のオーバーフローまたはアンダーフローなし

x*x + y*yがオーバーフローした場合、手動で計算を実行すると、間違った答えが返されます。ただし、std::hypotを使用すると、中間計算がオーバーフローしないことが保証されます。

この格差の例を見ることができます ここ

プラットフォームに関連する表現がオーバーフローしないことがわかっている数値を使用している場合は、ナイーブバージョンを喜んで使用できます。

24
TartanLlama