Когда я должен использовать hypot над sqrtl? - PullRequest
6 голосов
/ 13 апреля 2020

Здесь уже обсуждалось , что hypot медленнее, чем sqrt, потому что он обрабатывает случаи, когда два входа огромны или крошечны, так что sqrt ошибочно вернет inf или 0.

Однако, согласно некоторому тесту , hypot даже медленнее, чем сначала преобразовать в более высокую точность, а затем выполнить тривиальный расчет и выполнить обратное преобразование.

Итак, в каком случае я должен использовать hypot? Проблема возникает только в том случае, если нет большего типа с плавающей точкой и переполнения?

EDIT: sqrtl и hypot отличаются на входе a=1,b=1.8e-8, но sqrtl возвращает более точный результат:

hypot 1.0
sqrtl 1.000000000000000222044604925031
exact 1.000000000000000161999999999999986878000000000002125764000...
1+eps 1.0000000000000002220446049250313080847263336181640625

Точные строки, в которые добавляется eps к результату, отображаются здесь

Ответы [ 2 ]

4 голосов
/ 13 апреля 2020

Функция double hypot(double x, double y) вычисляет длину гипотенузы прямоугольного треугольника со сторонами x и y или расстояние от точки (x, y) до начала координат. Использование этой функции вместо прямой формулы sqrt(x * x + y * y) целесообразно, поскольку ошибка намного меньше. Действительно, для некоторых значений аргумента возведение в квадрат может привести к потере точности (если значение слишком мало, возведение в квадрат дает 0), или бесконечный результат значения слишком велик. Использование прямой формулы может привести к неверным результатам, даже в пределах ожидаемого диапазона: max(|x|, |y|) <= hypot(x, y) <= sqrt(2) * max(|x|, |y|).

hypot() использует альтернативные формулы, чтобы избежать этих патологических случаев, с некоторыми затратами на производительность, но если вы знаете, что ваши аргументы не вызывая потери точности или бесконечного результата, и вам нужна дополнительная скорость за счет корректности, вы можете использовать простую формулу sqrt(x * x + y * y).

Как правило, если x и y равны нулю или имеют абсолютное значение от 1e-100 до 1e + 100 и 1e-4 <= |x|/|y| <= 1e4, sqrt должно быть в порядке.

В вашем примере b очень мало по сравнению с a, что приводит к полной потере точности, поскольку b*b на настолько меньше, чем a*a, что a*a + b*b невозможно отличить от a*a. Использование long double для промежуточного результата дает вам достаточную дополнительную точность для a*a + b*b, чтобы быть представленным с достаточной точностью для sqrt для вычисления значимого результата. Но поскольку sqrt(1 + epsilon) приблизительно равно 1 + epsilon/2, результат в любом случае пригоден для использования.

2 голосов
/ 13 апреля 2020

Это потому, что вы сравниваете вещи, которые вы не должны ... hypot не конвертирует с более высокой точностью, вычисляет квадрат root и конвертирует обратно с более низкой точностью . hypot использует специальный алгоритм, чтобы гарантировать, что вычисление даст хороший результат, даже если числа являются большими или крошечными для заданной точности. Существует hypotl для вычисления длины для длинных двойных чисел, которую вы не можете правильно вычислить, используя sqrtl. И, long double может быть точно такого же типа, как double ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...