评估1 / tanh(x) - 1 / x表示非常小的x

时间:2017-04-07 13:11:29

标签: python numpy math rounding

我需要计算数量

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

3 个答案:

答案 0 :(得分:4)

对于非常小的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

答案 1 :(得分: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 plottingmpmath适用于您正在使用的matplotlib,因此这可以解决您的问题。

以下是如何将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

答案 2 :(得分:0)

一个可能更简单的解决方案就是改变numpy运行的数据类型:

array.sort(compare)

使用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)])