Skip to content

Commit c1ec6dd

Browse files
committed
Restrict the incomplete gamma to x >= 0 and finish the same-precision internals
`gamma(a, x)` and `loggamma(a, x)` now throw a `DomainError` for real `x < 0` (including x == -Inf), where the mathematical value is complex except at integer `a`. This matches MPFR and the NSWC library, which both reject negative `x`. The `BigFloat` method is a direct `mpfr_gamma_inc` ccall; `_gamma_big` and its `expint` fallback for negative arguments are gone, and so is the separate `gamma(a::Integer, x)` method. The generic `_gamma` and `_loggamma` are restricted to `Float16`/`Float32`/`Float64` arguments of one precision, like the `expint` internals. `expint(::BigFloat, ::BigFloat)` delegates to MPFR through the incomplete gamma, E_ν(z) = z^(ν-1) Γ(1-ν, z), which does not cancel for `ν` near a positive integer: 258 correct bits of 256 at δ = 1e-40 where the origin series kept 119. `expintx` has no `BigFloat` method any more --- MPFR has no scaled incomplete gamma, and forming exp(z)·E_ν(z) from the unscaled value would defeat the purpose of the scaled function. The remaining `expint` internals take both arguments at one precision (`Union{T,Complex{T}}` with `T` one of the three hardware float types), with the promotion done once at the public entry: an integer order now adopts the argument's precision instead of dragging the computation to `Float64`. This removes the `float`/`promote`/`oftype` shims inside, the unreachable `En_safe_gamma_term(::Integer, ::Real)` method, and the `typemax(Int)` guard in `En_expand_origin` (the order is a float there, and `isodd` works on floats). `En_safeexpmult` and `En_imagbranchcut` are split into real and complex methods instead of branching on `isa`, using `sincospi`, and the near-pole series evaluates its `π^2`/`π^4` constants in the working precision.
1 parent 4783524 commit c1ec6dd

5 files changed

Lines changed: 92 additions & 121 deletions

File tree

src/expint.jl

Lines changed: 56 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ end
131131

132132
function _expint(z::Complex{Float64}, ::Val{expscaled}=Val{false}()) where {expscaled}
133133
if real(z) < 0
134-
return _expint(1, z, 1000, Val{expscaled}())
134+
return _expint(one(real(z)), z, 1000, Val{expscaled}())
135135
else
136136
return expint_opt(z, Val{expscaled}())
137137
end
@@ -160,8 +160,8 @@ end
160160

161161
# Continued fraction for En(ν, z) that doesn't use a term with
162162
# the gamma function: https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/10/0001/
163-
function En_cf_nogamma::Number, z::Number, n::Int=1000)
164-
B = float(z + ν)
163+
function En_cf_nogamma::Union{T,Complex{T}}, z::Union{T,Complex{T}}, n::Int=1000) where {T<:Union{Float16,Float32,Float64}}
164+
B = z + ν
165165
Bprev::typeof(B) = z
166166
A::typeof(B) = 1
167167
Aprev::typeof(B) = 1
@@ -196,18 +196,17 @@ function En_cf_nogamma(ν::Number, z::Number, n::Int=1000)
196196
end
197197

198198
# Calculate Γ(1 - ν) * z^(ν-1) safely
199-
function En_safe_gamma_term::Number, z::Number)
200-
ν1 = 1 - oftype(z, ν)
199+
function En_safe_gamma_term::Union{T,Complex{T}}, z::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
200+
ν1 = 1 - ν
201201
lgamma, lgammasign = ν1 isa Real ? logabsgamma(ν1) : (loggamma(ν1), 1)
202202
return lgammasign * exp((ν - 1)*log(z) + lgamma)
203203
end
204-
En_safe_gamma_term::Integer, z::Real) = (z 0 || isodd(ν) ? 1 : -1) * exp((ν - 1)*log(abs(z)) + loggamma(1 - oftype(z, ν)))
205204

