Найти тему
Репетитор IT mentor

Проблемы использования тригонометрических функций в программировании

Проблема 1

В большинстве языков программирования тригонометрические функции принимают аргумент, который имеет смысл угла, в виде радиан, а не градусов. Поэтому многие начинающие разработчики долго пытаются отловить ошибку в математических вычислениях. Ведь, написав sin(30) они ожидают получить 0.5, так как думают, что компилятор воспринимает это выражение как синус тридцати градусов. Но вместо ожиданий получают -0.988032. При этом компилятор не выдает никаких синтаксических ошибок. С чем это связано и почему так происходит? Дело в том, как мы уже сказали ранее, компилятор думает, что под синусом стоит 30 радиан. Что соответствует в градусах 30 ⋅ ( 180 / π ) ~ 1718.87339°, что дает нам sin(1718.87339°) ~ - 0.988031612. И значение вполне нормальное, а ошибку уловить бывает очень трудно.

Приведем пример в виде кода:

Наблюдаем явное несоответствие :(
Наблюдаем явное несоответствие :(

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

Теперь уже всё работает как хотелось бы :)
Теперь уже всё работает как хотелось бы :)

Проблема 2

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

-3

Представим такую ситуацию, что мы хотим вращать какой-то объект-стрелку за мышкой. Координаты мыши (x; y) мы получаем от события перемещения курсора. Далее мы хотим получить угол альфа. Возникает идея получать его через арктангенс отношения y к x. В C/C++ для этого существует функция atan2() , определенная в модуле math.h (для C) и cmath ( для C++ ).

y_coord - Значение с плавающей точкой, представленное как  у-координата.
x_coord - Значение с плавающей точкой, представленное как  x-координата.
y_coord - Значение с плавающей точкой, представленное как у-координата. x_coord - Значение с плавающей точкой, представленное как x-координата.

Функция, с двумя параметрами, вычисляет арктангенс и возвращает значение арктангенса y_coord/x_coord , выраженное в радианах.

Возвращаемое значение: Угол арктангенса y_coord /x_coord, в интервале: β [-π,+π]. И вот здесь как раз скрыт подвох (!).

При анимации движения/поворота вращение может резко начаться в другую сторону, т.к. после угла +π сразу идет угол -π, можно сказать, что это точка бифуркации, где резко меняется знак. Этот функциональный разрыв лучше всего устранить так, чтобы угол плавно менялся от 0 до 2π или от 0° до 360°.

Первоначальная идею я сначала попробовал реализовать следующими образом:

(  https://onlinegdb.com/HJFXUA-Ld  )
( https://onlinegdb.com/HJFXUA-Ld )

И тут возникла интересная ошибка... На консоль выдало 224 градуса, вместо 225. Вроде мелочь, а неприятно. Даже не ожидал такого. Программа возвращает 224, а должна 225, если представить тригонометрический круг. Увеличил точность числа pi, всё равно 224.

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

Поэтому, были найдены решения этой проблемы 3 способами:

Все эти решения корректно возвращают 225 градусов для x = - 1 и y = -1
Все эти решения корректно возвращают 225 градусов для x = - 1 и y = -1

Таким образом, получилась функция, которая возвращает угол в диапазоне от 0° до 360°, что является удобным для программирования вращения различных предметов.

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

Проблема 3

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

Чаще всего нам необходим cos(α) или sin(α) в каких-либо дальнейших вычислениях. А найти их можно, воспользовавшись свойствами векторного и скалярного произведения векторов.

-7
Пример, показывающий как можно наиболее простым способом найти sin() и cos() нужного угла между двумя векторами. C++.
Пример, показывающий как можно наиболее простым способом найти sin() и cos() нужного угла между двумя векторами. C++.

А с какими проблемами, связанными с геометрией или тригонометрией, вы сталкивались при программировании своих проектов? Расскажите об этом в комментариях.

Если Вам нужна помощь или репетитор по физике, математике или информатике/программированию, Вы можете написать в мою группу Репетитор IT mentor в VK

Библиотека с книгами для физиков, математиков и программистов
Репетитор IT mentor в VK
Репетитор IT mentor в Instagram
Репетитор IT mentor в telegram