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

使用Python math.acos()时,数值错误导致数学域错误,python,math,Python,Math,我使用math.acos()计算两个向量之间的角度。其思想是计算两个标准化向量的点积,并使用点积的arccos返回两个向量的角度(在0到pi的范围内) 有时,归一化后的两个向量具有相同的方向,其点积应为1。然而,由于数值误差,它实际上是0.99999998。。。或者有时是1.0000000000002。后者通过错误ValueError:math domain error 我无意中发现这是一个类似的问题,但被关闭了。我在这里再次询问,希望能更好地了解如何避免此类错误 在我的例子中,我必须检查两个向

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

有时,归一化后的两个向量具有相同的方向,其点积应为1。然而,由于数值误差,它实际上是0.99999998。。。或者有时是1.0000000000002。后者通过错误
ValueError:math domain error

我无意中发现这是一个类似的问题,但被关闭了。我在这里再次询问,希望能更好地了解如何避免此类错误


在我的例子中,我必须检查两个向量是否具有相同的方向,然后再进行点生成和arccos。这很有帮助,但我仍然想知道是否有更好的方法来做到这一点。

这是所有使用向量和浮点运算的人都会遇到的一个古老的数值问题。一个简单的修复方法是将计算角度的代码包装到具有一些夹紧逻辑的函数中:

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)

数值偏移非常小,这是大多数编程语言(IEEE标准,它基于数字的日志)中如何存储浮点的结果。你应该简单地将其旋转到你认为与你可以接受的误差范围内的角度相对应的某个水平,比如说10^-10。或者如果math.abs(结果1),则写一行
 45.0 deg
180.0 deg
180.0 deg

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