Очень интересная проблема.
Сначала отметим, что подынтегральное выражение
from numpy import exp
def f(x):
return exp(-x)
def g(x):
c = 0.9
return c * x**(c - 1) * exp(-x ** c)
def integrand(x):
return f(x) * log(f(x) / g(x))
имеет особенность в 0, которая является интегрируемой , и интеграл по [0,infty] можно оценить аналитически . После некоторой манипуляции вы обнаружите, что
import numpy
import scipy.special
c = 0.9
# euler_mascheroni constant
gamma = 0.57721566490153286060
val = scipy.special.gamma(c + 1) - 1 - numpy.log(c) + (c - 1) * gamma
print(val)
0.0094047810750603
wolfram-alpha правильно дает многозначное значение. Чтобы воспроизвести это численными методами, хорошей первой попыткой всегда является tanh-sinh квадратура (например, из quadpy , мой проект). Обрежьте домен на какое-то большое значение, где в любом случае функция почти равна 0, тогда:
from numpy import exp, log
import quadpy
def f(x):
return exp(-x)
def g(x):
c = 0.9
return c * x**(c - 1) * exp(-x ** c)
def integrand(x):
return f(x) * log(f(x) / g(x))
val, err = quadpy.tanh_sinh(integrand, 0.0, 100.0, 1.0e-8)
print(val)
0.009404781075063085
Теперь для некоторых других вещей, которые, возможно, удивительно, делают не работают так хорошо.
При взгляде на интеграл типа exp(-x) * f(x)
первое, что должно прийти в голову, это квадратура Гаусса-Лагерра . Например, с quadpy (один из моих проектов):
import numpy
import quadpy
c = 0.9
def f(x):
return numpy.exp(-x)
def g(x):
return c * x ** (c - 1) * numpy.exp(-x ** c)
scheme = quadpy.e1r.gauss_laguerre(100)
val = scheme.integrate(lambda x: numpy.log(f(x) / g(x)))
print(val[0])
Это дает
0.010039543105755215
, что является удивительно плохим приближением для фактического значения, несмотря на то, чточто мы использовали 100 точек интеграции. Это связано с тем, что подынтегральное выражение не может быть очень хорошо аппроксимировано полиномами, особенно слагаемыми log(x)
и x ** c
:
import numpy
from numpy import exp, log, ones
from scipy.special import gamma
import quadpy
c = 0.9
def integrand(x):
return exp(-x) * (-x - log(c) - (c - 1) * log(x) - (-x ** c))
scheme = quadpy.e1r.gauss_laguerre(200)
val = scheme.integrate(lambda x: -x - log(c) - (c - 1) * log(x) - (-x ** c))[0]
vals = numpy.array([
- scheme.integrate(lambda x: x)[0],
-log(c) * scheme.integrate(lambda x: ones(x.shape))[0],
-(c - 1) * scheme.integrate(lambda x: log(x))[0],
scheme.integrate(lambda x: x ** c)[0]
])
euler_mascheroni = 0.57721566490153286060
exact = numpy.array([
-1.0,
-log(c),
euler_mascheroni * (c-1),
gamma(c + 1)
])
print("approximation, exact, diff:")
print(numpy.column_stack([vals, exact, abs(vals - exact)]))
print()
print("sum:")
print(sum(vals))
approximation, exact, diff:
[[-1.00000000e+00 -1.00000000e+00 8.88178420e-16]
[ 1.05360516e-01 1.05360516e-01 6.93889390e-17]
[-5.70908293e-02 -5.77215665e-02 6.30737142e-04]
[ 9.61769857e-01 9.61765832e-01 4.02488825e-06]]
sum:
0.010039543105755278