Skip to content

Commit 3ece734

Browse files
authored
bug fixes in expintx (#285)
* bug fixes in expintx * fix spurious underflow in expintx for real(z) >> 1
1 parent 9d73acd commit 3ece734

File tree

2 files changed

+27
-28
lines changed

2 files changed

+27
-28
lines changed

src/expint.jl

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,19 @@ function En_cf_nogamma(ν::Number, z::Number, n::Int=1000)
169169
scale = sqrt(floatmax(real(A)))
170170

171171
# two recurrence steps / loop
172-
iters = 0
172+
iters = 1
173173
for i = 2:n
174174
iters += 1
175175

176-
A′ = A
177-
A = z*A + (i-1) * Aprev
178-
Aprev = A′
179-
B′ = B
180-
B = z*B + (i-1) * Bprev
181-
Bprev = B′
176+
A, Aprev = z*A + (i-1) * Aprev, A
177+
B, Bprev = z*B + (i-1) * Bprev, B
182178

183-
A′ = A
184-
A = A ++i-1) * Aprev
185-
Aprev = A′
186-
B′ = B
187-
B = B ++i-1) * Bprev
188-
Bprev = B′
179+
(isinf(A) | isinf(B)) && return Aprev/Bprev, iters-1
189180

190-
conv = abs(Aprev*B - A*Bprev) < ϵ*abs(B*Bprev)
191-
conv && i > 4 && break
181+
A, Aprev = A ++i-1) * Aprev, A
182+
B, Bprev = B ++i-1) * Bprev, B
183+
184+
i > 4 && abs(Aprev*B - A*Bprev) < ϵ*abs(B*Bprev) && break
192185

193186
# rescale
194187
if fastabs(A) > scale
@@ -221,18 +214,14 @@ function En_cf_gamma(ν::Number, z::Number, n::Int=1000)
221214
ϵ = 10*eps(real(B))
222215
scale = sqrt(floatmax(real(A)))
223216

224-
iters = 0
217+
iters = 1
225218
j = 1
226219
for i = 2:n
227220
iters += 1
228221

229-
A′ = A
230222
term = iseven(i) ? -(i÷2 - 1 - ν)*z : z*(i÷2)
231-
A = (i - ν)*A + term * Aprev
232-
Aprev = A′
233-
B′ = B
234-
B = (i - ν)*B + term * Bprev
235-
Bprev = B′
223+
A, Aprev = (i - ν)*A + term * Aprev, A
224+
B, Bprev = (i - ν)*B + term * Bprev, B
236225

237226
conv = abs(Aprev*B - A*Bprev) < ϵ*abs(B*Bprev)
238227
conv && break
@@ -458,21 +447,25 @@ function _expint(ν::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{fa
458447
# 16(2), 169–177. https://doi.org/10.1145/78928.78933
459448
doconj = imag(z) < 0
460449
rez, imz = real(z), abs(imag(z))
450+
zorig = z
461451
z = doconj ? conj(z) : z
462452
ν = doconj ? conj(ν) : ν
463453

464-
quick_niter, nmax = 50, 45
454+
quick_niter = niter >> 4
465455
# start with small imaginary part if exactly on negative real axis
466456
imstart = (imz == 0) ? abs(z)*sqrt(eps(typeof(real(z)))) : imz
467457
z₀ = rez + imstart*im
468458
g_start, cf_start, i, _ = En_cf(ν, z₀, quick_niter)
469459
E_start = g_start + En_safeexpmult(-z₀, cf_start)
470460
isnan(E_start) && return E_start
471-
if imz > 0 && i < nmax
461+
if imz > 0 && i < quick_niter
472462
# didn't need to take any steps
463+
if expscaled
464+
E_start = En_safeexpmult(z₀, g_start) + cf_start
465+
end
473466
return doconj ? conj(E_start) : E_start
474467
end
475-
while i > nmax
468+
while i == quick_niter
476469
# double imaginary part until in region with fast convergence
477470
imstart *= 2
478471
z₀ = rez + imstart*im
@@ -504,7 +497,7 @@ function _expint(ν::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{fa
504497
En = bit ? En : En + bc
505498
end
506499
end
507-
return expscaled ? exp(z) * En : En
500+
return expscaled ? En_safeexpmult(zorig, En) : En
508501
end
509502
end
510503

test/expint.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ using Base.MathConstants
9393
for (i, ans) in zip(1:15, near_pole5_ans)
9494
@test expint(5 - 10.0^(-i), 2.5) ans
9595
end
96-
96+
9797
@test expint(2.000001, 4.3) 0.0022470372637239675640390482141893761501016099509821867746
9898
@test expint(1.999999, 4.3) 0.0022470379319936678143503120160911823783417969321242814713
9999

@@ -141,11 +141,17 @@ using Base.MathConstants
141141
@testset "expintx" begin
142142
@test expintx(1e-10) 22.448635267383787506197038031047821505309344119883144316155006107
143143
@test expintx(1e-100) 229.68129363450303554119263337835401832906798952693737400452702286
144-
@test expintx(1e10) 9.999999999000000000199999999940000000023999999988000000007e-11
144+
@test expintx(1e10) 9.999999999000000000199999999940000000023999999988000000007e-11
145145
@test_broken expintx(1e10, 1e10im) 4.99999999999999999995000000001499999999700000000000000000e-11 - 4.99999999950000000004999999999999999999700000000149999999e-11im
146146
@test expintx(2, 1e10) 9.999999998000000000599999999760000000119999999928000000050e-11
147147
@test expintx(5+5im, 1e10+1e10im) 4.99999999750000000124999999940000000023624999998587499986e-11 - 4.99999999750000000149999999897500000075624999942337500043e-11im
148148
@test expintx(2, 1e5+1e5im) 4.999999998500059998500000003149748011339999937637483913514e-6 - 4.999900001499999998500089996850000011338866062369999513582e-6im
149+
150+
for ν in (1,2,-2,2+3im,2-3im,-2+3im,-2-3im), z in (0.1+0.2im, -0.1+0.2im, 4+5im, -4+5im, -4-5im, -10+1e-4im, -10-1e-4im)
151+
@test expintx(ν, z) exp(z) * expint(ν, z)
152+
end
153+
154+
@test expintx(4, 1e300) == 1e-300
149155
end
150156

151157
# issue #272: more cases with real results

0 commit comments

Comments
 (0)