Chcę porównać kąty i poznać odległość między nimi. W przypadku tej aplikacji pracuję w stopniach, ale działałoby to również w radianach i gradach. Problem z kątami polega na tym, że zależą one od arytmetyki modułowej, tj. 0–360 stopni.
Powiedzmy, że jeden kąt wynosi 15 stopni, a drugi 45. Różnica wynosi 30 stopni, a kąt 45 stopni jest większy niż 15 stopni.
Ale to się psuje, gdy masz, powiedzmy, 345 stopni i 30 stopni. Mimo że porównują się prawidłowo, różnica między nimi wynosi 315 stopni zamiast prawidłowych 45 stopni.
Jak mogę to rozwiązać? Mógłbym napisać kod algorytmiczny:
if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;
Ale wolałbym rozwiązanie, które unika porównań / gałęzi i opiera się całkowicie na arytmetyki.
mathematics
angles
Thomas O
źródło
źródło
Odpowiedzi:
Oto moja uproszczona, bez rozgałęzienia, bez porównania, bez wersji min / max:
Usunięto moduł, ponieważ dane wejściowe są wystarczająco ograniczone (dzięki Martinowi za wskazanie tego).
Dwa abs, trzy odejmowania.
źródło
Co sprawia, że uważasz, że 315 jest niepoprawny? W jednym kierunku wynosi 315 stopni, w drugim - 45. Chcesz wybrać, który jest najmniejszy z 2 możliwych kątów i wydaje się, że z natury wymaga warunkowego. Nie można go rozwiązać za pomocą arytmetyki zawijania (tj. Za pomocą operatora modułu), ponieważ wraz ze stopniowym zwiększaniem jednego kąta kąt między nimi rośnie, aż osiągnie 180, a następnie zaczyna spadać.
Myślę, że albo musisz sprawdzić oba kąty i zdecydować, który kierunek chcesz zmierzyć, albo obliczyć oba kierunki i zdecydować, który wynik chcesz.
źródło
Zawsze istnieje sztuczka polegająca na zrobieniu obu gałęzi i pozostawieniu jednego z wyników porównania:
Nie wiem, jak to zrobić bez porównań , ale zwykle gałąź powoduje, że kod jest wolny i długi, a nie porównanie. Przynajmniej moim zdaniem jest to bardziej czytelne niż odpowiedź Martina (każdy dobry programista C rozpozna go jako ekwiwalent bezgałęziowy i zobaczy, co robi), ale również mniej wydajny.
Ale, jak powiedziałem w moim komentarzu, algorytmy bez rozgałęzień są dobre na procesorach z głębokimi potokami i złymi prognozami - mikrokontroler ma zwykle mały potok, a komputer stacjonarny zwykle ma dobre przewidywanie, więc jeśli nie celujesz w konsolę do gier, wersja rozgałęziona jest prawdopodobnie najlepszą trasą, jeśli zmniejsza liczbę instrukcji.
Jak zawsze profilowanie - które może być tak proste jak liczenie operacji dla twojego systemu - da ci prawdziwą odpowiedź.
źródło
Zakładając, że prawda przyjmuje wartość -1, a fałsz - 0, a „~”, „&” i „|” są bitowe nie , a i czy operatorzy odpowiednio, a my pracujemy z uzupełnionych do dwóch arytmetyka:
źródło
A co z tym?
Dodanie 360 ma na celu uniknięcie różnic ujemnych, ponieważ moduł liczby ujemnej zwraca wynik ujemny. Otrzymasz mniejszy z dwóch możliwych wyników.
Nadal istnieje dorozumiana decyzja, ale nie wiem, jak jej uniknąć. Zasadniczo porównujesz dwa kąty, obliczając różnicę zgodnie z ruchem wskazówek zegara lub przeciwnie do ruchu wskazówek zegara, i wydaje się, że wyraźnie chcesz mniejszej z tych dwóch różnic. Nie wiem, jak uzyskać ten wynik, nie porównując ich. To znaczy bez użycia „abs”, „min”, „max” lub jakiegoś podobnego operatora.
źródło
Chociaż twoje pytanie nie zawierało odniesienia do nich, zamierzam pracować nad założeniem, że twoje pytanie dotyczące obliczania kąta wynika z chęci poznania minimalnego kąta między dwoma wektorami .
To obliczenie jest łatwe. Zakładając, że A i B są wektorami:
angle_between = acos( Dot( A.normalized, B.normalized ) )
Jeśli nie masz wektorów i chciałbyś skorzystać z tego podejścia, możesz zbudować wektory długości jednostkowej, biorąc pod uwagę swoje kąty
new Vector2( cos( angle ), sin ( angle ) )
.źródło
Zasadniczo to samo co odpowiedź JasonD, z wyjątkiem użycia operacji bitowych zamiast funkcji wartości bezwzględnej.
Zakłada się, że masz 16-bitowe krótkie liczby całkowite!
źródło
Myślę
źródło
Ponieważ zależy ci tylko na wyeliminowaniu rozgałęzień i „złożonych” operacji wykraczających poza arytmetykę, polecam to:
min(abs(angle1 - angle2), abs(angle2 - angle1))
Nadal potrzebujesz
abs
tam, mimo że wszystkie kąty są pozytywne. W przeciwnym razie zawsze wybierany będzie najbardziej negatywny wynik (i zawsze będzie dokładnie jedna negatywna odpowiedź na pozytywne, unikalne a i b przy porównywaniu ab i ba).Uwaga: Nie zachowa to kierunku między kątem 1 i kątem 2. Czasami potrzebujesz tego do celów AI.
Jest to podobne do odpowiedzi CeeJay, ale eliminuje wszystkie moduły. Nie wiem, jaki jest koszt cyklu
abs
, ale zgaduję, że to 1 lub 2. Trudno też powiedzieć, jaki jest kosztmin
. Może 3? Tak więc wraz z 1 cyklem na odejmowanie ta linia powinna kosztować około 4 do 9.źródło
Uzyskać mniejszy względny kąt w podpisanym (+/-) postaci, z perspektywy mają wobec niedostatku :
Stopnie
Radians
Racjonalne uzasadnienie
Natknąłem się na ten wątek po tym, jak to rozgryzłem, szukając rozwiązania, które pozwoli uniknąć modulo; jak dotąd nie znalazłem żadnego . To rozwiązanie służy do zachowania znaku perspektywy, ponieważ @ jacob-phillips poprosił o ten komentarz . Istnieją tańsze rozwiązania, jeśli potrzebujesz tylko najkrótszego kąta bez znaku.
źródło
To stare pytanie, ale natknąłem się na tę samą sprawę - musiałem uzyskać różnicę kątową, najlepiej bez gałęzi i ciężkiej matematyki. Właśnie z tym skończyłem:
Ograniczeniem jest to, że „b” nie powinien mieć więcej niż „N” obrotów w porównaniu z „a”. Jeśli nie możesz tego zapewnić i możesz zezwolić na dodatkowe operacje, użyj tego jako pierwszej linii:
Wpadłem na pomysł z 13. komentarza tego posta: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- znak
źródło
chyba mógłbym powiedzieć
oczywiście biorąc pod uwagę, że kąt jest mierzony w stopniach.
źródło