@@ -292,38 +292,77 @@ end
292
292
293
293
# series about origin, general ν
294
294
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/01/0003/
295
- function En_expand_origin_general (ν:: Number , z:: Number )
296
- gammaterm = En_safe_gamma_term (ν, z)
297
- frac = one (real (z))
298
- sumterm = frac / (1 - ν)
299
- k, maxiter = 1 , 100
300
- ϵ = 10 * eps (real (sumterm))
301
- while k < maxiter
295
+ function En_expand_origin_general (ν:: Number , z:: Number , niter:: Integer )
296
+ # gammaterm = En_safe_gamma_term(ν, z)
297
+ gammaterm = gamma (1 - ν)* z^ (ν- 1 )
298
+ frac = one (z)
299
+ blowup = abs (1 - ν) < 0.5 ? frac / (1 - ν) : zero (z)
300
+ sumterm = abs (1 - ν) < 0.5 ? zero (z) : frac / (1 - ν)
301
+ k = 1
302
+ ε = 10 * eps (typeof (abs (frac)))
303
+ while k < niter
302
304
frac *= - z / k
303
305
prev = sumterm
304
- sumterm += frac / (k + 1 - ν)
305
- if abs (sumterm - prev) < ϵ
306
- break
306
+ if abs (k + 1 - ν) < 0.5
307
+ blowup += frac / (k + 1 - ν)
308
+ else
309
+ sumterm += frac / (k + 1 - ν)
310
+ if abs (sumterm - prev) < ε* abs (prev)
311
+ break
312
+ end
307
313
end
308
314
k += 1
309
315
end
310
- return gammaterm - sumterm
316
+
317
+ if real (ν+ z) isa Union{Float64, Float32} && abs (gammaterm - blowup) < 1e-3 * abs (blowup)
318
+ δ = round (ν) - ν
319
+ n = real (round (ν)) - 1
320
+
321
+ # (1 - z^δ)/δ series
322
+ logz = log (z)
323
+ series1 = - logz - logz^ 2 * δ/ 2 - logz^ 3 * δ^ 2 / 6 - logz^ 4 * δ^ 3 / 24 - logz^ 5 * δ^ 4 / 120
324
+
325
+ # due to https://functions.wolfram.com/GammaBetaErf/Gamma/06/01/05/01/0004/
326
+ # expressions for higher order terms found using:
327
+ # https://gist.github.com/augustt198/348e8f9ba33c0248f1548309c47c6d0e
328
+ ψ₀, ψ₁, ψ₂, ψ₃, ψ₄ = polygamma .((0 ,1 ,2 ,3 ,4 ), n+ 1 )
329
+ series2 = ψ₀ + (3 * ψ₀^ 2 + π^ 2 - 3 * ψ₁)* δ/ 6 + (ψ₀^ 3 + (π^ 2 - 3 ψ₁)* ψ₀ + ψ₂)δ^ 2 / 6
330
+ series2 += (7 π^ 4 + 15 * (ψ₀^ 4 + 2 ψ₀^ 2 * (π^ 2 - 3 ψ₁) + ψ₁* (- 2 π^ 2 + 3 ψ₁) + 4 ψ₀* ψ₂) - 15 ψ₃)* δ^ 3 / 360
331
+ series2 += (3 ψ₀^ 5 + ψ₀^ 3 * (10 π^ 2 - 30 ψ₁) + 30 ψ₀^ 2 * ψ₂ + ψ₀* (45 ψ₁^ 2 - 30 π^ 2 * ψ₁ - 15 ψ₃ + 7 π^ 4 ) - 30 ψ₁* ψ₂ + 10 π^ 2 * ψ₂ + 3 ψ₄)* δ^ 4 / 360
332
+
333
+ return (series1 + series2) * En_safe_expfact (n, z) * z^ (ν- n- 1 ) - sumterm
334
+ end
335
+ return gammaterm - (blowup + sumterm)
311
336
end
312
337
313
- # series about the origin, special case for integer n > 0
314
- # https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/02/0005/
315
- function En_expand_origin_posint (n:: Integer , z:: Number )
316
- gammaterm = 1 # (-z)^(n-1) / (n-1)!
317
- for i = 1 : n- 1
318
- gammaterm *= - z / i
338
+ # compute (-z)^n / n!, avoiding overflow if possible, where n is an integer ≥ 0 (but not necessarily an Integer)
339
+ function En_safe_expfact (n:: Real , z:: Number )
340
+ if n < 100
341
+ powerterm = one (z)
342
+ for i = 1 : Int (n)
343
+ powerterm *= - z/ i
344
+ end
345
+ return powerterm
346
+ else
347
+ if z isa Real
348
+ sgn = z ≤ 0 ? one (n) : (n <= typemax (Int) ? (isodd (Int (n)) ? - one (n) : one (n)) : (- 1 )^ n)
349
+ return sgn * exp (n * log (abs (z)) - loggamma (n+ 1 ))
350
+ else
351
+ return exp (n * log (- z) - loggamma (n+ 1 ))
352
+ end
319
353
end
354
+ end
320
355
356
+ # series about the origin, special case for integer n > 0
357
+ # https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/02/0005/
358
+ function En_expand_origin_posint (n, z:: Number , niter:: Integer )
359
+ gammaterm = En_safe_expfact (n- 1 , z) # (-z)^(n-1) / (n-1)!
321
360
frac = one (real (z))
322
361
gammaterm *= digamma (oftype (frac,n)) - log (z)
323
362
sumterm = n == 1 ? zero (frac) : frac / (1 - n)
324
- k, maxiter = 1 , 100
363
+ k = 1
325
364
ϵ = 10 * eps (real (sumterm))
326
- while k < maxiter
365
+ while k < niter
327
366
frac *= - z / k
328
367
# skip term with zero denominator
329
368
if k != n- 1
@@ -338,11 +377,11 @@ function En_expand_origin_posint(n::Integer, z::Number)
338
377
return gammaterm - sumterm
339
378
end
340
379
341
- function En_expand_origin (ν:: Number , z:: Number )
380
+ function En_expand_origin (ν:: Number , z:: Number , niter :: Integer )
342
381
if isinteger (ν) && real (ν) > 0
343
- return En_expand_origin_posint (Integer (ν) , z)
382
+ return real (ν) < ( typemax (Int) >> 2 ) ? En_expand_origin_posint (Int ( real (ν)) , z, niter) : En_expand_origin_posint ( real (ν), z, niter )
344
383
else
345
- return En_expand_origin_general (ν, z)
384
+ return En_expand_origin_general (ν, z, niter )
346
385
end
347
386
end
348
387
@@ -398,7 +437,7 @@ function _expint(ν::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{fa
398
437
if abs2 (z) < 9
399
438
# use Taylor series about the origin for small z
400
439
mult = expscaled ? exp (z) : 1
401
- return mult * En_expand_origin (ν, z)
440
+ return mult * En_expand_origin (ν, z, niter )
402
441
end
403
442
404
443
if z isa Real || real (z) > 0
@@ -409,7 +448,7 @@ function _expint(ν::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{fa
409
448
g, cf, _ = zero (z), En_cf_nogamma (ν, z, niter)...
410
449
end
411
450
g != 0 && (g *= gmult)
412
- cf = expscaled ? cf : En_safeexpmult (- z, cf)
451
+ cf = expscaled ? cf : En_safeexpmult (- z, cf)
413
452
return g + cf
414
453
else
415
454
# Procedure for z near the negative real axis based on
0 commit comments