206205
# continued fraction for En(ν, z) that uses the gamma function:
207206
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/10/0005/
208207
# returns the two terms from the above equation separately
209-
function En_cf_gamma::Number, z::Number, n::Int=1000)
210-
A, z = map(float, promote(1 - ν, z))
208+
function En_cf_gamma::Union{T,Complex{T}}, z::Union{T,Complex{T}}, n::Int=1000) where {T<:Union{Float16,Float32,Float64}}
209+
A = 1 - ν + zero(z)
211210
B = oneunit(A)
212211
Bprev = zero(B)
213212
Aprev = oneunit(A)
@@ -243,7 +242,7 @@ end
243242
# picks between continued fraction representations in
244243
# En_cf_nogamma and En_cf_gamma
245244
# returns (evaluated result, # iterations used, whether En_cf_gamma was chosen)
246-
function En_cf::Number, z::Number, niter::Int=1000)
245+
function En_cf::Union{T,Complex{T}}, z::Union{T,Complex{T}}, niter::Int=1000) where {T<:Union{Float16,Float32,Float64}}
247246
if real(1-ν) > 0
248247
gammapart, cfpart, iters = En_cf_gamma(ν, z, niter)
249248
gammaabs, cfabs = abs(gammapart), abs(cfpart)
@@ -257,7 +256,8 @@ end
257256

258257
# Compute expint(ν, z₀+Δ) given start = expint(ν, z₀), as described by [Amos 1980].
259258
# This is used to incrementally approach the negative real axis.
260-
function En_taylor::Number, start::Number, z₀::Number, Δ::Number)
259+
function En_taylor::Union{T,Complex{T}}, start::Union{T,Complex{T}}, z₀::Union{T,Complex{T}},
260+
Δ::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
261261
a = exp(z₀) * start
262262
k, iters = 0, 0
263263
asum = a
@@ -283,7 +283,7 @@ end
283283

284284
# series about origin, general ν
285285
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/01/0003/
286-
function En_expand_origin_general::Union{T,Complex{T}}, z::Union{T,Complex{T}}, niter::Int) where {T<:AbstractFloat}
286+
function En_expand_origin_general::Union{T,Complex{T}}, z::Union{T,Complex{T}}, niter::Int) where {T<:Union{Float16,Float32,Float64}}
287287
# gammaterm = En_safe_gamma_term(ν, z)
288288
gammaterm = gamma(1-ν)*z^-1)
289289
frac = one(z)
@@ -313,21 +313,9 @@ end
313313
# is O(δ^5) while the cancelling form loses accuracy like eps/δ; the two meet at
314314
# δ ~ eps(T)^(1/6), which is where the switch is made.
315315
#
316-
# There is no method for complex `BigFloat`, and none for any other `AbstractFloat`:
317-
# `polygamma` is not defined for them, and five terms could not serve that precision
318-
# in any case.
319-
#
320-
# Real `BigFloat` is delegated to MPFR instead, which computes
321-
# E_ν(z) = z^(ν-1) Γ(1-ν, z) without the cancellation. `mpfr_gamma_inc` needs z > 0
322-
# and its cost grows linearly in ν, so the series is kept where it is adequate anyway,
323-
# i.e. when no term fell into `blowup` and there was no cancellation to begin with.
324-
function En_origin_pole_series::BigFloat, z::BigFloat, gammaterm, blowup, sumterm)
325-
if !iszero(blowup) && z > 0 && ν < 1000
326-
return z^-1) * gamma(1-ν, z)
327-
end
328-
return gammaterm - (blowup + sumterm)
329-
end
330-
316+
# There is no method for any other type: `polygamma` is not defined beyond these
317+
# precisions, and five terms could not serve a wider one in any case. `BigFloat` is
318+
# handled by `expint(::BigFloat, ::BigFloat)`, which delegates to MPFR.
331319
function En_origin_pole_series::Union{T,Complex{T}}, z::Union{T,Complex{T}},
332320
gammaterm, blowup, sumterm) where {T<:Union{Float16,Float32,Float64}}
333321
m = round(ν)
@@ -345,14 +333,12 @@ function En_origin_pole_series(ν::Union{T,Complex{T}}, z::Union{T,Complex{T}},
345333
# expressions for higher order terms found using:
346334
# https://gist.github.com/augustt198/348e8f9ba33c0248f1548309c47c6d0e
347335
ψ₀, ψ₁, ψ₂, ψ₃, ψ₄ = polygamma.((0,1,2,3,4), n+1)
348-
series2 = ψ₀ + (3*ψ₀^2 + π^2 - 3*ψ₁)*δ/6 + (ψ₀^3 +^2 - 3ψ₁)*ψ₀ + ψ₂)δ^2/6
349-
series2 += (7π^4 + 15*(ψ₀^4 + 2ψ₀^2 *^2 - 3ψ₁) + ψ₁*(-2π^2 + 3ψ₁) + 4ψ₀*ψ₂) - 15ψ₃)*δ^3/360
350-
series2 += (3ψ₀^5 + ψ₀^3*(10π^2 - 30ψ₁) + 30ψ₀^2*ψ₂ + ψ₀*(45ψ₁^2 - 30π^2*ψ₁ - 15ψ₃ + 7π^4) - 30ψ₁*ψ₂ + 10π^2*ψ₂ + 3ψ₄)*δ^4/360
336+
π², π⁴ = T(π)^2, T(π)^4
337+
series2 = ψ₀ + (3*ψ₀^2 + π² - 3*ψ₁)*δ/6 + (ψ₀^3 + (π² - 3ψ₁)*ψ₀ + ψ₂)δ^2/6
338+
series2 += (7π⁴ + 15*(ψ₀^4 + 2ψ₀^2 * (π² - 3ψ₁) + ψ₁*(-2π² + 3ψ₁) + 4ψ₀*ψ₂) - 15ψ₃)*δ^3/360
339+
series2 += (3ψ₀^5 + ψ₀^3*(10π² - 30ψ₁) + 30ψ₀^2*ψ₂ + ψ₀*(45ψ₁^2 - 30π²*ψ₁ - 15ψ₃ + 7π⁴) - 30ψ₁*ψ₂ + 10π²*ψ₂ + 3ψ₄)*δ^4/360
351340

