c++ c++11 floating-accuracy

c++ - Cuándo usar `std:: hypot(x, y)` sobre `std:: sqrt(x*x+y*y)`



c++11 floating-accuracy (1)

La documentación de std::hypot dice que:

Calcula la raíz cuadrada de la suma de los cuadrados de x e y, sin desbordamiento o subdesbordamiento indebido en las etapas intermedias del cálculo.

Me cuesta concebir un caso de prueba en el que se deba usar std::hypot sobre el sqrt(x*x + y*y) trivial sqrt(x*x + y*y) .

La siguiente prueba muestra que std::hypot es aproximadamente 20x más lento que el cálculo ingenuo.

#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; } }

Así que estoy pidiendo orientación, ¿cuándo debo usar std::hypot(x,y) para obtener resultados correctos sobre el std::sqrt(x*x + y*y) mucho más rápido?

Aclaración: estoy buscando respuestas que se apliquen cuando x e y son números de punto flotante. Es decir, comparar

double h = std::hypot(static_cast<double>(x),static_cast<double>(y));

a:

double xx = static_cast<double>(x); double yy = static_cast<double>(y); double h = std::sqrt(xx*xx + yy*yy);


La respuesta está en la documentación citada.

Calcula la raíz cuadrada de la suma de los cuadrados de x e y, sin desbordamiento o subdesbordamiento indebido en las etapas intermedias del cálculo .

Si x*x + y*y desborda, entonces si realiza el cálculo manualmente, obtendrá la respuesta incorrecta. Sin embargo, si usa std::hypot , garantiza que los cálculos intermedios no se desbordarán.

Puedes ver un ejemplo de esta disparidad here .

Si está trabajando con números que sabe que no desbordarán la representación relevante para su plataforma, puede usar la versión ingenua.