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

Posted

技术标签:

【中文标题】ValueError:来自 math.acos 的数学域错误和来自 numpy.arccos 的 NaN【英文标题】:ValueError: math domain error from math.acos and NaN from numpy.arccos 【发布时间】:2018-06-22 10:41:31 【问题描述】:

我看到有人问过类似的问题,但我还没有找到可以帮助我的答案。我正在尝试使用点积方法找到两个向量之间的角度。

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 设置为相距 180 度(如上)的向量时,我得到 ValueError:数学域错误。我从 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

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

【问题讨论】:

【参考方案1】:

问题在于浮点。 np.dot(u,v) / (mag(u) * mag(v)) 的结果可能类似于 -1.000000000000002,这不是 acos 的有效数字(因为 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)

【讨论】:

【参考方案2】:

移动平方根至少可以修复您提供的输入,因为此后结果在所有中间步骤中仍然是整数

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

【讨论】:

以上是关于ValueError:来自 math.acos 的数学域错误和来自 numpy.arccos 的 NaN的主要内容,如果未能解决你的问题,请参考以下文章

java中math的用法

c#math

Math.floor是啥?

ValueError:spacy.strings.StringStore 大小已更改,可能表示二进制不兼容。预期来自 C 标头的 80,来自 PyObject 的 64

来自 sklearn 的 OneHotEncoder 在传递类别时会给出 ValueError

ValueError: Tensor 必须来自与 Tensorflow 中具有双向 RNN 的 Tensor 相同的图