Я пытаюсь выполнить интеграл от -бесконечности до бесконечности, используя уравнение, содержащее член, возведенный в степень M. При очень высоких (5000+) значениях M это значение этого члена может превышать 10 ^ 100.
У меня есть программа на Python (3.10), которая работает для M = 1000, но ничего особенного.
import numpy as np
from scipy import integrate, special
def integrand(u, M, Z, r):
sqrt_r = np.sqrt(r)
sqrt_term = np.sqrt(2 * (1 - r))
arg1 = (Z + sqrt_r * u) / sqrt_term
arg2 = (-Z + sqrt_r * u) / sqrt_term
erf_term = special.erf(arg1) - special.erf(arg2)
return np.exp(-u**2 / 2) / np.sqrt(2 * np.pi) * erf_term**M
def evaluate_integral(M, Z, r):
result, _ = integrate.quad(integrand, -np.inf, np.inf, args=(M, Z, r))
return 1 / (2**M) * result
# Example usage:
M = 1000
Z = 5
r = 0.6
integral_value = evaluate_integral(M, Z, r)
Я получаю следующую ошибку:
IntegrationWarning: The occurrence of roundoff error is detected, which prevents
the requested tolerance from being achieved. The error may be
underestimated.
result, _ = integrate.quad(integrand, -np.inf, np.inf, args=(M, Z, r))
и результат для Integral_value равен nan
.
Есть ли способ выполнить этот интеграл с помощью Python, который был бы удобен, поскольку позволил бы мне включиться в остальную часть моей программы, или мне придется использовать другой инструмент?
Ничего не меняя, значения функции превышают 1e300. Наверняка что-то не так в формулировке.
Кроме того, интеграл от бесконечности на практике гораздо уже. Функция для |u| > 6,5 фактически равно 0.
Если значения являются числами с плавающей запятой, «float64» имеет максимальный размер и конечную точность.
Рассмотрите возможность аналитического решения, либо на бумаге, либо с помощью Wolfram Alpha или Sympy.
Подсказка в том, что вы ищете не интеграл, а интеграл/2**M. Поместите это /2 внутрь оскорбительного члена интеграла.
Предполагая, что функция определена правильно (что было бы удивительно, учитывая рассматриваемые величины), не интегрируйте ее в линейном пространстве. Вместо этого используйте эквивалент журнала:
def integrand_log(u, M: float, Z: float, r: float):
sqrt_r = np.sqrt(r)
sqrt_term = np.sqrt(2*(1 - r))
arg1 = (sqrt_r*u + Z)/sqrt_term
arg2 = (sqrt_r*u - Z)/sqrt_term
erf_term = special.erf(arg1) - special.erf(arg2)
return (
M*np.log(erf_term)
- 0.5 * (u**2 + np.log(2 * np.pi))
)
Это лог-идентичность
приближается к тому, чтобы помочь вам вернуться к линейному пространственному интегралу, но этого недостаточно. Я уточню в редактировании позже.
Нет, ваша единственная проблема в том, что вы взяли множитель 1/2**M за пределы интеграла. Если вы положите его обратно внутрь, у вас будет
(erf_term/2)**M
и это не произойдет, потому что разница двух функций ошибок не может превышать 2, поэтому новый коэффициент в квадратных скобках меньше 1.
Я... Оглядываясь назад, это была самая очевидная вещь на свете. Спасибо.
Вам придется изменить способ вычислений
integrand
. Работа с логарифмами может помочь.