352-
# `π^2` and `π^4` above are `Float64`, so the series is evaluated in at least that
353-
# precision and narrowed here
354-
res = (series1 + series2) * En_safe_expfact(n, z) * z^-n-1) - sumterm
355-
return oftype(gammaterm, res)
341+
return (series1 + series2) * En_safe_expfact(n, z) * z^-n-1) - sumterm
356342
end
357343

358344
# Compute (-z)^n / n!, avoiding overflow if possible.
@@ -367,13 +353,13 @@ end
367353
# takes over: the term is then negligible next to the sums the callers add it to, and
368354
# orders too large to loop over have to be handled as well (`expint(1e15, 2.5)` is
369355
# tested, and `Int` is 32 bits on some platforms).
370-
function En_safe_expfact(n::T, z::T) where {T<:AbstractFloat}
356+
function En_safe_expfact(n::T, z::T) where {T<:Union{Float16,Float32,Float64}}
371357
n < 12 && return _En_powerterm(n, z)
372358
sgn = z <= 0 ? one(T) : (isodd(n) ? -one(T) : one(T))
373359
return sgn * exp(n*log(abs(z)) - loggamma(n + one(T)))
374360
end
375361

376-
function En_safe_expfact(n::T, z::Complex{T}) where {T<:AbstractFloat}
362+
function En_safe_expfact(n::T, z::Complex{T}) where {T<:Union{Float16,Float32,Float64}}
377363
n < 12 && return _En_powerterm(n, z)
378364
return exp(n*log(-z) - loggamma(n + one(T)))
379365
end
@@ -389,10 +375,10 @@ end
389375

390376
# series about the origin, special case for integer n > 0
391377
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/02/0005/
392-
function En_expand_origin_posint(n, z::Number, niter::Integer)
378+
function En_expand_origin_posint(n::T, z::Union{T,Complex{T}}, niter::Int) where {T<:Union{Float16,Float32,Float64}}
393379
frac = one(real(z))
394-
gammaterm = En_safe_expfact(oftype(frac, n-1), z) # (-z)^(n-1) / (n-1)!
395-
gammaterm *= digamma(oftype(frac,n)) - log(z)
380+
gammaterm = En_safe_expfact(n-1, z) # (-z)^(n-1) / (n-1)!
381+
gammaterm *= digamma(n) - log(z)
396382
sumterm = n == 1 ? zero(frac) : frac / (1 - n)
397383
k = 1
398384
ϵ = 10*eps(real(sumterm))
@@ -411,41 +397,45 @@ function En_expand_origin_posint(n, z::Number, niter::Integer)
411397
return gammaterm - sumterm
412398
end
413399

