Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaMath / SpecialFunctions.jl / 814

25 Sep 2020 - 15:06 coverage: 85.701% (+0.05%) from 85.647%
814

Pull #242

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Merge 225521a95 into 1bb0913fc
Pull Request #242: Adds Owen's T function

32 of 33 new or added lines in 1 file covered. (96.97%)

62 existing lines in 10 files now uncovered.

3644 of 4252 relevant lines covered (85.7%)

2014.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.83
/src/gamma.jl
1
# This file contains code that was formerly a part of Julia. License is MIT: http://julialang.org/license
2

3
using Base.MPFR: ROUNDING_MODE, big_ln2
4

5
const ComplexOrReal{T} = Union{T,Complex{T}}
6

7
# Bernoulli numbers B_{2k}, using tabulated numerators and denominators from
8
# the online encyclopedia of integer sequences.  (They actually have data
9
# up to k=249, but we stop here at k=20.)  Used for generating the polygamma
10
# (Stirling series) coefficients below.
11
#   const A000367 = map(BigInt, split("1,1,-1,1,-1,5,-691,7,-3617,43867,-174611,854513,-236364091,8553103,-23749461029,8615841276005,-7709321041217,2577687858367,-26315271553053477373,2929993913841559,-261082718496449122051", ","))
12
#   const A002445 = [1,6,30,42,30,66,2730,6,510,798,330,138,2730,6,870,14322,510,6,1919190,6,13530]
13
#   const bernoulli = A000367 .// A002445 # even-index Bernoulli numbers
14

15
"""
16
    digamma(x)
17

18
Compute the digamma function of `x` (the logarithmic derivative of `gamma(x)`).
19
"""
20
function digamma(z::ComplexOrReal{Float64})
21
    # Based on eq. (12), without looking at the accompanying source
22
    # code, of: K. S. Kölbig, "Programs for computing the logarithm of
23
    # the gamma function, and the digamma function, for complex
24
    # argument," Computer Phys. Commun.  vol. 4, pp. 221–226 (1972).
25
    x = real(z)
1,792×
26
    if x <= 0 # reflection formula
1,792×
27
        ψ = -π * cot(π*z)
264×
28
        z = 1 - z
264×
29
        x = real(z)
264×
30
    else
31
        ψ = zero(z)
1,528×
32
    end
33
    if x < 7
1,792×
34
        # shift using recurrence formula
35
        n = 7 - floor(Int,x)
612×
36
        for ν = 1:n-1
1,152×
37
            ψ -= inv(z + ν)
4,452×
38
        end
39
        ψ -= inv(z)
612×
40
        z += n
612×
41
    end
42
    t = inv(z)
1,792×
43
    ψ += log(z) - 0.5*t
1,792×
44
    t *= t # 1/z^2
1,792×
45
    # the coefficients here are Float64(bernoulli[2:9] .// (2*(1:8)))
46
    ψ -= t * @evalpoly(t,0.08333333333333333,-0.008333333333333333,0.003968253968253968,-0.004166666666666667,0.007575757575757576,-0.021092796092796094,0.08333333333333333,-0.4432598039215686)
1,792×
47
end
48

49
function digamma(x::BigFloat)
50
    z = BigFloat()
