使用Python math.acos()时数值错误导致数学域错误

时间:2016-04-17 02:23:16

标签: python math

我使用math.acos()来计算两个向量之间的角度。想法是计算两个归一化向量的点积,并使用点积的arccos返回两个向量的角度(在0到pi的范围内)。

偶然地,两个向量在归一化时具有相同的方向,并且它们的点积应为1.但是,由于数值误差,它实际上是0.999999999998,...或者有时是1.0000000000002。后者使用错误<img runat="server" src="" data-id="12345" />

杀死math.acos()

我偶然发现这个question询问了类似的问题,但是已经关闭了。在这里,我重新询问,希望能更好地了解如何避免此类错误。

就我而言,在进行点生成和arccos之前,我必须检查两个向量是否具有相同的方向。这有帮助,但我仍然想知道是否有更好的方法来做到这一点。

1 个答案:

答案 0 :(得分:3)

这是使用向量和浮点运算的所有人遇到的旧数值问题。一个简单的解决方法是使用一些钳位逻辑来包装计算角度的代码:

import numpy as np
import math

def angle_between(vhat1, vhat2, tol = 5e-6):
    cosang = np.dot(vhat1, vhat2)
    if math.fabs(cosang) > 1.0:
        if math.fabs(cosang) - 1.0 < tol:
            cosang = math.modf(cosang)[1]
        else:
            raise ValueError('Invalid arguments (vectors not normalized?)')
    return math.acos(cosang)



w = np.array([ 1., 0., 0.])
z = np.array([-1., 0., 0.])
v = np.array([ math.sqrt(2.)/2., math.sqrt(2.)/2., 0.])
z1 = np.array([-1.0000001, 0., 0.])
w1 = np.array([9., 3., -5.])

print "{0:>5} deg".format(angle_between(v, w) * 180.0 / math.pi)
print "{0:>5} deg".format(angle_between(w, z) * 180.0 / math.pi)
print "{0:>5} deg".format(angle_between(w, z1) * 180.0 / math.pi)
# this last one will raise ValueError
print "{0:>5} deg".format(angle_between(w1, z1) * 180.0 / math.pi)

输出:

 45.0 deg
180.0 deg
180.0 deg

...
ValueError: Invalid arguments (vectors not normalized?)