414-
function En_expand_origin::Number, z::Number, niter::Int)
400+
function En_expand_origin::Union{T,Complex{T}}, z::Union{T,Complex{T}}, niter::Int) where {T<:Union{Float16,Float32,Float64}}
415401
if isinteger(ν) && real(ν) > 0
416-
return real(ν) < (typemax(Int)>>2) ? En_expand_origin_posint(Int(real(ν)), z, niter) : En_expand_origin_posint(real(ν), z, niter)
402+
return En_expand_origin_posint(real(ν), z, niter)
417403
else
418-
# `En_expand_origin_general` takes both arguments at the same precision
419-
T = typeof(one(real(z)))
420-
return En_expand_origin_generalisa Real ? convert(T, ν) : convert(Complex{T}, ν), z, niter)
404+
return En_expand_origin_general(ν, z, niter)
421405
end
422406
end
423407

424408
# can find imaginary part of E_ν(x) for x on negative real axis analytically
425409
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/04/05/01/0003/
426-
function En_imagbranchcut::Union{T,Complex{T}}, z::Union{T,Complex{T}}) where {T<:AbstractFloat}
410+
function En_imagbranchcut::T, z::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
411+
a = real(z)
412+
s, c = sincospi(ν)
413+
lgamma, lgammasign = logabsgamma(ν)
414+
return -2 * lgammasign * Complex(c, -s) * π * exp((ν-1)*log(complex(a)) - lgamma) * im
415+
end
416+
function En_imagbranchcut::Complex{T}, z::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
427417
a = real(z)
428418
e1 = exp* imag(ν))
429-
e2 = Complex(cospi(real(ν)), -sinpi(real(ν)))
430-
lgamma, lgammasign = ν isa Real ? logabsgamma(ν) : (loggamma(ν), 1)
431-
return -2 * lgammasign * e1 * π * e2 * exp((ν-1)*log(complex(a)) - lgamma) * im
419+
s, c = sincospi(real(ν))
420+
return -2 * e1 * Complex(c, -s) * π * exp((ν-1)*log(complex(a)) - loggamma(ν)) * im
432421
end
433422

434-
function En_safeexpmult(z, a)
423+
# compute exp(z) * a, avoiding overflow of the exponential by shifting into the exponent
424+
function En_safeexpmult(z::Union{T,Complex{T}}, a::T) where {T<:Union{Float16,Float32,Float64}}
435425
zexp = exp(z)
436-
if isinf(zexp) || iszero(zexp)
437-
return a isa Real ? sign(a) * exp(z + log(abs(a))) : exp(z + log(a))
438-
else
439-
return zexp*a
440-
end
426+
return isinf(zexp) || iszero(zexp) ? sign(a) * exp(z + log(abs(a))) : zexp*a
427+
end
428+
function En_safeexpmult(z::Union{T,Complex{T}}, a::Complex{T}) where {T<:Union{Float16,Float32,Float64}}
429+
zexp = exp(z)
430+
return isinf(zexp) || iszero(zexp) ? exp(z + log(a)) : zexp*a
441431
end
442432

443-
function _expint::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{false}()) where {expscaled}
433+
function _expint::Union{T,Complex{T}}, z::Union{T,Complex{T}}, niter::Int=1000,
434+
::Val{expscaled}=Val{false}()) where {T<:Union{Float16,Float32,Float64}, expscaled}
444435
if abs(ν) > 50 && !(isreal(ν) && real(ν) > 0)
445436
throw(ArgumentError("Unsupported order |ν| > 50 off the positive real axis"))
446437
end
447438

