Как правильно вычислить округленные тригонометрические функции в градусах?
Как я могу определить тригонометрические функции, которые принимают аргументы в градусах вместо обычных радианов, и вычислить правильно округленные результаты для этих аргументов?
Умножение аргумента на M_PI/180.0
перед передачей его соответствующей функции в радианах не работает, т.к. M_PI/180.0
не π/180. Раздел 5.5 Руководства по арифметике с плавающей точкой предлагает метод для вычисления правильно округленного произведения аргумента на π/180, но некоторые аргументы все равно будут такими, что этот продукт будет близок к средней точке между двумя последовательными представимыми числами с плавающей точкой, а затем применение даже правильно округленной функции в радианах может привести к неверному конечному результату.
Две стратегии, которые могут работать в одиночку или в комбинации, используют более высокую точность и использование sinpi
,cospi
, tanpi
тригонометрические функции из CRlibm, которые вычисляют соответственно sin(πx)
, cos(πx)
а также tan(πx)
,
Для последней стратегии остается проблема деления на 180, что не является точным для многих аргументов.
Что касается стратегии более высокой точности (умножение аргумента на представление с расширенной точностью π/180, затем применение функции расширенной точности в радианах), может возникнуть проблема с "точными" случаями. Теорема, которая утверждает, что единственные рациональные результаты sin
, cos
а также tan
для рационального аргумента получены в 0
относится только к радианам. Очевидно, что это не относится к версиям степеней, и если для некоторого ввода x с плавающей запятой sindeg(x) является точно средней точкой между двумя последовательными представимыми числами с плавающей запятой, то никакой промежуточной точности недостаточно, чтобы гарантировать, что окончательная результат правильно округлен.
4 ответа
Единственные рациональные q
для которого cosdeg(360q)
рационально иметь 1, 2, 3, 4 или 6 в качестве знаменателя. Эта статья Йерга Янеля содержит краткое и красивое доказательство с использованием теории поля в разделе 6. (Действительно, автор характеризует степень алгебраического числа cosdeg(360q)
используя функцию Эйлера.) Таким образом, с плавающей запятой нет q
такой, что cosdeg(360q)
находится на полпути между двумя соседними числами с плавающей точкой.
Так что я думаю, что ответ "примерно так же, как вы реализуете sin
и друзья радианам ", хотя @gnasher729 замечательно показывает, что сокращение аргументов для степеней намного, намного приятнее.
Это трудно. С положительной стороны, вы можете уменьшить аргумент до +/- 45 градусов точно. Таким образом, вам нужно правильно округлить результаты в пределах +/- 45 градусов. Для очень маленького x, sin (x) составляет около x * (pi / 180), что достаточно сложно, чтобы точно округлить.
Например, чтобы получить в основном правильно округленные результаты для функции синуса, возьмите -45 <= x <= 45. Разбейте x на xhi = round (512 x) / 512 и xlo = x - xhi. Пусть sin (x градусов) ≈ ax - bx^3. Округлите a и b так, чтобы s (x) a*xhi - b * (xhi^3) вычислилось точно. Вычислите остаток греха (x градусов) - s (x) тщательно; ошибка округления должна быть довольно маленькой, потому что результат мал. Добавьте к s (x), это в большинстве случаев даст правильно округленный результат.
Ну, это сложный вопрос. Позвольте мне уточнить некоторые моменты:
- Какая точность требуется для вывода? Это стандарт IEEE 754 одинарной или двойной точности или нестандартный? Более того, я предполагаю, что вход, то есть тот, который представлен в градусах, должен быть представлен с той же точностью, что и выходные данные, как это имеет место для нормальных радианных входов.
- Каковы ваши показатели производительности? CRlibm оптимизирован для получения правильно округленных результатов с двойной точностью. С другой стороны, MPFR используется для произвольной точности, но он намного медленнее, чем CRlibm, когда требуется вывод только двойной точности.
- Какой у вас рабочий диапазон? т.е. [минимальный аргумент, максимальный аргумент]? Это важно для CRlibm, поскольку он работает для диапазонов двойной точности. Тем не менее, это не будет иметь большого значения для MPFR.
Я в основном рекомендую использовать MPFR, если вы обязаны использовать ввод только в градусах. Напомню, что любой аргумент в градусах, когда он умножается на (Pi/180), приводит к трансцендентному числу. Однако то, что передается в тригонометрическую функцию, является представлением с плавающей точкой, округленным, предпочтительно округленным до ближайшего целого числа, до рабочей точности.
Я рекомендую вам сделать следующее:
- Используйте MPFR, используйте библиотеку C, когда это возможно, поскольку она предлагает гораздо лучшую производительность, чем ее привязки.
- Установите точность MPFR намного выше, чем ваша целевая точность. Например (точность цели + 300). Делая это, вы избегаете любой потери точности для операции ((Аргумент * Пи)/180). Это можно легко сделать в библиотеке MPFR C с помощью mpfr_set_default_prec().
- Выполните операцию: X_n=(Аргумент *Pi)/180, а затем выполните Sin(X_n) или любую другую функцию, которую вы хотите. В MPFR есть постоянная пи, которая представлена в пределах вашей рабочей точности
- Округлите свой результат до целевой точности.
"Элементарные функции" Мюллера показывают статистически, что большинство, НЕ ВСЕ, сложных случаев правильно округляются, если рабочая точность немного больше, чем удвоенная целевая точность. Но в вашем случае, поскольку вход теоретически трансцендентен, для безопасности, за счет производительности, рабочая точность намного выше целевой. На самом деле, 10х вполне достаточно для почти 100% случаев, если вам требуется конечный результат с удвоенной точностью.
Если вам нужна низкая точность, т. Е. Одинарная или меньшая точность, можно провести исчерпывающий тест, чтобы выбрать самую низкую рабочую точность, при которой все случаи правильно округлены.
Сначала нужно определить точные случаи, и на это уже дан ответ. Теперь, для других случаев, есть хорошо известная проблема дилеммы производителя столов. Если ваша арифметика имеет фиксированную (и небольшую) точность и вы хотите получить сертифицированную оценку промежуточной точности, которая может потребоваться, есть два известных решения:
- Получите оценку, основанную на теореме Нестеренко и Вальдшмидта, как описано в разделе 4.3 моей кандидатской диссертации (кстати, я думаю, что это также дало бы вам форму точных случаев). Но вы получите очень большие границы точности (хотя бы несколько миллионов бит?).
- Найдите самый сложный случай. Достаточно выполнить поиск в [0,180], поскольку любой больший аргумент сведется к значению в [0,180] с той же дробной частью (поскольку точка является целым числом).