Взгляните на эти два треугольника. Они совершенно одинаковой формы, т. е. углы у них одинаковые, но у второго стороны в два раза длиннее, чем у первого.

Если мы вычислим синус угла в 30 градусов, мы получим 0,5, что означает, что сторона, противоположная углу в 30 градусов, равна 0,5 или половине длины гипотенузы. Это относится не только к двум показанным здесь треугольникам, но и к любому треугольнику с одним углом в 30 градусов, независимо от его размера.

Есть две другие связанные тригонометрические функции, косинус и тангенс, которые работают таким же образом. Косинус дает отношение прилежащей стороны (горизонтали на диаграмме) к гипотенузе, а тангенс дает отношение противолежащей (вертикальной) стороны к прилежащей стороне.

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

Любая среда программирования или карманный калькулятор предоставят функции синуса, косинуса и тангенса, поэтому вам вряд ли придется вычислять их самостоятельно или программировать с нуля. Однако, если вам посчастливилось быть фанатом чисел, вы все равно хотели бы знать, как это сделать, и это полезный небольшой проект по программированию.

Полиномы Тейлора

Возможно, вы знакомы с формулами в формате y = ax + b (который технически известен как многочлен первого порядка). Такая формула позволяет вычислить значение y для любого заданного значения x, используя простую арифметику — вы просто умножаете x на константу a, а затем добавьте еще одну константу b.

К сожалению, для некоторых функций, таких как синус и косинус, таких формул не существует, поэтому их необходимо вычислять с использованием таких методов, как полиномы Тейлора. Возможно, вы захотите прочитать Статью в Википедии, отметив, в частности, их использование для вычисления синусов.

Формула полинома Тейлора для синуса выглядит немного устрашающе в формах, представленных Википедией:

но во второй форме мы видим, что он состоит из простого повторяющегося термина:

В этой формуле следует отметить четыре момента:

  • Начнем с угла x (в радианах), для которого мы хотим вычислить синус
  • Затем мы поочередно вычитаем или добавляем повторяющийся член
  • Степени и факториалы* начинаются с 3 и увеличиваются на 2 на каждой итерации.
  • Чем больше терминов мы вычисляем, тем большую точность получаем

*Факториал числа представляет собой произведение всех чисел от 1 до этого числа и обозначается восклицательным знаком. Например 5! = 1*2*3*4*5=120.

Проект

Этот проект будет состоять из модуля Python, реализующего функцию sine_of_radians, и небольшого количества кода для демонстрации результатов.

При написании функции, которая возвращает или принимает в качестве аргумента значение, которое может быть выражено в разных единицах измерения, я придерживаюсь соглашения о включении единицы измерения в имена функции или аргумента. В этом случае углы могут быть выражены в градусах или радианах, поэтому я включил слово радианы в название функции.

(Собственная функция Python math.sine также принимает радианы — интересно, сколько тысяч людей на протяжении многих лет были сбиты с толку, получая «неправильный» ответ, когда они задавали угол в градусах!)

В коде используется проект Запоминание факториалов, который я недавно опубликовал, чтобы избежать повторного вычисления факториалов. Если вы вычисляете большое количество тригонометрических функций, например, при построении синусоиды, повторяющиеся накладные расходы на вычисление факториалов могут быть значительными, поэтому запоминание (сохранение предварительно вычисленных значений) может повысить эффективность.

Проект состоит из следующих файлов, которые вы можете клонировать/скачать с Github.

  • факториалмемоизация.py
  • taylorseries.py
  • main.py

Я не буду повторять здесь код factorialmemoization.py, но он включен в репозиторий и, конечно же, в сообщение, ссылка на которое приведена выше.

Это taylorseries.py.

Функция sine_of_radians принимает в качестве аргументов угол в радианах, синус которого мы хотим вычислить, и градус, в котором мы хотим вычислить функцию.

Максимальное число в показанной выше последовательности 3,5,7… формулы ряда Тейлора известно — довольно запутанно — как степень полинома и не имеет ничего общего со значением слова «градус» как единицы угла. Минимум 3, и я произвольно использовал 63 как максимум; если аргумент степени находится за пределами этого диапазона, возникает исключение.

Как я упоминал выше, вычисление ряда Тейлора включает в себя чередование вычитания и добавления следующего члена. Чтобы сократить громоздкий код, мы всегда ДОБАВЛЯЕМ следующий член, но сначала умножаем его на переменную с именем multiplier, которая будет переключаться между -1 и 1. Она инициализируется значением -1, но умножается на -1 на каждой итерации. Перед использованием в цикле переменная sine инициализируется значением угла.

Степень, до которой мы хотим вычислить ряд Тейлора, соответствует максимальному факториалу, который нам нужен, поэтому это значение используется для построения объекта FactorialMemoization для предварительного вычисления необходимых факториалов.

Цикл повторяется от 3 до указанной степени, каждый раз увеличиваясь на 2. Затем оценивается текущий член с использованием currentdegree в качестве показателя степени и для получения предварительно вычисленного факториала. Затем знак множителя «переворачивается», и когда цикл завершается, мы возвращаем sine.

Теперь нам просто нужно попробовать это.

Сначала мы распечатываем заголовки столбцов таблицы; в таблице будут показаны градусы, синус степеней, рассчитанный с использованием функции Python math.sine, и, наконец, синусы, рассчитанные в различных степенях с помощью нашей функции полинома Тейлора. Значения math.sine будут считаться окончательными и использоваться для проверки точности наших собственных значений. Затем мы входим в цикл, печатая строку для каждого угла со значениями для каждого столбца.

Теперь мы можем запустить код с помощью этой команды в терминале.

python3.8 main.py

Это выход.

Как видите, для меньших углов синусы достаточно точны по сравнению со значениями функции Python math.sin, даже при меньших степенях полинома Тейлора, и полностью точны до 6 знаков после запятой до 90 градусов при степени 11.

После 90 градусов значения становятся все более неточными. Для 360 градусов значение Тейлора составляет около -35 при степени 3, когда оно должно быть равно 0, и даже при степени 11 оно составляет около -3.

Вы можете поэкспериментировать, чтобы увидеть, как более высокие степени полинома дают более точные результаты для более высоких градусов угла.

Из-за симметричного и циклического характера функции синуса неточность за пределами 90 градусов не является проблемой — мы можем легко использовать значения от 0 до 90 градусов для любого угла, сдвигая и/или отрицая их на соответствующую величину.

Было бы полезно увидеть график различных синусоид вышеперечисленных значений, и это сформирует будущий пост.