4×
51
    ccall((:mpfr_digamma, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, ROUNDING_MODE[])
4×
52
    return z
4×
53
end
54

55
"""
56
    trigamma(x)
57

58
Compute the trigamma function of `x` (the logarithmic second derivative of `gamma(x)`).
59
"""
60
function trigamma(z::ComplexOrReal{Float64})
61
    # via the derivative of the Kölbig digamma formulation
62
    x = real(z)
276×
63
    if x <= 0 # reflection formula
276×
64
        return (π * csc(π*z))^2 - trigamma(1 - z)
8×
65
    end
66
    ψ = zero(z)
268×
67
    if x < 8
268×
68
        # shift using recurrence formula
69
        n = 8 - floor(Int,x)
232×
70
        ψ += inv(z)^2
232×
71
        for ν = 1:n-1
440×
72
            ψ += inv(z + ν)^2
2,312×
73
        end
74
        z += n
232×
75
    end
76
    t = inv(z)
268×
77
    w = t * t # 1/z^2
268×
78
    ψ += t + 0.5*w
268×
79
    # the coefficients here are Float64(bernoulli[2:9])
80
    ψ += t*w * @evalpoly(w,0.16666666666666666,-0.03333333333333333,0.023809523809523808,-0.03333333333333333,0.07575757575757576,-0.2531135531135531,1.1666666666666667,-7.092156862745098)
268×
81
end
82

83
signflip(m::Number, z) = (-1+0im)^m * z
!
84
signflip(m::Integer, z) = iseven(m) ? z : -z
120×
85

86
# (-1)^m d^m/dz^m cot(z) = p_m(cot z), where p_m is a polynomial
87
# that satisfies the recurrence p_{m+1}(x) = p_m′(x) * (1 + x^2).
88
# Note that p_m(x) has only even powers of x if m is odd, and
89
# only odd powers of x if m is even.  Therefore, we write p_m(x)
90
# as p_m(x) = q_m(x^2) m! for m odd and p_m(x) = x q_m(x^2) m! if m is even.
91
# Hence the polynomials q_m(y) satisfy the recurrence:
92
#     m odd:  q_{m+1}(y) = 2 q_m′(y) * (1+y) / (m+1)
93
#    m even:  q_{m+1}(y) = [q_m(y) + 2 y q_m′(y)] * (1+y) / (m+1)
94
# This function computes the coefficients of the polynomial q_m(y),
95
# returning an array of the coefficients of 1, y, y^2, ...,
96
function cotderiv_q(m::Int)
97
    m < 0 && throw(DomainError(m, "`m` must be nonnegative."))
20,200×
98
    m == 0 && return [1.0]
20,200×
99
    m == 1 && return [1.0, 1.0]
20,200×
100
    q₋ = cotderiv_q(m-1)
19,800×
101
    d = length(q₋) - 1 # degree of q₋
19,800×
102
    if isodd(m-1)
19,800×
103
        q = Vector{Float64}(undef, length(q₋))
10,000×
104
        q[end] = d * q₋[end] * 2/m
10,000×
105
        for i = 1:length(q)-1
20,000×
106
            q[i] = ((i-1)*q₋[i] + i*q₋[i+1]) * 2/m
333,400×
107
        end
108
    else # iseven(m-1)
109
        q = Vector{Float64}(undef, length(q₋) + 1)
9,800×
110
        q[1] = q₋[1] / m
9,800×
111
        q[end] = (1 + 2d) * q₋[end] / m
9,800×
112
        for i = 2:length(q)-1
19,600×
113
            q[i] = ((1 + 2(i-1))*q₋[i] + (1 + 2(i-2))*q₋[i-1]) / m
166,600×
114
        end
115
    end
116
    return q
19,800×
117
end
118

119
# precompute a table of cot derivative polynomials
120
const cotderiv_Q = [cotderiv_q(m) for m in 1:100]
121

122
# Evaluate (-1)^m d^m/dz^m [π cot(πz)] / m!.  If m is small, we
123
# use the explicit derivative formula (a polynomial in cot(πz));
124
# if m is large, we use the derivative of Euler's harmonic series:
125
#          π cot(πz) = ∑ inv(z + n)
126
function cotderiv(m::Integer, z)
127
    isinf(imag(z)) && return zero(z)
20×
128
    if m <= 0
16×
129
        m == 0 && return π * cot(π*z)
!
130
        throw(DomainError(m, "`m` must be nonnegative."))
!
131
    end
132
    if m <= length(cotderiv_Q)
16×
133
        q = cotderiv_Q[m]
12×
134
        x = cot(π*z)
12×
135
        y = x*x
12×
136
        s = q[1] + q[2] * y
12×
137
        t = y
12×
138
        # evaluate q(y) using Horner (TODO: Knuth for complex z?)
139
        for i = 3:length(q)
24×
140
            t *= y
12×
141
            s += q[i] * t
12×
142
        end
143
        return π^(m+1) * (isodd(m) ? s : x*s)
12×
144
    else # m is large, series derivative should converge quickly
145
        p = m+1
4×
146
        z -= round(real(z))
4×
147
        s = inv(z^p)
4×
148
        n = 1
4×
149
        sₒ = zero(s)
4×
150
        while s != sₒ
8×
151
            sₒ = s
4×
152
            a = (z+n)^p
4×
153
            b = (z-n)^p
4×
154
            s += (a + b) / (a * b)
4×
155
            n += 1
4×
156
        end
157
        return s
4×
158
    end
159
end
160

161
# Helper macro for polygamma(m, z):
162
#   Evaluate p[1]*c[1] + x*p[2]*c[2] + x^2*p[3]*c[3] + ...
163
#   where c[1] = m + 1
164
#         c[k] = c[k-1] * (2k+m-1)*(2k+m-2) / ((2k-1)*(2k-2)) = c[k-1] * d[k]
165
#         i.e. d[k] = c[k]/c[k-1] = (2k+m-1)*(2k+m-2) / ((2k-1)*(2k-2))
166
#   by a modified version of Horner's rule:
167
#      c[1] * (p[1] + d[2]*x * (p[2] + d[3]*x * (p[3] + ...))).
168
# The entries of p must be literal constants and there must be > 1 of them.
169
macro pg_horner(x, m, p...)
170
    k = length(p)
8×
171
    me = esc(m)
8×
172
    xe = esc(x)
8×
173
    ex = :(($me + $(2k-1)) * ($me + $(2k-2)) * $(p[end]/((2k-1)*(2k-2))))
8×
174
    for k = length(p)-1:-1:2
8×
175
        cdiv = 1 / ((2k-1)*(2k-2))
56×
176
        ex = :(($cdiv * ($me + $(2k-1)) * ($me + $(2k-2))) *
56×
177
               ($(p[k]) + $xe * $ex))
178
    end
179
    :(($me + 1) * ($(p[1]) + $xe * $ex))
8×
180
end
181

182
# compute oftype(x, y)^p efficiently, choosing the correct branch cut
183
pow_oftype(x, y, p) = oftype(x, y)^p
3,416×
184
pow_oftype(x::Complex, y::Real, p::Complex) = oftype(x, y^p)
620×
UNCOV
185
function pow_oftype(x::Complex, y::Real, p::Real)
!
186
    if p >= 0
!
187
        # note: this will never be called for y < 0,
188
        # which would throw an error for non-integer p here
189
        return oftype(x, y^p)
!
190
    else
191
        yp = y^-p # use real power for efficiency
!
192
        return oftype(x, Complex(yp, -zero(yp))) # get correct sign of zero!
!
193
    end
194
end
195

196
# Generalized zeta function, which is related to polygamma
197
# (at least for integer m > 0 and real(z) > 0) by:
198
#    polygamma(m, z) = (-1)^(m+1) * gamma(m+1) * zeta(m+1, z).
199
# Our algorithm for the polygamma is just the m-th derivative
200
# of our digamma approximation, and this derivative process yields
201
# a function of the form
202
#          (-1)^(m) * gamma(m+1) * (something)
203
# So identifying the (something) with the -zeta function, we get
204
# the zeta function for free and might as well export it, especially
205
# since this is a common generalization of the Riemann zeta function
206
# (which Julia already exports).   Note that this geneneralization
207
# is equivalent to Mathematica's Zeta[s,z], and is equivalent to the
208
# Hurwitz zeta function for real(z) > 0.
209

210
"""
211
    zeta(s, z)
212

213
Generalized zeta function defined by
214
```math
215
\\zeta(s, z)=\\sum_{k=0}^\\infty \\frac{1}{((k+z)^2)^{s/2}},
216
```
217
where any term with ``k+z=0`` is excluded.  For ``\\Re z > 0``,
218
this definition is equivalent to the Hurwitz zeta function
219
``\\sum_{k=0}^\\infty (k+z)^{-s}``.
220

221
The Riemann zeta function is recovered as ``\\zeta(s)=\\zeta(s,1)``.
222

223
External links: [Riemann zeta function](https://en.wikipedia.org/wiki/Riemann_zeta_function), [Hurwitz zeta function](https://en.wikipedia.org/wiki/Hurwitz_zeta_function)
224
"""
225
function zeta(s::ComplexOrReal{Float64}, z::ComplexOrReal{Float64})
226
    ζ = zero(promote_type(typeof(s), typeof(z)))
312×
227

228
    (z == 1 || z == 0) && return oftype(ζ, zeta(s))
604×
229
    s == 2 && return oftype(ζ, trigamma(z))
300×
230

231
    x = real(z)
236×
232

233
    # annoying s = Inf or NaN cases:
234
    if !isfinite(s)
236×
235
        (isnan(s) || isnan(z)) && return (s*z)^2 # type-stable NaN+Nan*im
8×
236
        if real(s) == Inf
4×
237
            z == 1 && return one(ζ)
4×
238
            if x > 1 || (x >= 0.5 ? abs(z) > 1 : abs(z - round(x)) > 1)
4×
239
                return zero(ζ) # distance to poles is > 1
4×
240
            end
241
            x > 0 && imag(z) == 0 && imag(s) == 0 && return oftype(ζ, Inf)
!
242
        end
243
        throw(DomainError(s, "`s` must be finite."))  # nothing clever to return
!
244
    end
245
    if isnan(x)
232×
246
        if imag(z) == 0 && imag(s) == 0
!
247
            return oftype(ζ, x)
!
248
        else
249
            return oftype(ζ, Complex(x,x))
!
250
        end
251
    end
252

253
    m = s - 1
232×
254

255
    # Algorithm is just the m-th derivative of digamma formula above,
256
    # with a modified cutoff of the final asymptotic expansion.
257

258
    # Note: we multiply by -(-1)^m m! in polygamma below, so this factor is
259
    #       pulled out of all of our derivatives.
260

261
    cutoff = 7 + real(m) + abs(imag(m)) # TODO: this cutoff is too conservative?
232×
262
    if x < cutoff
232×
263
        # shift using recurrence formula
264
        xf = floor(x)
204×
265
        nx = Int(xf)
204×
266
        n = ceil(Int, cutoff - nx)
204×
267
        minus_s = -s
204×
268
        if nx < 0 # x < 0
204×
269
            # need to use (-z)^(-s) recurrence to be correct for real z < 0
270
            # [the general form of the recurrence term is (z^2)^(-s/2)]
271
            minus_z = -z
68×
272
            ζ += pow_oftype(ζ, minus_z, minus_s) # ν = 0 term
68×
273
            if xf != z
88×
274
                ζ += pow_oftype(ζ, z - nx, minus_s)
56×
275
                # real(z - nx) > 0, so use correct branch cut
276
                # otherwise, if xf==z, then the definition skips this term
277
            end
278
            # do loop in different order, depending on the sign of s,
279
            # so that we are looping from largest to smallest summands and
280
            # can halt the loop early if possible; see issue #15946
281
            # FIXME: still slow for small m, large Im(z)
282
            if real(s) > 0
68×
283
                for ν in -nx-1:-1:1
80×
284
                    ζₒ= ζ
1,900×
285
                    ζ += pow_oftype(ζ, minus_z - ν, minus_s)
1,900×
286
                    ζ == ζₒ && break # prevent long loop for large -x > 0
3,796×
287
                end
288
            else
289
                for ν in 1:-nx-1
56×
290
                    ζₒ= ζ
184×
291
                    ζ += pow_oftype(ζ, minus_z - ν, minus_s)
184×
292
                    ζ == ζₒ && break # prevent long loop for large -x > 0
252×
293
                end
294
            end
295
        else # x ≥ 0 && z != 0
296
            ζ += pow_oftype(ζ, z, minus_s)
136×
297
        end
298
        # loop order depends on sign of s, as above
299
        if real(s) > 0
204×
300
            for ν in max(1,1-nx):n-1
348×
301
                ζₒ= ζ
1,636×
302
                ζ += pow_oftype(ζ, z + ν, minus_s)
1,636×
303
                ζ == ζₒ && break # prevent long loop for large m
3,244×
304
            end
305
        else
306
            for ν in n-1:-1:max(1,1-nx)
56×
307
                ζₒ= ζ
56×
308
                ζ += pow_oftype(ζ, z + ν, minus_s)
56×
309
                ζ == ζₒ && break # prevent long loop for large m
56×
310
            end
311
        end
312
        z += n
204×
313
    end
314

315
    t = inv(z)
232×
316
    w = isa(t, Real) ? conj(oftype(ζ, t))^m : oftype(ζ, t)^m
232×
317
    ζ += w * (inv(m) + 0.5*t)
232×
318

319
    t *= t # 1/z^2
232×
320
    ζ += w*t * @pg_horner(t,m,0.08333333333333333,-0.008333333333333333,0.003968253968253968,-0.004166666666666667,0.007575757575757576,-0.021092796092796094,0.08333333333333333,-0.4432598039215686,3.0539543302701198)
232×
321

322
    return ζ
232×
323
end
324

325
"""
326
    polygamma(m, x)
327

328
Compute the polygamma function of order `m` of argument `x` (the `(m+1)`th derivative of the
329
logarithm of `gamma(x)`)
330

331
External links: [Wikipedia](https://en.wikipedia.org/wiki/Polygamma_function)
332

333
See also: [`gamma(z)`](@ref SpecialFunctions.gamma)
334
"""
335
function polygamma(m::Integer, z::ComplexOrReal{Float64})
336
    m == 0 && return digamma(z)
84×
337
    m == 1 && return trigamma(z)
84×
338

339
    # In principle, we could support non-integer m here, but the
340
    # extension to complex m seems to be non-unique, the obvious
341
    # extension (just plugging in a complex m below) does not seem to
342
    # be the one used by Mathematica or Maple, and sources do not
343
    # agree on what the "right" extension is (e.g. Mathematica & Maple
344
    # disagree).   So, at least for now, we require integer m.
345

346
    # real(m) < 0 is valid, but I don't think our asymptotic expansion
347
    # here works in this case.  m < 0 polygamma is called a
348
    # "negapolygamma" function in the literature, and there are
349
    # multiple possible definitions arising from different integration
350
    # constants. We throw a DomainError since the definition is unclear.
351
    real(m) < 0 && throw(DomainError(m, "`real(m)` must be nonnegative, since the definition in this case is ambiguous."))
84×
352

353
    s = Float64(m+1)
88×
354
    # It is safe to convert any integer (including `BigInt`) to a float here
355
    # as underflow occurs before precision issues.
356
    if real(z) <= 0 # reflection formula
84×
357
        (zeta(s, 1-z) + signflip(m, cotderiv(m,z))) * (-gamma(s))
20×
358
    else
359
        signflip(m, zeta(s,z) * (-gamma(s)))
64×
360
    end
361
end
362

363
"""
364
    invdigamma(x)
365

366
Compute the inverse [`digamma`](@ref) function of `x`.
367
"""
368
function invdigamma(y::Float64)
369
    # Implementation of fixed point algorithm described in
370
    # "Estimating a Dirichlet distribution" by Thomas P. Minka, 2000
371

372
    # Closed form initial estimates
373
    if y >= -2.22
48×
374
        x_old = exp(y) + 0.5
24×
375
        x_new = x_old
24×
376
    else
377
        x_old = -1.0 / (y - digamma(1.0))
120×
378
        x_new = x_old
24×
379
    end
380

381
    # Fixed point algorithm
382
    delta = Inf
48×
383
    iteration = 0
48×
384
    while delta > 1e-12 && iteration < 25
208×
385
        iteration += 1
160×
386
        x_new = x_old - (digamma(x_old) - y) / trigamma(x_old)
160×
387
        delta = abs(x_new - x_old)
160×
388
        x_old = x_new
160×
389
    end
390

391
    return x_new
48×
392
end
393

394
"""
395
    zeta(s)
396

397
Riemann zeta function
398

399
```math
400
\\zeta(s)=\\sum_{n=1}^\\infty \\frac{1}{n^s}\\quad\\text{for}\\quad s\\in\\mathbb{C}.
401
```
402

403
External links: [Wikipedia](https://en.wikipedia.org/wiki/Riemann_zeta_function)
404
"""
405
function zeta(s::ComplexOrReal{Float64})
406
    # Riemann zeta function; algorithm is based on specializing the Hurwitz
407
    # zeta function above for z==1.
408

409
    # blows up to ±Inf, but get correct sign of imaginary zero
410
    s == 1 && return NaN + zero(s) * imag(s)
312×
411

412
    if !isfinite(s) # annoying NaN and Inf cases
208×
413
        isnan(s) && return imag(s) == 0 ? s : s*s
20×
414
        if isfinite(imag(s))
12×
415
            real(s) > 0 && return 1.0 - zero(s)*imag(s)
8×
416
            imag(s) == 0 && return NaN + zero(s)
4×
417
        end
418
        return NaN*zero(s) # NaN + NaN*im
4×
419
    elseif real(s) < 0.5
188×
420
        absim = abs(imag(s))
56×
421
        if abs(real(s)) + absim < 1e-3 # Taylor series for small |s|
56×
422
            return @evalpoly(s, -0.5,
8×
423
                             -0.918938533204672741780329736405617639861,
424
                             -1.0031782279542924256050500133649802190,
425
                             -1.00078519447704240796017680222772921424,
426
                             -0.9998792995005711649578008136558752359121)
427
        end
428
        if absim > 12 # amplitude of sinpi(s/2) ≈ exp(imag(s)*π/2)
48×
429
            # avoid overflow/underflow (issue #128)
430
            lg = loggamma(1 - s)
28×
431
            ln2pi = 1.83787706640934548356 # log(2pi) to double precision
28×
432
            rehalf = real(s)*0.5
28×
433
            return zeta(1 - s) * exp(lg + absim*(pi/2) + s*ln2pi) * (0.5/π) *
28×
434
                Complex(sinpi(rehalf), copysign(cospi(rehalf), imag(s)))
435
        else
436
            return zeta(1 - s) * gamma(1 - s) * sinpi(s*0.5) * (2π)^s / π
20×
437
        end
438
    end
439

440
    m = s - 1
132×
441

442
    # shift using recurrence formula:
443
    #   n is a semi-empirical cutoff for the Stirling series, based
444
    #   on the error term ~ (|m|/n)^18 / n^real(m)
445
    # FIXME: slow for large imag(s) and small real(s)
446
    n = ceil(Int,6 + 0.7*abs(imag(s-1))^inv(1 + real(m)*0.05))
132×
447
    ζ = one(s)
132×
448
    for ν = 2:n
264×
449
        ζₒ= ζ
16,292×
450
        ζ += inv(ν)^s
16,292×
451
        ζ == ζₒ && break # prevent long loop for large m
32,584×
452
    end
453
    z = 1 + n
132×
454
    t = inv(z)
132×
455
    w = t^m
132×
456
    ζ += w * (inv(m) + 0.5*t)
132×
457

458
    t *= t # 1/z^2
132×
459
    ζ += w*t * @pg_horner(t,m,0.08333333333333333,-0.008333333333333333,0.003968253968253968,-0.004166666666666667,0.007575757575757576,-0.021092796092796094,0.08333333333333333,-0.4432598039215686,3.0539543302701198)
132×
460

461
    return ζ
132×
462
end
463

464
function zeta(x::BigFloat)
465
    z = BigFloat()
12×
466
    ccall((:mpfr_zeta, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, ROUNDING_MODE[])
12×
467
    return z
12×
468
end
469

470
"""
471
    eta(x)
472

473
Dirichlet eta function ``\\eta(s) = \\sum^\\infty_{n=1}(-1)^{n-1}/n^{s}``.
474
"""
475
function eta(z::ComplexOrReal{Float64})
476
    δz = 1 - z
48×
477
    if abs(real(δz)) + abs(imag(δz)) < 7e-3 # Taylor expand around z==1
48×
478
        return 0.6931471805599453094172321214581765 *
16×
479
               @evalpoly(δz,
480
                         1.0,
481
                         -0.23064207462156020589789602935331414700440,
482
                         -0.047156357547388879740146103148112380421254,
483
                         -0.002263576552598880778433550956278702759143568,
484
                         0.001081837223249910136105931217561387128141157)
485
    else
486
        return -zeta(z) * expm1(0.6931471805599453094172321214581765*δz)
32×
487
    end
488
end
489

490
function eta(x::BigFloat)
491
    x == 1 && return big_ln2()
21×
492
    return -zeta(x) * expm1(big_ln2()*(1-x))
8×
493
end
494

495
# Converting types that we can convert, and not ones we can not
496
# Float16, and Float32 and their Complex equivalents can be converted to Float64
497
# and results converted back.
498
# Otherwise, we need to make things use their own `float` converting methods
499
# and in those cases, we do not convert back either as we assume
500
# they also implement their own versions of the functions, with the correct return types.
501
# This is the case for BitIntegers (which become `Float64` when `float`ed).
502
# Otherwise, if they do not implement their version of the functions we
503
# manually throw a `MethodError`.
504
# This case occurs, when calling `float` on a type does not change its type,
505
# as it is already a `float`, and would have hit own method, if one had existed.
506

507

508
# If we really cared about single precision, we could make a faster
509
# Float32 version by truncating the Stirling series at a smaller cutoff.
510
# and if we really cared about half precision, we could make a faster
511
# Float16 version, by using a precomputed table look-up.
512

513

514
for T in (Float16, Float32, Float64)
515
    @eval f64(x::Complex{$T}) = Complex{Float64}(x)
20×
516
    @eval f64(x::$T) = Float64(x)
212×
517
end
518

519

520
for f in (:digamma, :trigamma, :zeta, :eta, :invdigamma)
521
    @eval begin
522
        function $f(z::Union{ComplexOrReal{Float16}, ComplexOrReal{Float32}})
523
            oftype(z, $f(f64(z)))
168×
524
        end
525

526
        function $f(z::Number)
527
            x = float(z)
112×
528
            typeof(x) === typeof(z) && throw(MethodError($f, (z,)))
112×
529
            # There is nothing to fallback to, as this didn't change the argument types
530
            $f(x)
80×
531
        end
532
    end
533
end
534

535

536
for T1 in (Float16, Float32, Float64), T2 in (Float16, Float32, Float64)
537
    (T1 == T2 == Float64) && continue # Avoid redefining base definition
538

539
    @eval function zeta(s::ComplexOrReal{$T1}, z::ComplexOrReal{$T2})
540
        ζ = zeta(f64(s), f64(z))
24×
541
        convert(promote_type(typeof(s), typeof(z)),  ζ)
24×
542
    end
543
end
544

545

546
function zeta(s::Number, z::Number)
547
    t = float(s)
107×
548
    x = float(z)
107×
549
    if typeof(t) === typeof(s) && typeof(x) === typeof(z)
107×
550
        # There is nothing to fallback to, since this didn't work
551
        throw(MethodError(zeta,(s,z)))
16×
552
    end
553
    zeta(t, x)
91×
554
end
555

556

557
function polygamma(m::Integer, z::Union{ComplexOrReal{Float16}, ComplexOrReal{Float32}})
558
    oftype(z, polygamma(m, f64(z)))
8×
559
end
560

561

562
function polygamma(m::Integer, z::Number)
563
    x = float(z)
15×
564
    typeof(x) === typeof(z) && throw(MethodError(polygamma, (m,z)))
15×
565
    # There is nothing to fallback to, since this didn't work
566
    polygamma(m, x)
15×
567
end
568

569
export gamma, loggamma, logabsgamma, beta, logbeta, logabsbeta, logfactorial, logabsbinomial
570

571
## from base/special/gamma.jl
572

573
gamma(x::Float64)       = nan_dom_err(ccall((:tgamma, libm), Float64, (Float64,), x), x)
3,366×
574
gamma(x::Float32)       = nan_dom_err(ccall((:tgammaf, libm), Float32, (Float32,), x), x)
16×
575
gamma(x::Float16)       = Float16(gamma(Float32(x)))
8×
576
gamma(x::Real)          = gamma(float(x))
32×
577
gamma(x::AbstractFloat) = throw(MethodError(gamma, x))
4×
578

579
function gamma(x::BigFloat)
580
    isnan(x) && return x
36×
581
    z = BigFloat()
36×
582
    ccall((:mpfr_gamma, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, ROUNDING_MODE[])
36×
583
    isnan(z) && throw(DomainError(x, "NaN result for non-NaN input."))
36×
584
    return z
36×
585
end
586

587
@doc raw"""
588
    gamma(z)
589

590
Compute the gamma function for complex ``z``, defined by
591

592
```math
593
\Gamma(z)
594
:=
595
\begin{cases}
596
    n!
597
    & \text{for} \quad z = n+1 \;, n = 0,1,2,\dots
598
    \\
599
    \int_0^\infty t^{z-1} {\mathrm e}^{-t} \, {\mathrm d}t
600
    & \text{for} \quad \Re(z) > 0
601
\end{cases}
602
```
603
and by analytic continuation in the whole complex plane.
604

605
External links:
606
[DLMF](https://dlmf.nist.gov/5.2.1),
607
[Wikipedia](https://en.wikipedia.org/wiki/Gamma_function).
608

609
See also: [`loggamma(z)`](@ref SpecialFunctions.loggamma).
610

611
# Implementation by
612
- `Float`: C standard math library
613
    [libm](https://en.wikipedia.org/wiki/C_mathematical_functions#libm).
614
- `Complex`: by `exp(loggamma(z))`.
615
- `BigFloat`: C library for multiple-precision floating-point [MPFR](https://www.mpfr.org/)
616
"""
617
gamma
618

619
function logabsgamma(x::Float64)
620
    signp = Ref{Int32}()
11,628×
621
    y = ccall((:lgamma_r,libm),  Float64, (Float64, Ptr{Int32}), x, signp)
11,628×
622
    return y, signp[]
11,628×
623
end
624
function logabsgamma(x::Float32)
625
    signp = Ref{Int32}()
36×
626
    y = ccall((:lgammaf_r,libm),  Float32, (Float32, Ptr{Int32}), x, signp)
36×
627
    return y, signp[]
36×
628
end
629
logabsgamma(x::Real) = logabsgamma(float(x))
!
630
logabsgamma(x::Float16) = Float16.(logabsgamma(Float32(x)))
8×
631
logabsgamma(x::Integer) = logabsgamma(float(x))
2,508×
632
logabsgamma(x::AbstractFloat) = throw(MethodError(logabsgamma, x))
8×
633

634

635
"""
636
    logfactorial(x)
637

638
Compute the logarithmic factorial of a nonnegative integer `x`.
639
Equivalent to [`loggamma`](@ref) of `x + 1`, but `loggamma` extends this function
640
to non-integer `x`.
641
"""
642
logfactorial(x::Integer) = x < 0 ? throw(DomainError(x, "`x` must be non-negative.")) : loggamma(x + oneunit(x))
16×
643

644
"""
645
    logabsgamma(x)
646

647
Compute the logarithm of absolute value of [`gamma`](@ref) for
648
[`Real`](@ref) `x`and returns a tuple `(log(abs(gamma(x))), sign(gamma(x)))`.
649

650
See also [`loggamma`](@ref).
651
"""
652
function logabsgamma end
653

654
"""
655
    loggamma(x)
656

657
Computes the logarithm of [`gamma`](@ref) for given `x`. If `x` is a `Real`, then it
658
throws a `DomainError` if `gamma(x)` is negative.
659

660
See also [`logabsgamma`](@ref).
661
"""
662
function loggamma end
663

664
function loggamma(x::Real)
665
    (y, s) = logabsgamma(x)
3,524×
666
    s < 0.0 && throw(DomainError(x, "`gamma(x)` must be non-negative"))
3,520×
667
    return y
3,516×
668
end
669
loggamma(x::Number) = loggamma(float(x))
!
670

671
# asymptotic series for log(gamma(z)), valid for sufficiently large real(z) or |imag(z)|
672
function loggamma_asymptotic(z::Complex{Float64})
673
    zinv = inv(z)
200×
674
    t = zinv*zinv
200×
675
    # coefficients are bernoulli[2:n+1] .// (2*(1:n).*(2*(1:n) - 1))
676
    return (z-0.5)*log(z) - z + 9.1893853320467274178032927e-01 + # <-- log(2pi)/2
200×
677
       zinv*@evalpoly(t, 8.3333333333333333333333368e-02,-2.7777777777777777777777776e-03,
678
                         7.9365079365079365079365075e-04,-5.9523809523809523809523806e-04,
679
                         8.4175084175084175084175104e-04,-1.9175269175269175269175262e-03,
680
                         6.4102564102564102564102561e-03,-2.9550653594771241830065352e-02)
681
end
682

683
# Compute the logΓ(z) function using a combination of the asymptotic series,
684
# the Taylor series around z=1 and z=2, the reflection formula, and the shift formula.
685
# Many details of these techniques are discussed in D. E. G. Hare,
686
# "Computing the principal branch of log-Gamma," J. Algorithms 25, pp. 221-236 (1997),
687
# and similar techniques are used (in a somewhat different way) by the
688
# SciPy loggamma function.  The key identities are also described
689
# at http://functions.wolfram.com/GammaBetaErf/LogGamma/
690
function loggamma(z::Complex{Float64})
691
    x = real(z)
316×
692
    y = imag(z)
316×
693
    yabs = abs(y)
316×
694
    if !isfinite(x) || !isfinite(y) # Inf or NaN
600×
695
        if isinf(x) && isfinite(y)
44×
696
            return Complex(x, x > 0 ? (y == 0 ? y : copysign(Inf, y)) : copysign(Inf, -y))
24×
697
        elseif isfinite(x) && isinf(y)
20×
698
            return Complex(-Inf, y)
8×
699
        else
700
            return Complex(NaN, NaN)
12×
701
        end
702
    elseif x > 7 || yabs > 7 # use the Stirling asymptotic series for sufficiently large x or |y|
504×
703
        return loggamma_asymptotic(z)
88×
704
    elseif x < 0.1 # use reflection formula to transform to x > 0
184×
705
        if x == 0 && y == 0 # return Inf with the correct imaginary part for z == 0
40×
706
            return Complex(Inf, signbit(x) ? copysign(oftype(x, pi), -y) : -y)
!
707
        end
708
        # the 2pi * floor(...) stuff is to choose the correct branch cut for log(sinpi(z))
709
        return Complex(1.1447298858494001741434262, # log(pi)
40×
710
                       copysign(6.2831853071795864769252842, y) # 2pi
711
                       * floor(0.5*x+0.25)) -
712
               log(sinpi(z)) - loggamma(1-z)
713
    elseif abs(x - 1) + yabs < 0.1
144×
714
        # taylor series around zero at z=1
715
        # ... coefficients are [-eulergamma; [(-1)^k * zeta(k)/k for k in 2:15]]
716
        w = Complex(x - 1, y)
20×
717
        return w * @evalpoly(w, -5.7721566490153286060651188e-01,8.2246703342411321823620794e-01,
20×
718
                                -4.0068563438653142846657956e-01,2.705808084277845478790009e-01,
719
                                -2.0738555102867398526627303e-01,1.6955717699740818995241986e-01,
720
                                -1.4404989676884611811997107e-01,1.2550966952474304242233559e-01,
721
                                -1.1133426586956469049087244e-01,1.000994575127818085337147e-01,
722
                                -9.0954017145829042232609344e-02,8.3353840546109004024886499e-02,
723
                                -7.6932516411352191472827157e-02,7.1432946295361336059232779e-02,
724
                                -6.6668705882420468032903454e-02)
725
    elseif abs(x - 2) + yabs < 0.1
124×
726
        # taylor series around zero at z=2
727
        # ... coefficients are [1-eulergamma; [(-1)^k * (zeta(k)-1)/k for k in 2:12]]
728
        w = Complex(x - 2, y)
12×
729
        return w * @evalpoly(w, 4.2278433509846713939348812e-01,3.2246703342411321823620794e-01,
12×
730
                               -6.7352301053198095133246196e-02,2.0580808427784547879000897e-02,
731
                               -7.3855510286739852662729527e-03,2.8905103307415232857531201e-03,
732
                               -1.1927539117032609771139825e-03,5.0966952474304242233558822e-04,
733
                               -2.2315475845357937976132853e-04,9.9457512781808533714662972e-05,
734
                               -4.4926236738133141700224489e-05,2.0507212775670691553131246e-05)
735
    end
736
    # use recurrence relation loggamma(z) = loggamma(z+1) - log(z) to shift to x > 7 for asymptotic series
737
    shiftprod = Complex(x,yabs)
112×
738
    x += 1
112×
739
    sb = false # == signbit(imag(shiftprod)) == signbit(yabs)
112×
740
    # To use log(product of shifts) rather than sum(logs of shifts),
741
    # we need to keep track of the number of + to - sign flips in
742
    # imag(shiftprod), as described in Hare (1997), proposition 2.2.
743
    signflips = 0
112×
744
    while x <= 7
532×
745
        shiftprod *= Complex(x,yabs)
420×
746
        sb′ = signbit(imag(shiftprod))
420×
747
        signflips += sb′ & (sb′ != sb)
420×
748
        sb = sb′
420×
749
        x += 1
420×
750
    end
751
    shift = log(shiftprod)
112×
752
    if signbit(y) # if y is negative, conjugate the shift
112×
753
        shift = Complex(real(shift), signflips*-6.2831853071795864769252842 - imag(shift))
28×
754
    else
755
        shift = Complex(real(shift), imag(shift) + signflips*6.2831853071795864769252842)
84×
756
    end
757
    return loggamma_asymptotic(Complex(x,y)) - shift
112×
758
end
759
loggamma(z::Complex{T}) where {T<:Union{Integer,Rational}} = loggamma(float(z))
52×
760
loggamma(z::Complex{T}) where {T<:Union{Float32,Float16}} = Complex{T}(loggamma(Complex{Float64}(z)))
!
761

762
gamma(z::Complex) = exp(loggamma(z))
52×
763

764
"""
765
    beta(x, y)
766

767
Euler integral of the first kind ``\\operatorname{B}(x,y) = \\Gamma(x)\\Gamma(y)/\\Gamma(x+y)``.
768
"""
769
function beta end
770

771
function beta(a::Real, b::Real)
772
    #Special case for negative integer argument
773
    if a <= 0.0
52×
774
        if isinteger(a) && 1-a-b > 0
8×
775
            sgn = isinteger(b/2) ? 1 : -1
4×
776
            return sgn* beta(1-a-b,b)
4×
777
        end
778
    end
779
    if b <= 0.0
48×
780
        if isinteger(b) && 1-a-b > 0
!
781
            sgn = isinteger(a/2) ? 1 : -1
!
782
            return sgn* beta(1-a-b,a)
!
783
        end
784
    end
785
    if a < b
48×
786
        a,b = b,a
32×
787
    end
788
    #asymptotic expansion for log(B(a,b)) for |a| >> |b|
789
    if abs(a) > 1e5*abs(b) && abs(a) > 1e5
48×
790
        return exp(loggammadiv(b,a) + loggamma(b))
4×
791
    end
792
    ya, sa = logabsgamma(a)
48×
793
    yb, sb = logabsgamma(b)
44×
794
    yab, sab = logabsgamma(a+b)
44×
795
    return exp(ya + yb - yab) * (sa*sb*sab)
44×
796
end
797

798
function beta(a::Number, b::Number)
799
    ya = loggamma(a)
12×
800
    yb = loggamma(b)
12×
801
    yab = loggamma(a+b)
12×
802
    return exp(ya + yb - yab)
12×
803
end
804

805
"""
806
    logbeta(x, y)
807

808
Natural logarithm of the [`beta`](@ref) function ``\\log(|\\operatorname{B}(x,y)|)``.
809

810
See also [`logabsbeta`](@ref).
811
"""
812
logbeta(a::Number, b::Number) = loggamma(a)+loggamma(b)-loggamma(a+b)
1,156×
813

814
"""
815
    logabsbeta(x, y)
816

817
Compute the natural logarithm of the absolute value of the [`beta`](@ref) function, returning a tuple `(log(abs(beta(x,y))), sign(beta(x,y)))`
818

819
See also [`logbeta`](@ref).
820
"""
821
function logabsbeta(a::Real, b::Real)
822
    if a <= 0.0
920×
823
        if isinteger(a) && 1-a-b > 0
8×
824
            sgn = isinteger(b/2) ? 1 : -1
4×
825
            return logabsbeta(1-a-b,b)
4×
826
        end
827
    end
828
    if b <= 0.0
916×
829
        if isinteger(b) && 1-a-b > 0
!
830
            sgn = isinteger(a/2) ? 1 : -1
!
831
            return logabsbeta(1-a-b,a)
!
832
        end
833
    end
834
    if a < b
916×
835
        a,b = b,a
12×
836
    end
837
    #asymptotic expansion for log(B(a,b)) for |a| >> |b|
838
    if abs(a) > 1e5*abs(b) && abs(a) > 1e5
916×
839
        return (loggammadiv(b,a) + loggamma(b)), 1
4×
840
    end
841
    ya, sa = logabsgamma(a)
916×
842
    yb, sb = logabsgamma(b)
912×
843
    yab, sab = logabsgamma(a+b)
912×
844
    (ya + yb - yab), (sa*sb*sab)
912×
845
end
846
## from base/mpfr.jl
847

848
# log of absolute value of gamma function
UNCOV
849
function logabsgamma(x::BigFloat)
!
850
    z = BigFloat()
!
851
    lgamma_signp = Ref{Cint}()
!
852
    ccall((:mpfr_lgamma,:libmpfr), Cint, (Ref{BigFloat}, Ref{Cint}, Ref{BigFloat}, Int32), z, lgamma_signp, x, ROUNDING_MODE[])
!
853
    return z, lgamma_signp[]
!
854
end
855

UNCOV
856
function loggamma(x::BigFloat)
!
857
    (y, s) = logabsgamma(x)
!
858
    s < 0.0 && throw(DomainError(x, "`gamma(x)` must be non-negative"))
!
859
    return y
!
860
end
861
if Base.MPFR.version() >= v"4.0.0"
862
    function beta(y::BigFloat, x::BigFloat)
863
        z = BigFloat()
4×
864
        ccall((:mpfr_beta, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Int32), z, y, x, ROUNDING_MODE[])
4×
865
        return z
4×
866
    end
867
end
868

869
## from base/combinatorics.jl'
870

871
function gamma(n::Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64})
872
    n < 0 && throw(DomainError(n, "`n` must not be negative."))
49×
873
    n == 0 && return Inf
49×
874
    n <= 2 && return 1.0
45×
875
    n > 20 && return gamma(Float64(n))
35×
876
    @inbounds return Float64(Base._fact_table64[n-1])
30×
877
end
878

879
## from base/math.jl
880

881
## from base/numbers.jl
882

883
# this trickery is needed while the deprecated method in Base exists
884
@static if !hasmethod(Base.factorial, Tuple{Number})
885
    import Base: factorial
886
end
887
factorial(x) = Base.factorial(x) # to make SpecialFunctions.factorial work unconditionally
!
888
factorial(x::Number) = gamma(x + 1) # fallback for x not Integer
20×
889

890
"""
891
    logabsbinomial(n, k)
892

893
Accurate natural logarithm of the absolute value of the [`binomial`](@ref)
894
coefficient `binomial(n, k)` for large `n` and `k` near `n/2`.
895

896
Returns a tuple `(log(abs(binomial(n,k))), sign(binomial(n,k)))`.
897
"""
898
function logabsbinomial(n::T, k::T) where {T<:Integer}
899
    S = float(T)
844×
900
    s = one(S)
844×
901
    if n < 0
844×
902
        # reflection formula
903
        #  binomial(n,k) = (-1)^k * binomial(-n+k-1,k)
904
        n = -n + k - 1
16×
905
        s = isodd(k) ? -s : s
16×
906
    end
907
    if k < 0 || k > n
1,684×
908
        # binomial(n,k) == 0
909
        return (typemin(S), zero(S))
8×
910
    elseif k == 0 || k == n
1,664×
911
        # binomial(n,k) == ±1
912
        return (zero(S), s)
16×
913
    end
914
    if k > (n>>1)
820×
915
        k = n - k
412×
916
    end
917
    if k == 1
820×
918
        # binomial(n,k) == ±n
919
        return (log(abs(n)), s)
16×
920
    else
921
        return (-log1p(n) - logabsbeta(n - k + one(T), k + one(T))[1], s)
804×
922
    end
923
end
924
logabsbinomial(n::Integer, k::Integer) = logabsbinomial(promote(n, k)...)
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc