Я хочу сравнить углы и получить представление о расстоянии между ними. Для этого приложения я работаю в градусах, но оно также будет работать для радианов и градов. Проблема с углами заключается в том, что они зависят от модульной арифметики, то есть от 0 до 360 градусов.
Скажем, один угол составляет 15 градусов, а другой - 45. Разница составляет 30 градусов, а угол 45 градусов больше, чем 15 градусов.
Но это ломается, когда у вас есть, скажем, 345 градусов и 30 градусов. Хотя они сравниваются правильно, разница между ними составляет 315 градусов вместо правильных 45 градусов.
Как я могу решить это? Я мог бы написать алгоритмический код:
if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;
Но я бы предпочел решение, которое избегает сравнений / ветвей и полностью полагается на арифметику.
mathematics
angles
Томас О
источник
источник
Ответы:
Вот моя упрощенная, без ветвлений, без сравнения, без мин / макс версия:
Удален по модулю, поскольку входы достаточно ограничены (спасибо Мартину за то, что указал на это).
Два пресса, три вычитания.
источник
Что заставляет вас думать, что 315 неверно? В одном направлении это 315 градусов, в другом направлении - 45. Вы хотите выбрать, какой из наименьших из двух возможных углов, и это, по сути, требует условного. Вы не можете решить эту проблему с помощью арифметики обтекания (т. Е. С помощью оператора модуля), поскольку при постепенном увеличении одного угла угол между ними увеличивается, пока не достигнет 180, а затем начнет уменьшаться.
Я думаю, что вы должны либо проверить оба угла и решить, какое направление вы хотите измерить, либо рассчитать оба направления и решить, какой результат вы хотите.
источник
Всегда есть способ сделать обе ветви и позволить результату сравнения выбрать один:
Я не знаю способа сделать это без сравнений , но обычно ветвь делает код медленным и длинным, а не сравнение. По крайней мере, на мой взгляд, это более читабельно, чем ответ Мартина (любой хороший программист на Си распознает его как эквивалент без ветвей и увидит, что он делает), но также менее эффективно.
Но, как я уже сказал в своем комментарии, алгоритмы без ответвлений хороши для процессоров с глубокими конвейерами и плохим предсказанием - микроконтроллер обычно имеет крошечный конвейер, а настольный ПК обычно имеет хороший прогноз, поэтому, если вы не ориентируетесь на игровую консоль, версию ветвления вероятно, лучший маршрут, если он уменьшает количество команд.
Как всегда, профилирование - которое может быть таким же простым, как подсчет операций для вашей системы - даст вам реальный ответ.
источник
Предполагая, что значение true равно -1, а значение false равно 0, а '~', '&' и '|' поразрядно нет , и и или операторы соответственно, и мы работаем с арифметикой с двумя дополнениями:
источник
Как насчет этого?
Добавление 360 есть во избежание отрицательных различий, потому что по модулю отрицательного числа возвращается отрицательный результат. Тогда вы получите меньший из двух возможных результатов.
Есть еще неявное решение, но я не знаю, как его избежать. По сути, вы сравниваете два угла, вычисляя разницу по часовой стрелке или против часовой стрелки, и кажется, что вам явно требуется меньшее из этих двух различий. Я не знаю, как получить этот результат, не сравнивая их. То есть без использования «abs», «min», «max» или какого-либо подобного оператора.
источник
Хотя ваш вопрос о них не упоминается, я буду работать с предположением, что ваш вопрос об определении угла связан с желанием узнать минимальный угол между двумя векторами .
Этот расчет прост. Предполагая, A и B ваши векторы:
angle_between = acos( Dot( A.normalized, B.normalized ) )
Если у вас не было векторов и вы хотели использовать этот подход, вы могли бы делать векторы единичной длины с учетом ваших углов
new Vector2( cos( angle ), sin ( angle ) )
.источник
В основном так же, как ответ JasonD, за исключением использования побитовых операций вместо функции абсолютного значения.
Предполагается, что у вас есть 16-битные короткие целые числа!
источник
я думаю
источник
Так как вы заботитесь только об исключении ветвей и «сложных» операций помимо арифметики, я бы порекомендовал это:
min(abs(angle1 - angle2), abs(angle2 - angle1))
Вам все еще нужно
abs
там, несмотря на то, что все углы положительны. В противном случае всегда будет выбран самый отрицательный результат (и всегда будет ровно один отрицательный ответ для положительных, уникальных a и b при сравнении ab и ba).Примечание. Это не сохранит направление между углом1 и углом2. Иногда это нужно для целей ИИ.
Это похоже на ответ CeeJay, но устраняет все модули. Я не знаю, какова стоимость цикла
abs
, но я предполагаю, что это 1 или 2. Трудно сказать,min
сколько стоит стоимость . Может 3? Таким образом, наряду с 1 циклом на вычитание, эта строка должна стоить где-то около 4-9.источник
Получите меньший относительный угол в подписанном виде (+/-), с точки зрения иметь в стороне нужды :
степени
Радиан
обоснование
Я натолкнулся на эту тему после того, как понял это, в поисках решения, которое бы избегало по модулю; до сих пор я не нашел ни одного . Это решение предназначено для сохранения знака перспективы, поскольку @ jacob-phillips задал этот комментарий . Есть более дешевые решения, если вам нужен только самый короткий угол без знака.
источник
Это старый вопрос, но я столкнулся с тем же случаем - нужно было получить угловую разницу со знаком, желательно без веток и тяжелой математики. Вот чем я закончил:
Ограничение состоит в том, что «b» не должно иметь более чем «N» оборотов по сравнению с «a». Если вы не можете гарантировать это и можете разрешить дополнительные операции, используйте следующую строку:
Я получил идею из 13-го комментария этого поста: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- подписать
источник
я думаю, что могу сказать
Конечно, учитывая угол измеряется в градусах.
источник