Стабильный Котангенс - PullRequest
       6

Стабильный Котангенс

17 голосов
/ 17 сентября 2010

Есть ли более стабильная реализация функции котангенса, чем return 1.0 / tan (x) ;?

Ответы [ 3 ]

38 голосов
/ 18 сентября 2010

cot(x) = cos(x)/sin(x) должен быть численно более устойчивым вблизи π / 2, чем cot(x) = 1/tan(x). Вы можете эффективно реализовать это, используя sincos на платформах, которые его имеют.

Другая возможность - cot(x) = tan(M_PI_2 - x). Это должно быть быстрее, чем указано выше (даже если доступно sincos), но оно также может быть менее точным, поскольку M_PI_2, конечно, является лишь приближением трансцендентного числа π / 2, поэтому разница M_PI_2 - x не быть точным до полной ширины double мантиссы - на самом деле, если вам не повезет, он может иметь только несколько значащих битов.

2 голосов
/ 03 июля 2019

TL; DR No.

Как правило, при поиске источников неточности следует в первую очередь заботиться о сложениях и вычитаниях, которые могут привести к проблеме вычитания отмены.Умножения и деления, как правило, безвредны для точности, кроме добавления дополнительной ошибки округления, но могут вызывать проблемы из-за переполнения и недостаточного заполнения при промежуточных вычислениях.

Ни один номер машины x не может быть достаточно близок к кратным от π / 2 довызывает переполнение tan(x), поэтому tan(x) является четко определенным и конечным для всех кодировок с плавающей запятой для любого из форматов с плавающей запятой IEEE-754, и, соответственно, cot(x) = 1.0 / tan(x).

Это легко продемонстрировать, выполнив исчерпывающий тест со всеми числовыми кодировками float, поскольку исчерпывающий тест с использованием double невозможен, за исключением, возможно, самых больших суперкомпьютеров, существующих на сегодняшний день.

Используя математическую библиотеку с точной реализацией tan() с максимальной ошибкой ~ = 0,5 ulp , мы обнаруживаем, что при вычислении cot(x) = 1.0 / tan(x) максимальная ошибка составляет менее 1,5 ulp, где сравнивается дополнительная ошибкаСамому tan() способствует ошибка округления деления.

Повторение этого исчерпывающего теста для всех float значений с cot(x) = cos(x) / sin(x), где sin() и cos() вычисляются с максимальной ошибкойиз ~ = 0.5 ulp, мы находим, что максимальная ошибка в cot() составляет менее 2.0 ulps, поэтому немного больше.Это легко объяснить наличием трех источников ошибок вместо двух в предыдущей формуле.

Наконец, cot(x) = tan (M_PI_2 - x) страдает от проблемы вычитания, упомянутой ранее, когда x близок к M_PI_2, и от проблемычто в арифметике с плавающей точкой конечной точности M_PI_2 - x == M_PI_2, когда x достаточно мала по величине.Это может привести к очень большим ошибкам, в результате которых у нас не останется действительных битов.

0 голосов
/ 03 июля 2019

Если учитывать угол между двумя векторами (v и w), вы также можете получить котангенс следующим образом (используя Eigen :: Vector3d ):

inline double cot(Eigen::Vector3d v, Eigen::Vector3d w) { 
    return( v.dot(w) / (v.cross(w).norm()) ); 
};

При тета-угле между v и w указанная выше функция верна, поскольку:

  • | v x w | = | v |. | w | .sin (theta)
  • против w = | v |. | w | .cos (theta)
  • детская кроватка (тэта) = cos (тэта) / грех (тэта) = (против. Ш) / | v x w |
...