Python:计算锐角时精度失败

Dev*_*per 2 python precision geometry numpy

我们使用以下代码计算两条线之间的锐角。

def AcuteAngle2(line1,line2):
   ''':: line(x1,y1,x2,y2)'''
   u = (line1[2]-line1[0], line1[3]-line1[1])
   v = (line2[2]-line2[0], line2[3]-line2[1])
   return arccos(abs(dot(u,v)/(norm(u)*norm(v))))
Run Code Online (Sandbox Code Playgroud)

它按预期工作。例如:

>>> AcuteAngle2([0,0,1,0],[0,0,0,1])
1.5707963267948966         #in rad = 90 degree
Run Code Online (Sandbox Code Playgroud)

但是我们最近发现它在某些特殊情况下会失败!

>>> AcuteAngle2([0,0,1,0],[0,0,1,0])
0.0
Run Code Online (Sandbox Code Playgroud)

这是正确的,但是:

>>> AcuteAngle2([0,0,1,1],[0,0,1,1])
2.1073424255447017e-08                #failed!
Run Code Online (Sandbox Code Playgroud)

这是不正确的!它应该是 0.0。
任何想法和解决方案?

更新 1:按照以下答案中的建议
使用Decimal包可能对某些情况有所帮助。然而,我们的问题仍未解决,因为 (1) 有很多代码需要大量时间来调整每个部分以使用Decimal. 此外,(2)性能显着下降。此外,在处理numpy数组时需要 (3) 大量更改。因此它对我们的情况没有用。我们正在考虑某种装饰器等,而不改变事物并保持numpy性能。顺便说一句,有些人可能会建议使用多精度包,例如 gmpy 等,请注意,它们需要在代码中进行大量调整,这对我们的情况没有帮助。

max*_*000 6

如果您关心准确性,则使用arccos锐角是一个坏主意。问题是,对于接近 0 的小角度变化,该角度的余弦几乎不会改变。因为arccos情况相反 - 对于余弦角的非常小的变化,变化更大。

在 2D 和 3D 中,更好的方法是使用 atan2(crossproduct.length,scalarproduct)

在 2D 中,这变为atan2( dx1*dy2-dx2*dy1 , dx1*dy1+dx2*dy2 ). 请注意,您不需要对向量进行归一化,因此有两个改进:

  • 无误差放大 arccos
  • 没有平方根的额外误差

  • 我想到的唯一通用解决方案(高精度数据类型除外)是“评估计算中的舍入误差并选择误差较小的方法”。我怀疑有一种简单而通用的方法:( (2认同)