2017-04-07 67 views
2

我需要计算量评估1 /的tanh(X) - 1/X为非常小x

1/tanh(x) - 1/x 

x > 0,其中x既可以是非常小和非常大的。

渐近的小x,我们有

1/tanh(x) - 1/x -> x/3 

和大x

1/tanh(x) - 1/x -> 1 

总之,从10^-7小舍入误差计算表达式时,已经导致表达是精确评估为0:

import numpy 
import matplotlib.pyplot as plt 


x = numpy.array([2**k for k in range(-30, 30)]) 
y = 1.0/numpy.tanh(x) - 1.0/x 

plt.loglog(x, y) 
plt.show() 

enter image description here

+0

你可以定义自己的版本功能'1/tanh(x) - 1/x'如果参数太小/太大,会评估渐近表达式 – Stelios

+0

编写您自己的'tanh'? (我没有看到0直到小于10^-8。) –

回答

3

对于非常小的x,可以使用the Taylor expansion of 1/tanh(x) - 1/x around 0

y = x/3.0 - x**3/45.0 + 2.0/945.0 * x**5 

错误是命令O(x**7),所以如果选择10^-5作为断点,则相对误差和绝对误差将远低于机器精度。

import numpy 
import matplotlib.pyplot as plt 


x = numpy.array([2**k for k in range(-50, 30)]) 

y0 = 1.0/numpy.tanh(x) - 1.0/x 
y1 = x/3.0 - x**3/45.0 + 2.0/945.0 * x**5 
y = numpy.where(x > 1.0e-5, y0, y1) 


plt.loglog(x, y) 
plt.show() 

enter image description here

+2

这是正确的答案。为了避免泰勒展开而转向任意精度算术增加了大规模的复杂性,依赖性,存储和计算成本(我认为这是一个非常喜欢mpmath的人!) –

3

使用任意小数精度Python包mpmath。例如:

import mpmath 
from mpmath import mpf 

mpmath.mp.dps = 100 # set decimal precision 

x = mpf('1e-20') 

print (mpf('1')/mpmath.tanh(x)) - (mpf('1')/x) 
>>> 0.000000000000000000003333333333333333333333333333333333333333311111111111111111111946629156220629025294373160489201095913 

它变得非常精确。请致电mpmath plottingmpmathmatplotlib配合良好,因此您应该可以解决您的问题。


下面是如何mpmath融入你上面写的代码示例:

import numpy 
import matplotlib.pyplot as plt 
import mpmath 
from mpmath import mpf 

mpmath.mp.dps = 100 # set decimal precision 

x = numpy.array([mpf('2')**k for k in range(-30, 30)]) 
y = mpf('1.0')/numpy.array([mpmath.tanh(e) for e in x]) - mpf('1.0')/x 

plt.loglog(x, y) 
plt.show() 

enter image description here

0

一个可能更简单的解决方案来克服这种情况正在改变数据类型下这numpy的是操作:

import numpy as np 
import matplotlib.pyplot as plt 

x = np.arange(-30, 30, dtype=np.longdouble) 
x = 2**x 
y = 1.0/np.tanh(x) - 1.0/x 

plt.loglog(x, y) 
plt.show() 

使用longdouble数据类型并提供正确的解决方案,而舍入错误。


我没悦目修改你的榜样,你的情况,你需要修改的唯一的事情是:

x = numpy.array([2**k for k in range(-30, 30)]) 

到:

x = numpy.array([2**k for k in range(-30, 30)], dtype=numpy.longdouble) 
+0

我试过这个,发现它稍后才失效,在10^-10。 –

相关问题