Skip to content

Commit 8072ed6

Browse files
authored
digamma and trigamma accuracy improvements (#451)
* digamma accuracy improvement * changed `trigamma` and use `sinpi` * `sincospi` replaced by `sinpi, cospi` * use `tanpi` if available * added test case for `cotderiv(0, ...)` * code coverage
1 parent 37308bc commit 8072ed6

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

src/gamma.jl

+17-8
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,16 @@ function _digamma(z::ComplexOrReal{Float64})
2828
# argument," Computer Phys. Commun. vol. 4, pp. 221–226 (1972).
2929
x = real(z)
3030
if x <= 0 # reflection formula
31-
ψ = -π * cot*z)
31+
ψ = -π * _cotpi(z)
3232
z = 1 - z
3333
x = real(z)
3434
else
3535
ψ = zero(z)
3636
end
37-
if x < 7
37+
X = 8
38+
if x < X
3839
# shift using recurrence formula
39-
n = 7 - floor(Int,x)
40+
n = X - floor(Int,x)
4041
for ν = 1:n-1
4142
ψ -= inv(z + ν)
4243
end
@@ -56,6 +57,13 @@ function _digamma(x::BigFloat)
5657
return z
5758
end
5859

60+
"""
61+
_cotpi(x) = cot(π * x)
62+
63+
Accurate for integer arguments
64+
"""
65+
_cotpi(x) = @static VERSION >= v"1.10.0-DEV.525" ? inv(tanpi(x)) : cospi(x) / sinpi(x)
66+
5967
"""
6068
trigamma(x)
6169
@@ -67,12 +75,13 @@ function _trigamma(z::ComplexOrReal{Float64})
6775
# via the derivative of the Kölbig digamma formulation
6876
x = real(z)
6977
if x <= 0 # reflection formula
70-
return* csc*z))^2 - trigamma(1 - z)
78+
return/ sinpi(z))^2 - trigamma(1 - z)
7179
end
7280
ψ = zero(z)
73-
if x < 8
81+
N = 10
82+
if x < N
7483
# shift using recurrence formula
75-
n = 8 - floor(Int,x)
84+
n = N - floor(Int,x)
7685
ψ += inv(z)^2
7786
for ν = 1:n-1
7887
ψ += inv(z + ν)^2
@@ -132,12 +141,12 @@ const cotderiv_Q = [cotderiv_q(m) for m in 1:100]
132141
function cotderiv(m::Integer, z)
133142
isinf(imag(z)) && return zero(z)
134143
if m <= 0
135-
m == 0 && return π * cot*z)
144+
m == 0 && return π * _cotpi(z)
136145
throw(DomainError(m, "`m` must be nonnegative."))
137146
end
138147
if m <= length(cotderiv_Q)
139148
q = cotderiv_Q[m]
140-
x = cot*z)
149+
x = _cotpi(z)
141150
y = x*x
142151
s = q[1] + q[2] * y
143152
t = y

test/gamma.jl

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
@test digamma(convert(elty, 7e-7)) convert(elty, -1428572.005785942019703646)
1313
@test digamma(convert(elty, -0.5)) convert(elty, .03648997397857652055902367)
1414
@test digamma(convert(elty, -1.1)) convert(elty, 10.15416395914385769902271)
15+
# issue #450
16+
@test digamma(convert(elty, 0)) == convert(elty, -Inf)
17+
@test digamma(convert(elty, -1)) == convert(elty, -Inf)
1518

1619
@test digamma(convert(elty, 0.1)) convert(elty, -10.42375494041108)
1720
@test digamma(convert(elty, 1/2)) convert(elty, -γ - log(4))
@@ -35,6 +38,8 @@
3538
@test trigamma(convert(elty, 4)) convert(elty, π^2/6 - 49/36)
3639
@test trigamma(convert(elty, 5)) convert(elty, π^2/6 - 205/144)
3740
@test trigamma(convert(elty, 10)) convert(elty, π^2/6 - 9778141/6350400)
41+
@test trigamma(convert(elty, 0)) == convert(elty, Inf)
42+
@test trigamma(convert(elty, -1)) == convert(elty, Inf)
3843
end
3944
end
4045

@@ -268,6 +273,10 @@ end
268273
@test zeta(-6+13im) conj(zeta(-6-13im)) 133.4764526350263089084083707864441932569167866714712267139316498-54.15465727586582149098585229287107039070546786014930791081909684im
269274
@test 1e-12 > relerr(zeta(-2+13im, 3), 2.3621038290867825837364823054-3.9497600485207119519185591345im)
270275
@test 1e-12 > relerr(zeta(-2-13im, 3), 2.3621038290867825837364823054+3.9497600485207119519185591345im)
276+
277+
# issue #450
278+
@test SpecialFunctions.cotderiv(0, 2.0) == Inf
279+
@test_throws DomainError SpecialFunctions.cotderiv(-1, 2.0)
271280
end
272281

273282
@testset "logabsbinomial" begin

0 commit comments

Comments
 (0)