我正在使用类似的函数(在评估常量之后):
def n(x):
return (1.416e-28)*(x**47)*(np.exp(-4.545*x))
X的范围从0到20.中间的x ^ 47项会导致问题;即使第一个和最后一个项在x增加时变得非常小,代码也会在x ^ 47处溢出。
通过进行以下修改,我已经能够将其付诸实践:
def n(x):
logn=math.log((1.416e-28)*(x**47)*(np.exp(-4.545*x)),x)
return np.pow(r,logn)
这会返回相当易于管理的数字。
问题是我正在尝试传入一个numpy数组,但math.log只接受标量。此外,numpy似乎没有接受任意基数的日志功能。显然,在numpy中执行此操作的唯一方法是执行以下操作:
np.log(42**3)/np.log(42)
但是如果没有FIRST在基数r处获取日志,它就无法处理大数字。所以numpy不起作用。
我应该只是非pythonic并迭代n(x)fcn吗?
答案 0 :(得分:2)
自ln(a*b) = ln(a) + ln(b)
,ln(c**d) = d*ln(c)
和ln(exp(e*f)) = e*f
以来,您可以将您的功能重写为:
def n2(x):
return np.exp(np.log(1.416e-28) + 47*np.log(x) - 4.545*x)
但话虽如此,我发现使用这两种配方在性能方面没有重大差异:
>>> xx = np.linspace(0,20,1000)
>>> q = n(xx[1:])/n2(xx[1:])
>>> np.max(q)
1.0000000000000318
>>> np.min(q)
0.99999999999998357
注意测试中的xx[1:]
。这是因为ln(0)
未定义,如果您将nan
传递给q[0]
,则xx[0]
会导致n2
。
顺便说一句,您在帖子中提到的向量问题是因为您使用的是math.log
而不是np.log
。
答案 1 :(得分:1)
不要试图一次性计算x**47
,而是将其分解。计算它的“一半”,然后在计算“另一半”之前,通过乘以一个小数来减少部分乘积。
# Multiplications are computed left-to-right, so the partial
# product never gets too big.
return 1.416e-28 * x**23 * np.exp(-4.545*x) * x**24