Stabilny numerycznie sposób obliczania kątów między wektorami

14

Podczas stosowania klasycznej formuły kąta między dwoma wektorami:

α=arccosv1v2v1v2

stwierdzono, że dla bardzo małych / ostrych kątów występuje utrata precyzji, a wynik nie jest dokładny. Jak wyjaśniono w tej odpowiedzi Przepełnienie stosu , jednym rozwiązaniem jest użycie arcus tangens zamiast:

α=arctan2(v1×v2,v1v2)

I to rzeczywiście daje lepsze wyniki. Zastanawiam się jednak, czy dałoby to złe wyniki dla kątów bardzo zbliżonych do π/2 . Czy to prawda? Jeśli tak, to czy istnieje wzór umożliwiający dokładne obliczenie kątów bez sprawdzania tolerancji wewnątrz ifgałęzi?

astrojuanlu
źródło
1
Będzie to zależeć od implementacji funkcji odwrotnej stycznej do dwóch parametrów. Wolne, stabilne wersje warunkowo przełączają się między pracą z x / y i y / x, aby zachować precyzję, podczas gdy te szybkie trzymają rzeczy we właściwej ćwiartce, a zatem nie są bardziej precyzyjne niż wersja z jednym parametrem.
origimbo
Powinieneś zdefiniować „utratę precyzji”: załóżmy, że poprawną odpowiedzią jest α a zamiast tego otrzymujesz α+Δ . Czy potrzebujesz Δα czy Δπ jest wystarczający?
Stefano M
W tym przypadku poprawną odpowiedzią było a dostałem , oba . α 10 81αα1081
astrojuanlu

Odpowiedzi:

18

( Testowałem już to podejście i pamiętam, że zadziałało poprawnie, ale nie przetestowałem go specjalnie na to pytanie ).

O ile wiem, zarówno i .v 1v 2v1×v2v1v2

Zacznij od przeformułowania problemu jako znalezienia kąta trójkąta o długości boków,oraz(wszystkie są dokładnie obliczone w arytmetyce zmiennoprzecinkowej). Jest dobrze znany wariant Wzór Herona powodu Kahan ( miscalculating Obszaru oraz kąty igłą jak Triangle ), co pozwala na obliczenie powierzchni i kąt (między i ) trójkąta określonego przez jego długości bocznych, i zrób to stabilnie numerycznie. Ponieważ redukcja do tego podproblemu jest również dokładna, takie podejście powinno działać w przypadku dowolnych danych wejściowych.b = | v 2 | c = | v 1 - v 2 | a ba=|v1|b=|v2|c=|v1v2|ab

Cytując z tego artykułu (patrz str. 3), zakładając, że , Wszystkie nawiasy tutaj są umieszczone ostrożnie i mają one znaczenie; jeśli okaże się, że bierzesz pierwiastek kwadratowy z liczby ujemnej, wejściowe długości boków nie są długościami boków trójkąta.μ = { c - ( a - b ) , jeśli  b c 0 , b - ( a - c ) , jeśli  c > b 0 , nieprawidłowy trójkąt , w przeciwnym razie a n g l e = 2 arctan ( ab

μ={c(ab),if bc0,b(ac),if c>b0,invalid triangle,otherwise
angle=2arctan(((ab)+c)μ(a+(b+c))((ac)+b))

W pracy Kahana wyjaśniono, jak to działa, w tym przykłady wartości, dla których inne formuły zawodzą. Twoja pierwsza formuła dla to na stronie 4.C αC

Głównym powodem, dla którego sugeruję formułę Herona Kahana, jest to, że tworzy ona bardzo przyjemną prymitywną - wiele potencjalnie trudnych pytań dotyczących geometrii płaskiej można zredukować do znalezienia pola / kąta dowolnego trójkąta, więc jeśli możesz zredukować swój problem do tego, istnieje niezła, stabilna formuła i nie ma potrzeby wymyślać czegoś na własną rękę.

Edytuj Po komentarzu Stefano, stworzyłem wykres błędu względnego dla , ( kod ). Dwie linie to błędy względne dla i , przebiegające wzdłuż osi poziomej. Wygląda na to, że działa. v 2 = ( cos θ , sinv1=(1,0)θ = ϵ θ = π / 2 - ϵ ϵv2=(cosθ,sinθ)θ=ϵθ=π/2ϵϵwprowadź opis zdjęcia tutaj

Cyryl
źródło
Dzięki za link i odpowiedź! Niestety druga formuła, którą napisałem, nie pojawia się w artykule. Z drugiej strony ta metoda może być nieco złożona, ponieważ wymaga projekcji w 2D.
astrojuanlu
2
@astrojuanlu Nie ma tutaj rzutowania na 2d: cokolwiek to są dwa wektory 3d, definiują one pojedynczy (płaski) trójkąt między nimi - wystarczy znać jego długości boków.
Kirill,
Masz rację, mój komentarz nie ma sensu. Myślałem o współrzędnych zamiast długości. Dzięki jeszcze raz!
astrojuanlu,
2
@astrojuanlu Jeszcze jedna rzecz, na którą chcę zwrócić uwagę: wydaje się, że istnieje formalny dowód na to, że formuła pola jest dokładna w artykule Jak obliczyć powierzchnię trójkąta: Formalna wizyta , Sylvie Boldo , przy użyciu Flocq.
Kirill,
Doskonała odpowiedź, ale zaprzeczam, że zawsze można dokładnie obliczyć w arytmetyki zmiennoprzecinkowej. W rzeczywistości, jeśli wówczas dochodzi do katastrofalnych odwołań przy obliczaniu składników . cc<ϵmin(a,b)(v1v2)
Stefano M
7

Skuteczną odpowiedź na to pytanie nie jest zaskakujące w innej notatce Velvela Kahana :

α=2arctan(v1v1+v2v2,v1v1v2v2)

gdzie używam jako kąta utworzonego przez z osią poziomą. (W niektórych językach może być konieczne odwrócenie kolejności argumentów).arctan(x,y)(x,y)

(Dałem Mathematica demonstrację wzoru Kahan jest tutaj ).

JM
źródło
Masz na myśli ? arctan2
astrojuanlu
1
Jestem przyzwyczajony do przedstawiania dwuargumentowego arcus tangens jako , tak. W języku takim jak FORTRAN byłby to odpowiednik . arctan(x,y)ATAN2(Y, X)
JM