向量之间的角度数值稳定计算方法


14

当对两个向量之间的角度应用经典公式时:

α=arccosv1v2v1v2

人们发现,对于非常小的/锐角,会损失精度,结果也不准确。正如在解释这个堆栈溢出的答案,一个解决方案是使用反正切来代替:

α=arctan2(v1×v2,v1v2)

这确实提供了更好的结果。但是,我想知道这是否会给非常接近\ pi / 2的角度带来不好的结果π/2。是这样吗 如果是这样,是否有任何公式可以精确计算角度而无需检查if分支内的公差?


1
这将取决于两个参数反正切函数的实现。缓慢,稳定的版本有条件地在使用x / y和y / x进行切换以保持精度,而快速的版本只是将事物粘在正确的象限中,因此没有比一个参数版本更精确的了。
origimbo '17

您应该定义“精度损失”:假设正确的答案是,而是得到。您是否需要或足够?αα+ΔΔαΔπ
Stefano M,

在这种情况下,正确的答案是,我得到了,都为。α ·&10 8 « 1αα1081
astrojuanlu

Answers:


18

我之前已经测试过这种方法,我记得它可以正常工作,但是我没有专门针对这个问题进行测试。

据我所知,这两个 和如果几乎是平行/垂直的,则可能会遭受灾难性的取消-如果关闭任何一个输入,atan2都无法为您提供良好的准确性。v 1v 2v1×v2v1v2

首先重新确定问题,即找到边长为的三角形的角度 ,和(所有这些均以浮点算术精确计算)。由于Kahan(错误计算针状三角形的面积和角度),Heron公式有一个著名的变体,它可以让您计算由边长指定的三角形的面积和角度(在和之间),并在数值上稳定。因为对该子问题的减少也很准确,所以该方法应适用于任意输入。b = | v 2 | c = | v 1v 2 | ba=|v1|b=|v2|c=|v1v2|ab

引用该论文(请参阅第3页),假设, 这里所有的括号都经过精心放置,很重要;如果您发现自己采用负数的平方根,则输入边的长度不是三角形的边的长度。μ = { Ç - - b ab一个Ñë=2反正切

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

Kahan的论文对此作了解释,其中包括其他公式无法使用的值的示例。您的第一个公式是 4页上。αC

我建议使用Kahan的Heron公式的主要原因是因为它是一个非常漂亮的基元-可以将很多潜在棘手的平面几何问题简化为找到任意三角形的面积/角度,因此,如果您可以将问题简化为一个不错的稳定公式,无需您自己提出任何建议。

编辑根据Stefano的评论,我绘制了,(代码)的相对误差图。这两行是和的相对误差,沿水平轴移动。似乎可行。 v 2 = COS θ θ θ = ε θ = π / 2 - ε εv1=(1,0)v2=(cosθ,sinθ)θ=ϵθ=π/2ϵϵ在此处输入图片说明


感谢您的链接和答案!不幸的是,我写的第二个公式没有出现在文章中。另一方面,此方法可能会有点复杂,因为它需要2D投影。
astrojuanlu

2
@astrojuanlu这里没有2d的投影:无论两个3d向量是什么,它们在它们之间都定义了一个(平面)三角形-您只需要知道其边长即可。
基里尔

您说得对,我的评论没有道理。我在考虑坐标而不是长度。再次感谢!
astrojuanlu

2
@astrojuanlu我还要注意一件事:似乎有一个正式的证明,该区域公式在如何计算三角形的面积中是正确的使用Flocq 的形式重访 Sylvie Boldo。
基里尔

很好的答案,但我认为您始终可以在浮点算法中准确计算 。实际上,如果则在计算的分量时会发生灾难性的取消。ç < ε &CenterDot;&分钟cc<ϵmin(a,b)(v1v2)
Stefano M,

7

Velvel Kahan另一个说明中,对此问题的有效答案并不奇怪:

α=2arctan(v1v1+v2v2,v1v1v2v2)

我用作为与水平轴的夹角。(您可能必须在某些语言中翻转参数的顺序。)xarctan(x,y)(x,y)

(我在此处对Kahan的公式进行了Mathematica演示。)


您的意思是吗?arctan2
astrojuanlu

1
我习惯于将两个参数的反正切描述为,是的。在FORTRAN之类的语言中,等价于。arctan(x,y)ATAN2(Y, X)
JM
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.