448-
z, = promote(float(z), ν)
449439
if isnan(ν) || isnan(z)
450440
return oftype(z, NaN) * z
451441
end
@@ -535,9 +525,7 @@ function _expint(ν::Number, z::Number, niter::Int=1000, ::Val{expscaled}=Val{fa
535525

536526
# handle branch cut
537527
if imz == 0
538-
# `En_imagbranchcut` takes both arguments at the same precision
539-
νc = ν isa Real ? convert(real(typeof(z)), ν) : convert(complex(real(typeof(z))), ν)
540-
bc = En_imagbranchcut(νc, z)
528+
bc = En_imagbranchcut(ν, z)
541529
bit = !signbit(imag(z))
542530
sign = bit ? 1 : -1
543531
if isreal(ν)
@@ -565,7 +553,14 @@ External links:
565553
[DLMF 8.19](https://dlmf.nist.gov/8.19),
566554
[Wikipedia](https://en.wikipedia.org/wiki/Exponential_integral)
567555
"""
568-
expint::Number, z::Number, niter::Int=1000) = _expint(ν, z, niter, Val{false}())
556+
expint::Number, z::Number, niter::Int=1000) =
557+
_expint(promotereal(ν, float(z))..., niter, Val{false}())
558+
559+
# For real `BigFloat` arguments MPFR's incomplete gamma gives E_ν(z) = z^(ν-1) Γ(1-ν, z)
560+
# directly, and unlike the series about the origin it does not cancel for `ν` near a
561+
# positive integer. It throws for z < 0, where Γ(1-ν, z) is generally complex. There is
562+
# no scaled counterpart in MPFR, so `expintx` has no `BigFloat` method.
563+
_expint::BigFloat, z::BigFloat, niter::Int, ::Val{false}) = z^-1) * gamma(1-ν, z)
569564

570565

571566
@doc raw"""
@@ -581,7 +576,8 @@ If ``\nu`` is not specified, ``\nu = 1`` is used. Arbitrary complex
581576
582577
See also: [`expint(ν, z)`](@ref SpecialFunctions.expint)
583578
"""
584-
expintx::Number, z::Number, niter::Int=1000) = _expint(ν, z, niter, Val{true}())
579+
expintx::Number, z::Number, niter::Int=1000) =
580+
_expint(promotereal(ν, float(z))..., niter, Val{true}())
585581

586582
##############################################################################
587583
# expinti function Ei

src/gamma_inc.jl

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,8 @@ Returns the upper incomplete gamma function
10991099
```math
11001100
\Gamma(a,x) = \int_x^\infty t^{a-1} e^{-t} \mathrm{d}t
11011101
```
1102-
supporting arbitrary real or complex `a` and `x`.
1102+
for real or complex `a` and `x` of `Float16`, `Float32` or `Float64` precision, and for
1103+
real `BigFloat` arguments with `x >= 0`.
11031104
11041105
(The ordinary gamma function [`gamma(x)`](@ref) corresponds to ``\Gamma(a) = \Gamma(a,0)``.
11051106
See also the [`gamma_inc`](@ref) function to compute both the upper and lower
@@ -1110,44 +1111,23 @@ External links:
11101111
[Wikipedia](https://en.wikipedia.org/wiki/Incomplete_gamma_function)
11111112
"""
11121113
gamma(a::Number, x::Number) = _gamma(promotereal(float(a), float(x))...)
1113-
gamma(a::Integer, x::Number) = _gamma(a, float(x))
11141114

1115-
function _gamma(a::Number, x::Number)
1115+
function _gamma(a::Union{T,Complex{T}}, x::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
1116+
# Γ(a,x) is not real for x < 0, except for integer a, and is not supported there
1117+
x isa Real && x < 0 && throw(DomainError((a, x), "gamma will only return a complex result if called with a complex argument"))
11161118
if a isa Real && x isa Real && !isfinite(a*x)
1117-
if isinf(x) && isfinite(a)
1118-
if x > 0 # == +Inf
1119-
return one(a)*zero(x)
1120-
elseif a > 0 && isinteger(a) # x == -Inf
1121-
return one(a)*x # -Inf
1122-
end
1119+
if isinf(x) && isfinite(a) # x == +Inf
1120+
return one(a)*zero(x)
11231121
elseif isinf(a) && isfinite(x)
1124-
if a > 0
1125-
if x 0
1126-
return a*one(x) # +Inf
1127-
else
1128-
throw(DomainError((a, x), "gamma will only return a complex result if called with a complex argument"))
1129-
end
1130-
elseif a < 0
1131-
return zero(a)*one(x)
1132-
end
1122+
return a > 0 ? a*one(x) : zero(a)*one(x) # +Inf or 0
11331123
end
11341124
end
11351125
return iszero(x) ? gamma(one(x)*a) : x^a * expint(1 - a, x)
11361126
end
11371127

1138-
_gamma(a::Integer, x::BigFloat) = _gamma_big(a, x)
1139-
_gamma(a::BigInt, x::Real) = _gamma_big(a, x)
1140-
_gamma(a::BigInt, x::BigFloat) = _gamma_big(a, x)
1141-
_gamma(a::BigFloat,x::BigFloat) = _gamma_big(a, x)
1142-
function _gamma_big(a::Real,x::Real)
1143-
if x < 0
1144-
# MPFR returns NaN in this case
1145-
if isinteger(a) && a > 0
1146-
return invoke(_gamma, Tuple{Number,Number}, a, BigFloat(x))
1147-
else
1148-
throw(DomainError((a, x), "gamma will only return a complex result if called with a complex argument"))
1149-
end
1150-
end
1128+
function _gamma(a::BigFloat, x::BigFloat)
1129+
# MPFR returns NaN for x < 0, where Γ(a,x) is complex unless a is an integer
1130+
x < 0 && throw(DomainError((a, x), "gamma will only return a complex result if called with a complex argument"))
11511131
z = BigFloat()
11521132
ccall((:mpfr_gamma_inc, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Int32), z, a, x, ROUNDING_MODE[])
11531133
return z
@@ -1160,7 +1140,7 @@ Returns the log of the upper incomplete gamma function [`gamma(a,x)`](@ref):
11601140
```math
11611141
\log \Gamma(a,x) = \log \int_x^\infty t^{a-1} e^{-t} \mathrm{d}t
11621142
```
1163-
supporting arbitrary real or complex `a` and `x`.
1143+
for real or complex `a` and `x` of `Float16`, `Float32` or `Float64` precision.
11641144
11651145
If `a` and/or `x` is complex, then `exp(loggamma(a,x))` matches `gamma(a,x)` (up to floating-point error),
11661146
but `loggamma(a,x)` may differ from `log(gamma(a,x))` by an integer multiple of ``2\pi i``
@@ -1169,28 +1149,17 @@ but `loggamma(a,x)` may differ from `log(gamma(a,x))` by an integer multiple of
11691149
See also [`loggamma(x)`](@ref).
11701150
"""
11711151
loggamma(a::Number, x::Number) = _loggamma(promotereal(float(a), float(x))...)
1172-
loggamma(a::Integer, x::Number) = _loggamma(a, float(x))
1173-
function _loggamma(a::Number, x::Number)
1152+
function _loggamma(a::Union{T,Complex{T}}, x::Union{T,Complex{T}}) where {T<:Union{Float16,Float32,Float64}}
1153+
# as for `gamma(a,x)`, x < 0 is not supported
1154+
x isa Real && x < 0 && throw(DomainError((a, x), "loggamma will only return a complex result if called with a complex argument"))
11741155
if a isa Real && x isa Real && !isfinite(a*x)
1175-
if isinf(x) && isfinite(a)
1176-
if x > 0 # == +Inf
1177-
return -one(a)*x
1178-
elseif x < 0
1179-
throw(DomainError((a, x), "loggamma will only return a complex result if called with a complex argument"))
1180-
end
1156+
if isinf(x) && isfinite(a) # x == +Inf
1157+
return -one(a)*x
11811158
elseif isinf(a) && isfinite(x)
1182-
if a > 0 && x 0
1183-
return a*one(x) # +Inf
1184-
elseif a < 0
1185-
return a*one(x) # -Inf
1186-
end
1159+
return a*one(x) # +Inf or -Inf
11871160
end
11881161
end
11891162
# from gamma(a,x) = x^a * expintx(1-a, x) * exp(-x):
11901163
iszero(x) && return loggamma(one(x)*a)
1191-
if x isa Real && x < 0 && a isa Integer && isodd(a)
1192-
# minus signs in expintx and x^a may cancel
1193-
return a*log(-x) + log(-expintx(1-a, x)) - x
1194-
end
11951164
return a*log(x) + log(expintx(1 - a, x)) - x
11961165
end

test/expint.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ using Base.MathConstants
159159
@test Γ + cf*exp(-x) y
160160
end
161161
# type stability
162-
@test @inferred(SpecialFunctions.En_cf_gamma(1, 1.0 + 2.1im, 1000)) isa Tuple{ComplexF64,ComplexF64,Int}
163-
@test @inferred(SpecialFunctions.En_cf_gamma(1, 1.0f0, 1000)) isa Tuple{Float32,Float32,Int}
162+
@test @inferred(SpecialFunctions.En_cf_gamma(1.0, 1.0 + 2.1im, 1000)) isa Tuple{ComplexF64,ComplexF64,Int}
163+
@test @inferred(SpecialFunctions.En_cf_gamma(1.0f0, 1.0f0, 1000)) isa Tuple{Float32,Float32,Int}
164164
end
165165
@testset "En_expand_origin" begin
166166
for (x, y) in zip(xs, ys)

0 commit comments

Comments
 (0)