【问题标题】:Numerical error caused math domain error when using Python math.acos()使用 Python math.acos() 时出现数值错误导致数学域错误
【发布时间】:2016-08-08 21:29:00
【问题描述】:

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

有时这两个向量在归一化时具有相同的方向,它们的点积应该为 1。但是,由于数值错误,它实际上是 0.999999999998,... 或者有时是 1.0000000000002。后者以错误 ValueError: math domain error

杀死 math.acos()

我无意中发现这个question 询问类似的问题,但已关闭。在这里我重新询问,希望对如何避免此类错误有更好的了解。

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

【问题讨论】:

  • 数字偏移量非常小,这是大多数编程语言中浮点数存储方式的结果(IEEE标准,它基于数字的对数)。您应该简单地四舍五入到您认为与可接受误差范围内的角度相对应的某个水平,例如 10^-10。或者写一行if math.abs(result-1)<1e-10: ...

标签: python math


【解决方案1】:

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

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?)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多