@@ -539,3 +539,228 @@ function polygamma(m::Integer, z::Number)
539
539
# There is nothing to fallback to, since this didn't work
540
540
polygamma (m, x)
541
541
end
542
+
543
+ @static if VERSION >= v " 0.7.0-alpha.69"
544
+
545
+ export gamma, lgamma, beta, lbeta, lfactorial
546
+
547
+ # # from base/special/gamma.jl
548
+
549
+ gamma (x:: Float64 ) = nan_dom_err (ccall ((:tgamma ,libm), Float64, (Float64,), x), x)
550
+ gamma (x:: Float32 ) = nan_dom_err (ccall ((:tgammaf ,libm), Float32, (Float32,), x), x)
551
+
552
+ """
553
+ gamma(x)
554
+
555
+ Compute the gamma function of `x`.
556
+ """
557
+ gamma (x:: Real ) = gamma (float (x))
558
+
559
+ function lgamma_r (x:: Float64 )
560
+ signp = Ref {Int32} ()
561
+ y = ccall ((:lgamma_r ,libm), Float64, (Float64, Ptr{Int32}), x, signp)
562
+ return y, signp[]
563
+ end
564
+ function lgamma_r (x:: Float32 )
565
+ signp = Ref {Int32} ()
566
+ y = ccall ((:lgammaf_r ,libm), Float32, (Float32, Ptr{Int32}), x, signp)
567
+ return y, signp[]
568
+ end
569
+ lgamma_r (x:: Real ) = lgamma_r (float (x))
570
+ lgamma_r (x:: Number ) = lgamma (x), 1 # lgamma does not take abs for non-real x
571
+ """
572
+ lgamma_r(x)
573
+
574
+ Return L,s such that `gamma(x) = s * exp(L)`
575
+ """
576
+ lgamma_r
577
+
578
+ """
579
+ lfactorial(x)
580
+
581
+ Compute the logarithmic factorial of a nonnegative integer `x`.
582
+ Equivalent to [`lgamma`](@ref) of `x + 1`, but `lgamma` extends this function
583
+ to non-integer `x`.
584
+ """
585
+ lfactorial (x:: Integer ) = x < 0 ? throw (DomainError (x, " `x` must be non-negative." )) : lgamma (x + oneunit (x))
586
+ Base. @deprecate lfact lfactorial
587
+
588
+ """
589
+ lgamma(x)
590
+
591
+ Compute the logarithm of the absolute value of [`gamma`](@ref) for
592
+ [`Real`](@ref) `x`, while for [`Complex`](@ref) `x` compute the
593
+ principal branch cut of the logarithm of `gamma(x)` (defined for negative `real(x)`
594
+ by analytic continuation from positive `real(x)`).
595
+ """
596
+ function lgamma end
597
+
598
+ # asymptotic series for log(gamma(z)), valid for sufficiently large real(z) or |imag(z)|
599
+ @inline function lgamma_asymptotic (z:: Complex{Float64} )
600
+ zinv = inv (z)
601
+ t = zinv* zinv
602
+ # coefficients are bernoulli[2:n+1] .// (2*(1:n).*(2*(1:n) - 1))
603
+ return (z- 0.5 )* log (z) - z + 9.1893853320467274178032927e-01 + # <-- log(2pi)/2
604
+ zinv* @evalpoly (t, 8.3333333333333333333333368e-02 ,- 2.7777777777777777777777776e-03 ,
605
+ 7.9365079365079365079365075e-04 ,- 5.9523809523809523809523806e-04 ,
606
+ 8.4175084175084175084175104e-04 ,- 1.9175269175269175269175262e-03 ,
607
+ 6.4102564102564102564102561e-03 ,- 2.9550653594771241830065352e-02 )
608
+ end
609
+
610
+ # Compute the logΓ(z) function using a combination of the asymptotic series,
611
+ # the Taylor series around z=1 and z=2, the reflection formula, and the shift formula.
612
+ # Many details of these techniques are discussed in D. E. G. Hare,
613
+ # "Computing the principal branch of log-Gamma," J. Algorithms 25, pp. 221-236 (1997),
614
+ # and similar techniques are used (in a somewhat different way) by the
615
+ # SciPy loggamma function. The key identities are also described
616
+ # at http://functions.wolfram.com/GammaBetaErf/LogGamma/
617
+ function lgamma (z:: Complex{Float64} )
618
+ x = real (z)
619
+ y = imag (z)
620
+ yabs = abs (y)
621
+ if ! isfinite (x) || ! isfinite (y) # Inf or NaN
622
+ if isinf (x) && isfinite (y)
623
+ return Complex (x, x > 0 ? (y == 0 ? y : copysign (Inf , y)) : copysign (Inf , - y))
624
+ elseif isfinite (x) && isinf (y)
625
+ return Complex (- Inf , y)
626
+ else
627
+ return Complex (NaN , NaN )
628
+ end
629
+ elseif x > 7 || yabs > 7 # use the Stirling asymptotic series for sufficiently large x or |y|
630
+ return lgamma_asymptotic (z)
631
+ elseif x < 0.1 # use reflection formula to transform to x > 0
632
+ if x == 0 && y == 0 # return Inf with the correct imaginary part for z == 0
633
+ return Complex (Inf , signbit (x) ? copysign (oftype (x, pi ), - y) : - y)
634
+ end
635
+ # the 2pi * floor(...) stuff is to choose the correct branch cut for log(sinpi(z))
636
+ return Complex (1.1447298858494001741434262 , # log(pi)
637
+ copysign (6.2831853071795864769252842 , y) # 2pi
638
+ * floor (0.5 * x+ 0.25 )) -
639
+ log (sinpi (z)) - lgamma (1 - z)
640
+ elseif abs (x - 1 ) + yabs < 0.1
641
+ # taylor series around zero at z=1
642
+ # ... coefficients are [-eulergamma; [(-1)^k * zeta(k)/k for k in 2:15]]
643
+ w = Complex (x - 1 , y)
644
+ return w * @evalpoly (w, - 5.7721566490153286060651188e-01 ,8.2246703342411321823620794e-01 ,
645
+ - 4.0068563438653142846657956e-01 ,2.705808084277845478790009e-01 ,
646
+ - 2.0738555102867398526627303e-01 ,1.6955717699740818995241986e-01 ,
647
+ - 1.4404989676884611811997107e-01 ,1.2550966952474304242233559e-01 ,
648
+ - 1.1133426586956469049087244e-01 ,1.000994575127818085337147e-01 ,
649
+ - 9.0954017145829042232609344e-02 ,8.3353840546109004024886499e-02 ,
650
+ - 7.6932516411352191472827157e-02 ,7.1432946295361336059232779e-02 ,
651
+ - 6.6668705882420468032903454e-02 )
652
+ elseif abs (x - 2 ) + yabs < 0.1
653
+ # taylor series around zero at z=2
654
+ # ... coefficients are [1-eulergamma; [(-1)^k * (zeta(k)-1)/k for k in 2:12]]
655
+ w = Complex (x - 2 , y)
656
+ return w * @evalpoly (w, 4.2278433509846713939348812e-01 ,3.2246703342411321823620794e-01 ,
657
+ - 6.7352301053198095133246196e-02 ,2.0580808427784547879000897e-02 ,
658
+ - 7.3855510286739852662729527e-03 ,2.8905103307415232857531201e-03 ,
659
+ - 1.1927539117032609771139825e-03 ,5.0966952474304242233558822e-04 ,
660
+ - 2.2315475845357937976132853e-04 ,9.9457512781808533714662972e-05 ,
661
+ - 4.4926236738133141700224489e-05 ,2.0507212775670691553131246e-05 )
662
+ end
663
+ # use recurrence relation lgamma(z) = lgamma(z+1) - log(z) to shift to x > 7 for asymptotic series
664
+ shiftprod = Complex (x,yabs)
665
+ x += 1
666
+ sb = false # == signbit(imag(shiftprod)) == signbit(yabs)
667
+ # To use log(product of shifts) rather than sum(logs of shifts),
668
+ # we need to keep track of the number of + to - sign flips in
669
+ # imag(shiftprod), as described in Hare (1997), proposition 2.2.
670
+ signflips = 0
671
+ while x <= 7
672
+ shiftprod *= Complex (x,yabs)
673
+ sb′ = signbit (imag (shiftprod))
674
+ signflips += sb′ & (sb′ != sb)
675
+ sb = sb′
676
+ x += 1
677
+ end
678
+ shift = log (shiftprod)
679
+ if signbit (y) # if y is negative, conjugate the shift
680
+ shift = Complex (real (shift), signflips*- 6.2831853071795864769252842 - imag (shift))
681
+ else
682
+ shift = Complex (real (shift), imag (shift) + signflips* 6.2831853071795864769252842 )
683
+ end
684
+ return lgamma_asymptotic (Complex (x,y)) - shift
685
+ end
686
+ lgamma (z:: Complex{T} ) where {T<: Union{Integer,Rational} } = lgamma (float (z))
687
+ lgamma (z:: Complex{T} ) where {T<: Union{Float32,Float16} } = Complex {T} (lgamma (Complex {Float64} (z)))
688
+
689
+ gamma (z:: Complex ) = exp (lgamma (z))
690
+
691
+ """
692
+ beta(x, y)
693
+
694
+ Euler integral of the first kind ``\\ operatorname{B}(x,y) = \\ Gamma(x)\\ Gamma(y)/\\ Gamma(x+y)``.
695
+ """
696
+ function beta (x:: Number , w:: Number )
697
+ yx, sx = lgamma_r (x)
698
+ yw, sw = lgamma_r (w)
699
+ yxw, sxw = lgamma_r (x+ w)
700
+ return exp (yx + yw - yxw) * (sx* sw* sxw)
701
+ end
702
+
703
+ """
704
+ lbeta(x, y)
705
+
706
+ Natural logarithm of the absolute value of the [`beta`](@ref)
707
+ function ``\\ log(|\\ operatorname{B}(x,y)|)``.
708
+ """
709
+ lbeta (x:: Number , w:: Number ) = lgamma (x)+ lgamma (w)- lgamma (x+ w)
710
+
711
+ # # from base/mpfr.jl
712
+
713
+ # Functions for which NaN results are converted to DomainError, following Base
714
+ function gamma (x:: BigFloat )
715
+ isnan (x) && return x
716
+ z = BigFloat ()
717
+ ccall ((:mpfr_lgamma , :libmpfr ), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, ROUNDING_MODE[])
718
+ isnan (z) && throw (DomainError (x, " NaN result for non-NaN input." ))
719
+ return z
720
+ end
721
+
722
+ # log of absolute value of gamma function
723
+ function lgamma_r (x:: BigFloat )
724
+ z = BigFloat ()
725
+ lgamma_signp = Ref {Cint} ()
726
+ ccall ((:mpfr_lgamma ,:libmpfr ), Cint, (Ref{BigFloat}, Ref{Cint}, Ref{BigFloat}, Int32), z, lgamma_signp, x, ROUNDING_MODE[])
727
+ return z, lgamma_signp[]
728
+ end
729
+
730
+ lgamma (x:: BigFloat ) = lgamma_r (x)[1 ]
731
+
732
+ if Base. MPFR. version () >= v " 4.0.0"
733
+ function beta (y:: BigFloat , x:: BigFloat )
734
+ z = BigFloat ()
735
+ ccall ((:mpfr_beta , :libmpfr ), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Int32), z, y, x, ROUNDING_MODE[])
736
+ return z
737
+ end
738
+ end
739
+
740
+ # # from base/combinatorics.jl'
741
+
742
+ function gamma (n:: Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64} )
743
+ n < 0 && throw (DomainError (n, " `n` must not be negative." ))
744
+ n == 0 && return Inf
745
+ n <= 2 && return 1.0
746
+ n > 20 && return gamma (Float64 (n))
747
+ @inbounds return Float64 (Base. _fact_table64[n- 1 ])
748
+ end
749
+
750
+ # # from base/math.jl
751
+
752
+ @inline lgamma (x:: Float64 ) = nan_dom_err (ccall ((:lgamma , libm), Float64, (Float64,), x), x)
753
+ @inline lgamma (x:: Float32 ) = nan_dom_err (ccall ((:lgammaf , libm), Float32, (Float32,), x), x)
754
+ @inline lgamma (x:: Real ) = lgamma (float (x))
755
+
756
+ # # from base/numbers.jl
757
+ # TODO : deprecate instead of doing this type-piracy here?
758
+ Base. factorial (x:: Number ) = gamma (x + 1 ) # fallback for x not Integer
759
+
760
+ else # @static if
761
+
762
+ import Base: gamma, lgamma, beta, lbeta, lfact
763
+ const lfactorial = lfact
764
+ export lfactorial
765
+
766
+ end # @static if
0 commit comments