Рассмотрите треугольник с известными двумя сторонами и углом между ними; сравните использование формулы косинусов и методов координатной геометрии для нахождения третьей стороны и углов, укажите тонкости, когда численная устойчивость или округление существенны
Коротко: обе техники дают одинаковые аналитические формулы, но отличаются устойчивостью при машинной арифметике. Ниже — практические формулы и советы по численной устойчивости. Исходные обозначения: известны два прилежащих к углу длины aaa и bbb и угол между ними γ\gammaγ. Противоположная сторона обозначена ccc. 1) Формула косинусов (прямо) - Третья сторона: c2=a2+b2−2abcosγ,c=a2+b2−2abcosγ.
c^2=a^2+b^2-2ab\cos\gamma,\qquad c=\sqrt{a^2+b^2-2ab\cos\gamma}. c2=a2+b2−2abcosγ,c=a2+b2−2abcosγ.
- Остальные углы (через косинус): α=arccosb2+c2−a22bc,β=arccosa2+c2−b22ac.
\alpha=\arccos\frac{b^2+c^2-a^2}{2bc},\qquad \beta=\arccos\frac{a^2+c^2-b^2}{2ac}. α=arccos2bcb2+c2−a2,β=arccos2aca2+c2−b2. Проблемы при использовании напрямую: - Катастрофическое вычитание, когда a2+b2a^2+b^2a2+b2 и 2abcosγ2ab\cos\gamma2abcosγ близки (например, γ\gammaγ мало и a≈ba\approx ba≈b), — теряются значащие разряды в c2c^2c2. - Арифметика с квадратами может переполнять при очень больших a,ba,ba,b или терять точность при очень маленьких. - arccos(x)\arccos(x)arccos(x) нечувствителен, если xxx близко к ±1\pm1±1: небольшая ошибка в xxx даёт большую ошибку в угле. 2) Координатный метод (рекомендации для численной устойчивости) - Разместите вершину угла γ\gammaγ в начале координат, вектор вдоль оси xxx длиной aaa: u=(a,0)u=(a,0)u=(a,0), второй вектор длиной bbb под углом γ\gammaγ: v=(bcosγ,bsinγ)v=(b\cos\gamma,b\sin\gamma)v=(bcosγ,bsinγ). - Тогда c=∥u−v∥=(a−bcosγ)2+(bsinγ)2.
c=\|u-v\|=\sqrt{(a-b\cos\gamma)^2+(b\sin\gamma)^2}. c=∥u−v∥=(a−bcosγ)2+(bsinγ)2.
Для вычисления лучше использовать функцию hypot: c=hypot(a−bcosγ, bsinγ),
c=\operatorname{hypot}\bigl(a-b\cos\gamma,\; b\sin\gamma\bigr), c=hypot(a−bcosγ,bsinγ),
— hypot реализует масштабирование и уменьшает потерю точности и переполнение/зануление. - Для углов: вычислите одновременно косинус и синус угла и примените atan2: cosα=b2+c2−a22bc,sinα=asinγc,
\cos\alpha=\frac{b^2+c^2-a^2}{2bc},\qquad \sin\alpha=\frac{a\sin\gamma}{c}, cosα=2bcb2+c2−a2,sinα=casinγ,
затем α=atan2(sinα,cosα).
\alpha=\operatorname{atan2}\bigl(\sin\alpha,\cos\alpha\bigr). α=atan2(sinα,cosα).
Аналогично для β\betaβ (или использовав β=π−α−γ\beta=\pi-\alpha-\gammaβ=π−α−γ). Вычисление через atan2(cross,dot)\operatorname{atan2}(\text{cross},\text{dot})atan2(cross,dot) (dot — скалярное, cross — модуль вектора произведения) даёт устойчивое значение в (0,π)(0,\pi)(0,π). Почему координатный/векторный подход устойчивее: - Выражение в виде расстояния между векторами и использование hypot минимизирует эффект вычитания больших почти равных величин. - Использование atan2(sin,cos)\operatorname{atan2}(\sin,\cos)atan2(sin,cos) вместо arccos\arccosarccos уменьшает чувствительность при значениях косинуса, близких к ±1\pm1±1. - Можно явно контролировать масштабирование (деление на max(a,b)(a,b)(a,b)), чтобы избежать переполнения при больших длинах: c=max(a,b)(min(a,b)max(a,b))2−2min(a,b)max(a,b)cosγ+1.
c=\max(a,b)\sqrt{\Bigl(\frac{\min(a,b)}{\max(a,b)}\Bigr)^2-2\frac{\min(a,b)}{\max(a,b)}\cos\gamma+1}. c=max(a,b)(max(a,b)min(a,b))2−2max(a,b)min(a,b)cosγ+1. Практические рекомендации (когда важна точность): - Если ожидается, что ccc может быть очень маленьким (почти вырожденный треугольник), используйте формулу через hypot\operatorname{hypot}hypot на разности координат; не вычисляйте сначала a2+b2−2abcosγa^2+b^2-2ab\cos\gammaa2+b2−2abcosγ напрямую. - Для вычисления углов избегайте arccos(x)\arccos(x)arccos(x) при xxx близком к ±1\pm1±1. Лучше получить sin\sinsin и cos\coscos и взять atan2(sin,cos)\operatorname{atan2}(\sin,\cos)atan2(sin,cos). - Всегда защищайте аргументы arccos\arccosarccos и arcsin\arcsinarcsin от небольших выходов за диапазон из-за округления: явно зафиксируйте в [−1,1][-1,1][−1,1]. - При больших/малых масштабах данных используйте масштабирование (деление на max(a,b)(a,b)(a,b)) или арифметику с плавающей запятой повышенной точности (long double или многоточечная библиотека). - Библиотечные функции: используйте hypot, atan2, аккуратно clamp для acos/asin. Краткий итог: - Аналитически формула косинусов проста, но при прямом вычислении может быть неустойчива (вычитание больших близких величин, arccos проблемы). - Координатно/векторно с использованием hypot\operatorname{hypot}hypot и atan2\operatorname{atan2}atan2 обычно более устойчивы и практичны при реализации в вычислительной среде.
Исходные обозначения: известны два прилежащих к углу длины aaa и bbb и угол между ними γ\gammaγ. Противоположная сторона обозначена ccc.
1) Формула косинусов (прямо)
- Третья сторона:
c2=a2+b2−2abcosγ,c=a2+b2−2abcosγ. c^2=a^2+b^2-2ab\cos\gamma,\qquad c=\sqrt{a^2+b^2-2ab\cos\gamma}.
c2=a2+b2−2abcosγ,c=a2+b2−2abcosγ . - Остальные углы (через косинус):
α=arccosb2+c2−a22bc,β=arccosa2+c2−b22ac. \alpha=\arccos\frac{b^2+c^2-a^2}{2bc},\qquad
\beta=\arccos\frac{a^2+c^2-b^2}{2ac}.
α=arccos2bcb2+c2−a2 ,β=arccos2aca2+c2−b2 .
Проблемы при использовании напрямую:
- Катастрофическое вычитание, когда a2+b2a^2+b^2a2+b2 и 2abcosγ2ab\cos\gamma2abcosγ близки (например, γ\gammaγ мало и a≈ba\approx ba≈b), — теряются значащие разряды в c2c^2c2.
- Арифметика с квадратами может переполнять при очень больших a,ba,ba,b или терять точность при очень маленьких.
- arccos(x)\arccos(x)arccos(x) нечувствителен, если xxx близко к ±1\pm1±1: небольшая ошибка в xxx даёт большую ошибку в угле.
2) Координатный метод (рекомендации для численной устойчивости)
- Разместите вершину угла γ\gammaγ в начале координат, вектор вдоль оси xxx длиной aaa: u=(a,0)u=(a,0)u=(a,0), второй вектор длиной bbb под углом γ\gammaγ: v=(bcosγ,bsinγ)v=(b\cos\gamma,b\sin\gamma)v=(bcosγ,bsinγ).
- Тогда
c=∥u−v∥=(a−bcosγ)2+(bsinγ)2. c=\|u-v\|=\sqrt{(a-b\cos\gamma)^2+(b\sin\gamma)^2}.
c=∥u−v∥=(a−bcosγ)2+(bsinγ)2 . Для вычисления лучше использовать функцию hypot:
c=hypot(a−bcosγ, bsinγ), c=\operatorname{hypot}\bigl(a-b\cos\gamma,\; b\sin\gamma\bigr),
c=hypot(a−bcosγ,bsinγ), — hypot реализует масштабирование и уменьшает потерю точности и переполнение/зануление.
- Для углов: вычислите одновременно косинус и синус угла и примените atan2:
cosα=b2+c2−a22bc,sinα=asinγc, \cos\alpha=\frac{b^2+c^2-a^2}{2bc},\qquad
\sin\alpha=\frac{a\sin\gamma}{c},
cosα=2bcb2+c2−a2 ,sinα=casinγ , затем
α=atan2(sinα,cosα). \alpha=\operatorname{atan2}\bigl(\sin\alpha,\cos\alpha\bigr).
α=atan2(sinα,cosα). Аналогично для β\betaβ (или использовав β=π−α−γ\beta=\pi-\alpha-\gammaβ=π−α−γ). Вычисление через atan2(cross,dot)\operatorname{atan2}(\text{cross},\text{dot})atan2(cross,dot) (dot — скалярное, cross — модуль вектора произведения) даёт устойчивое значение в (0,π)(0,\pi)(0,π).
Почему координатный/векторный подход устойчивее:
- Выражение в виде расстояния между векторами и использование hypot минимизирует эффект вычитания больших почти равных величин.
- Использование atan2(sin,cos)\operatorname{atan2}(\sin,\cos)atan2(sin,cos) вместо arccos\arccosarccos уменьшает чувствительность при значениях косинуса, близких к ±1\pm1±1.
- Можно явно контролировать масштабирование (деление на max(a,b)(a,b)(a,b)), чтобы избежать переполнения при больших длинах:
c=max(a,b)(min(a,b)max(a,b))2−2min(a,b)max(a,b)cosγ+1. c=\max(a,b)\sqrt{\Bigl(\frac{\min(a,b)}{\max(a,b)}\Bigr)^2-2\frac{\min(a,b)}{\max(a,b)}\cos\gamma+1}.
c=max(a,b)(max(a,b)min(a,b) )2−2max(a,b)min(a,b) cosγ+1 .
Практические рекомендации (когда важна точность):
- Если ожидается, что ccc может быть очень маленьким (почти вырожденный треугольник), используйте формулу через hypot\operatorname{hypot}hypot на разности координат; не вычисляйте сначала a2+b2−2abcosγa^2+b^2-2ab\cos\gammaa2+b2−2abcosγ напрямую.
- Для вычисления углов избегайте arccos(x)\arccos(x)arccos(x) при xxx близком к ±1\pm1±1. Лучше получить sin\sinsin и cos\coscos и взять atan2(sin,cos)\operatorname{atan2}(\sin,\cos)atan2(sin,cos).
- Всегда защищайте аргументы arccos\arccosarccos и arcsin\arcsinarcsin от небольших выходов за диапазон из-за округления: явно зафиксируйте в [−1,1][-1,1][−1,1].
- При больших/малых масштабах данных используйте масштабирование (деление на max(a,b)(a,b)(a,b)) или арифметику с плавающей запятой повышенной точности (long double или многоточечная библиотека).
- Библиотечные функции: используйте hypot, atan2, аккуратно clamp для acos/asin.
Краткий итог:
- Аналитически формула косинусов проста, но при прямом вычислении может быть неустойчива (вычитание больших близких величин, arccos проблемы).
- Координатно/векторно с использованием hypot\operatorname{hypot}hypot и atan2\operatorname{atan2}atan2 обычно более устойчивы и практичны при реализации в вычислительной среде.