ValueError:来自math.acos的数学域错误和来自numpy.arccos的NaN

时间:2018-01-12 23:05:35

标签: python numpy math valueerror

我见过类似的问题,但我还没有找到答案来帮助我。我试图使用点积法找到两个向量之间的角度。

import math as m
import numpy as np

def mag(x):
    return np.sqrt(np.sum(i**2 for i in x))

u = np.array([1,1,1])
v = np.array([-1,-1,-1])

theta = m.degrees(np.arccos(np.dot(u,v) / (mag(u) * mag(v))))

它适用于大多数情况,但是当我将u和v设置为相隔180deg(如上所述)的向量时,我得到ValueError:math domain error。我从m.acos切换到np.arccos(如上所述)返回NaN,但它基本上是同样的问题。我知道这是由浮点舍入错误引起的,产生的值略低于-1,这超出了acos / arrcos的范围,但我无法弄清楚该做些什么。

print('theta = ', theta)
print('magnitude product = ', mag(u) * mag(v))
print('dot product = ', np.dot(u,v))
print('dot prod / mag prod = ', np.dot(u,v) / (mag(u) * mag(v)))
print('dot prod / mag prod < -1.0 = ', (np.dot(u,v) / (mag(u) * mag(v))) < -1.0)

theta =  nan
magnitude product =  3.0
dot product =  -3
dot prod / mag prod =  -1.0
dot prod / mag prod < -1.0 =  True

我尝试过使用十进制模块,但到目前为止只是让事情变得更糟。我无法想象这是一个不寻常的问题所以我猜测某个地方有一个很好的,干净的解决方案,但我找不到它。

2 个答案:

答案 0 :(得分:4)

问题在于浮点数。 np.dot(u,v) / (mag(u) * mag(v))的结果可能类似-1.000000000000002,这不是acos的有效数字(coz cos必须在范围[-1,1]内)

我建议你使用np.clip

def mag(x):
    return np.sqrt(np.sum(i ** 2 for i in x))

u = np.array([1, 1, 1])
v = np.array([-1, -1, -1])

cos = np.dot(u, v) / (mag(u) * mag(v))
cos = np.clip(cos, -1, 1)
rad = np.arccos(cos)  # or m.acos(cos)
print(rad)
theta = m.degrees(rad)
print(theta)

答案 1 :(得分:1)

移动平方根至少可以修复您提供的输入,因为结果在所有中间步骤都保持整数

import numpy as np

def mag2(x):
    return np.dot(x, x)  # or np.sum(x ** 2)

u = np.array([1,1,1])
v = np.array([-1,-1,-1])

theta = np.degrees(np.arccos(np.dot(u,v) / np.sqrt(mag2(u) * mag2(v))))