Используя имеющуюся функцию, можно начинать с разумного N, например 5, и продолжать удваивать число, пока не будет достигнута требуемая точность.
def integrate_tol(f, a, b, tol):
N = 5
old_integral = integrate(f, a, b, N)
while True:
N *= 2
new_integral = integrate(f, a, b, N)
if np.abs(old_integral - new_integral) < tol:
return (4*new_integral - old_integral)/3
old_integral = new_integral
Простой тест:
f = lambda x: np.exp(x)
print(integrate_tol(f, -1, 1, 1e-9))
print(np.exp(1)-np.exp(-1)) # exact value for comparison
печать
2.3504023872876028
2.3504023872876028
Нет никакой гарантии, что ошибка действительно меньше tol
(но опять же, scipy.quad
также не гарантирует этого).На практике ошибка будет намного меньше, чем tol, из-за использованного мною трюка, называемого Ричардсон экстраполяция : возвращаемое значение (4*new_integral - old_integral)/3
в целом намного точнее, чем сами новые или старые приближения.(Объяснение: поскольку integrate
использует правило средней точки, каждое удвоение N уменьшает погрешность примерно в 4 раза. Таким образом, взятие комбинации 4*new_integral - old_integral
почти сводит на нет остаточную ошибку в обоих этих результатах.)
(Примечание: в цикле while не рекомендуется начинать с N = 1; вероятно, этого будет недостаточно, и существует более высокий риск остановки слишком рано из-за некоторого числового совпадения, например, функция равна нулю в группемест.)