I am computing integrals of the form \int_s^t e^{-a -bx-cx^2}dx. The solution is available in closed form in a number of cases such as (1) c>0
and (2) c==0
and b!=0
. The problem is that the closed form solution for the case with c>0
gets some 0/0 errors as c
approaches 0. I have switched to using numerical quadrature which is insensitive to the issue, but I would appreciate if anybody has suggestions for a better way to code up the solutions.
Specifically, the solution for case 1 is \frac{\sqrt{\pi}}{2\sqrt{c}} e^{b^2/4c - a} (erf(\frac{b+2ct}{2\sqrt{c}}) - erf(\frac{b+2cs}{2\sqrt{c}})). The issue is that \frac{\sqrt{\pi}}{2\sqrt{c}} e^{b^2/4c} obviously goes haywire as c
goes to 0 (the erf
terms go to zero). As a result, c
doesnât have to get very small before I start getting NaN. Notably, if I switch to big(c)
floats, the issues go away. However, I would rather not go down that path. Iâm hoping someone can provide a new way to compute this that sidesteps the current deficiency.
The solution for case 2 is e^{-a}(e^{-bs}-e^{-bt})/b but does not really suffer from the same problem.
using LinearAlgebra
using SpecialFunctions
using QuadGK
# helper fun for case 1
erftransform(val,b,c) = (b+2*c*val)/(2*sqrt(c))
# case 1 solution
_integratesegment(mL,mU,a,b,c) = sqrt(pi)/(2*sqrt(c)) * exp(b^2/(4*c) - a) * erf(erftransform(mL,b,c),erftransform(mU,b,c))
# case 2 solution
_integratesegment(mL,mU,a,b) = exp(-a)*(exp(-b*mL)-exp(-b*mU))/b
# convenience function to handle branches
function integratesegment(mL,mU,a,b,c)
if c <= 1e-16 # sloppy branching...
iszero(b) && return exp(-a)*(mU-mL)
return _integratesegment(mL,mU,a,b)
else
return _integratesegment(mL,mU,a,b,c)
end
end
# numerical integration for checking
function integratesegmentgk(mL,mU,a,b,c)
hfun(x) = exp(-a -b*x -c*x^2)
res,tol = quadgk(hfun,mL,mU)
return res
end
cvals = [0, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1]
integratesegment.(0,1,1,-1,cvals)
#7-element Vector{Float64}:
# 0.6321205588285577
#NaN
#NaN
# 0.6318564031364802
# 0.629486671230845
# 0.6065301940547417
# 0.43578743768823325
integratesegmentgk.(0,1,1,-1,cvals)
#7-element Vector{Float64}:
# 0.6321205588285577
# 0.6321179164259259
# 0.632094135571238
# 0.6318564031364771
# 0.62948667123084
# 0.6065301940547421
# 0.43578743768823336
integratesegment.(0,1,1,-1,big.(cvals))
#7-element Vector{AbstractFloat}:
# 0.6321205588285577
# 0.6321179164259257048642256113765913352730335321928808376341466963000811949775715
# 0.6320941355712378411437988074357461837728588847560930563234431983546833766473449
# 0.6318564031364769326148887213013742689733182220055752005550532909361636641234183
# 0.6294866712308398372144996839722568272635753665524012813369407729846853283018586
# 0.6065301940547420107510309245899038352682705934158216165434799660850915880258804
# 0.4357874376882332994275778807401227237933115845358139306442570140687508954685834