@@ -114,7 +114,7 @@ const denom_10_20 = (1.0,
114
114
0.2523432345539146248733539983749722854603 )
115
115
116
116
# adapted from Steven G Johnson's initial implementation: issue #19
117
- function expint (x:: Float64 )
117
+ function expint_opt (x:: Float64 )
118
118
x < 0 && throw (DomainError (x, " negative argument, convert to complex first" ))
119
119
x == 0 && return Inf
120
120
if x > 2.15
@@ -132,10 +132,7 @@ function expint(x::Float64)
132
132
end
133
133
end
134
134
135
- function expint (z:: Complex{Float64} )
136
- if real (z) < 0
137
- return expint (1 , z)
138
- end
135
+ function expint_opt (z:: Complex{Float64} )
139
136
x² = real (z)^ 2
140
137
y² = imag (z)^ 2
141
138
if x² + 0.233 * y² ≥ 7.84 # use cf expansion, ≤ 30 terms
@@ -158,6 +155,15 @@ function expint(z::Complex{Float64})
158
155
end
159
156
end
160
157
158
+ function expint (z:: Complex{Float64} )
159
+ if real (z) < 0
160
+ return expint (1 , z)
161
+ else
162
+ return expint_opt (z)
163
+ end
164
+ end
165
+ expint (x:: Float64 ) = expint_opt (x)
166
+
161
167
expint (z:: Union{T,Complex{T},Rational{T},Complex{Rational{T}}} ) where {T<: Integer } = expint (float (z))
162
168
expint (x:: Number ) = expint (1 , x)
163
169
expint (z:: Float32 ) = Float32 (expint (Float64 (z)))
@@ -214,7 +220,7 @@ function En_cf_nogamma(ν::Number, z::Number, n::Int=1000)
214
220
end
215
221
216
222
# Calculate Γ(1 - ν) * z^(ν-1) safely
217
- En_safe_gamma_term (ν:: Number , z:: Number ) = exp ((ν - 1 )* log (z) + loggamma (1 - ν ))
223
+ En_safe_gamma_term (ν:: Number , z:: Number ) = exp ((ν - 1 )* log (z) + loggamma (1 - oftype (z, ν) ))
218
224
219
225
# continued fraction for En(ν, z) that uses the gamma function:
220
226
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/10/0005/
@@ -380,22 +386,24 @@ function expint(ν::Number, z::Number, niter::Int=1000)
380
386
if abs (ν) > 50 && ! (isreal (ν) && real (ν) > 0 )
381
387
throw (ArgumentError (" Unsupported order |ν| > 50 off the positive real axis" ))
382
388
end
383
- ν, z = promote (ν, float (z))
384
- if typeof (z) <: Real && z < 0
389
+
390
+ z, = promote (float (z), ν)
391
+ if isnan (ν) || isnan (z)
392
+ return oftype (z, NaN ) * z
393
+ end
394
+
395
+ if z isa Real && (isinteger (ν) ? (z < 0 && ν > 0 ) : (z < 0 || ν < 0 ))
385
396
throw (DomainError (z, " En will only return a complex result if called with a complex argument" ))
386
397
end
387
398
388
- if z == 0.0
389
- if real (ν) > 0
390
- return 1 / (ν - 1 )
391
- else
392
- return oftype (z, Inf )
393
- end
399
+ if z == 0
400
+ return oftype (z, real (ν) > 0 ? 1 / (ν- 1 ) : Inf )
394
401
end
402
+
395
403
if ν == 0
396
404
return exp (- z) / z
397
405
elseif ν == 1 && real (z) > 0 && z isa Union{Float64, Complex{Float64}}
398
- return E₁ (z)
406
+ return expint_opt (z)
399
407
end
400
408
# asymptotic test for |z| → ∞
401
409
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/02/0003/
@@ -408,9 +416,8 @@ function expint(ν::Number, z::Number, niter::Int=1000)
408
416
return En_expand_origin (ν, z)
409
417
end
410
418
411
- if real (z) > 0 && real (ν) > 0
412
- res, i = En_cf_nogamma (ν, z, niter)
413
- return res
419
+ if z isa Real
420
+ return first (z > 0 ? En_cf (ν, z, niter) : En_cf_nogamma (ν, z, niter))
414
421
else
415
422
# Procedure for z near the negative real axis based on
416
423
# (without looking at the accompanying source code):
@@ -424,7 +431,7 @@ function expint(ν::Number, z::Number, niter::Int=1000)
424
431
425
432
quick_niter, nmax = 50 , 45
426
433
# start with small imaginary part if exactly on negative real axis
427
- imstart = (imz == 0 ) ? abs (z)* 1e-8 : imz
434
+ imstart = (imz == 0 ) ? abs (z)* sqrt ( eps ( typeof ( real (z)))) : imz
428
435
z₀ = rez + imstart* im
429
436
E_start, i, _ = En_cf (ν, z₀, quick_niter)
430
437
if imz > 0 && i < nmax
0 commit comments