( Я вже перевіряв цей підхід і пам'ятаю, що він працював правильно, але я не перевіряв його спеціально для цього питання. )
Наскільки я можу сказати, обидва і може постраждати від катастрофічного скасування, якщо вони майже паралельні / перпендикулярні - atan2 не може дати точну точність, якщо будь-який вхід вимкнено.v 1 ⋅ v 2∥v1×v2∥v1⋅v2
Почніть з переформулювання задачі як знаходження кута трикутника зі сторонами довжини,і(всі вони точно обчислені в арифметиці з плаваючою точкою). Існує добре відомий варіант формули Герона завдяки Кахану ( Площа прорахунку та кути голкоподібного трикутника ), що дозволяє обчислити площу та кут (між і ) трикутника, визначеними його сторонами, і робити це стабільно чисельно. Оскільки зменшення цієї підпроблеми також точне, такий підхід повинен працювати для довільних даних.b = | v 2 | c = | v 1 - v 2 | a ba=|v1|b=|v2|c=|v1−v2|ab
Цитуючи цей документ (див. П. 3), припускаючи, що ,
Усі круглі дужки тут розміщуються обережно, і вони мають значення; якщо ви знайдете квадратний корінь від’ємного числа, довжина вхідної сторони не є бічними довжинами трикутника.μ = { c - ( a - b ) , якщо b ≥ c ≥ 0 , b - ( a - c ) , якщо c > b ≥ 0 , недійсний трикутник , інакше a n g l e = 2 арктану ( √a≥b
μ=⎧⎩⎨c−(a−b),b−(a−c),invalid triangle,if b≥c≥0,if c>b≥0,otherwise
angle=2arctan(((a−b)+c)μ(a+(b+c))((a−c)+b)−−−−−−−−−−−−−−−−−−−−√)
У статті Кахана є пояснення того, як це працює, включаючи приклади значень, для яких інші формули виходять з ладу. Ваша перша формула для є на сторінці 4.C ″αC′′
Основна причина, за якою я пропоную формулу Герона Кахана, полягає в тому, що це робить дуже приємним примітивом - багато потенційно складних запитань з площинної геометрії можна звести до пошуку площі / кута довільного трикутника, тож якщо ви можете звести свою проблему до цього, є приємна стабільна формула для цього, і немає необхідності придумувати щось самостійно.
Змінити Після коментаря Стефано, я зробив графік відносної помилки для , ( код ). Два рядки є відносними помилками для та , йдуть уздовж горизонтальної осі. Здається, що це працює.
v 2 = ( cos θ , sin θ ) θ = ϵ θ = π / 2 - ϵ ϵv1=(1,0)v2=(cosθ,sinθ)θ=ϵθ=π/2−ϵϵ