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.