179
179
"""
180
180
lambdaeta(eta)
181
181
182
- Compute the value of eta satisfying ``eta^{2}/2 = \\ lambda-1-\\ ln {\\ lambda}``.
182
+ Compute the value of `` \\ lambda`` satisfying ``\\ eta^{2}/2 = \\ lambda-1-\\ log {\\ lambda}``.
183
183
"""
184
184
function lambdaeta (eta:: Float64 )
185
185
s = eta* eta* 0.5
@@ -665,7 +665,7 @@ function gamma_inc_fsum(a::Float64, x::Float64)
665
665
end
666
666
667
667
"""
668
- gamma_inc_inv_psmall(a,p )
668
+ gamma_inc_inv_psmall(a, logr )
669
669
670
670
Compute `x0` - initial approximation when `p` is small.
671
671
Here we invert the series in Eqn (2.20) in the paper and write the inversion problem as:
@@ -675,8 +675,7 @@ x = r\\left[1 + a\\sum_{k=1}^{\\infty}\\frac{(-x)^{n}}{(a+n)n!}\\right]^{-1/a},
675
675
where ``r = (p\\ Gamma(1+a))^{1/a}``
676
676
Inverting this relation we obtain ``x = r + \\ sum_{k=2}^{\\ infty}c_{k}r^{k}``.
677
677
"""
678
- function gamma_inc_inv_psmall (a:: Float64 , p:: Float64 )
679
- logr = (1.0 / a)* (log (p) + logabsgamma (a + 1.0 )[1 ])
678
+ function gamma_inc_inv_psmall (a:: Float64 , logr:: Float64 )
680
679
r = exp (logr)
681
680
ap1 = a + 1.0
682
681
ap1² = ap1* ap1
@@ -694,7 +693,7 @@ function gamma_inc_inv_psmall(a::Float64, p::Float64)
694
693
end
695
694
696
695
"""
697
- gamma_inc_inv_qsmall(a,q )
696
+ gamma_inc_inv_qsmall(a, q, qgammaxa )
698
697
699
698
Compute `x0` - initial approximation when `q` is small from ``e^{-x_{0}} x_{0}^{a} = q \\ Gamma(a)``.
700
699
Asymptotic expansions Eqn (2.29) in the paper is used here and higher approximations are obtained using
@@ -703,9 +702,9 @@ x \\sim x_{0} - L + b \\sum_{k=1}^{\\infty} d_{k}/x_{0}^{k}
703
702
```
704
703
where ``b = 1-a``, ``L = \\ ln{x_0}``.
705
704
"""
706
- function gamma_inc_inv_qsmall (a:: Float64 , q:: Float64 )
705
+ function gamma_inc_inv_qsmall (a:: Float64 , q:: Float64 , qgammaxa :: Float64 )
707
706
b = 1.0 - a
708
- eta = sqrt (- 2 / a* log (q * gammax (a) * sqrt (twoπ / a) ))
707
+ eta = sqrt (- 2 / a* log (qgammaxa ))
709
708
x0 = a* lambdaeta (eta)
710
709
l = log (x0)
711
710
@@ -716,7 +715,9 @@ function gamma_inc_inv_qsmall(a::Float64, q::Float64)
716
715
ck3 = (@horner (l, @horner (b, - 12 , - 24 , - 11 ), @horner (b, 12 , 24 , 6 ), @horner (b, - 6 , - 9 ), 2 ))/ 6.0
717
716
ck4 = (@horner (l, @horner (b, 72 , 162 , 120 , 25 ), @horner (b, - 72 , - 168 , - 114 , - 12 ), @horner (b, 36 , 84 , 36 ), @horner (b, - 12 , - 22 ), 3 ))/ 12.0
718
717
x0 = x0 - l + b* r* @horner (r, ck1, ck2, ck3, ck4)
719
- else
718
+ elseif x0 > 1
719
+ # The x0 > 1 condition isn't in the original version but without it
720
+ # the update in the branch can cause negative initial x0
720
721
r = 1.0 / x0
721
722
l² = l* l
722
723
ck1 = l - 1.0
@@ -726,19 +727,7 @@ function gamma_inc_inv_qsmall(a::Float64, q::Float64)
726
727
end
727
728
728
729
"""
729
- gamma_inc_inv_asmall(a,p,q,pcase)
730
-
731
- Compute `x0` - initial approximation when `a` is small.
732
- Here the solution `x` of ``P(a,x)=p`` satisfies ``x_{l} < x < x_{u}``
733
- where ``x_{l} = (p\\ Gamma(a+1))^{1/a}`` and ``x_{u} = -\\ log{(1 - p\\ Gamma(a+1))}``, and is used as starting value for Newton iteration.
734
- """
735
- function gamma_inc_inv_asmall (a:: Float64 , p:: Float64 , q:: Float64 , pcase:: Bool )
736
- logp = (pcase) ? log (p) : log1p (- q)
737
- return exp ((1.0 / a)* (logp + loggamma1p (a)))
738
- end
739
-
740
- """
741
- gamma_inc_inv_alarge(a,porq,s)
730
+ gamma_inc_inv_alarge(a, minpq, pcase)
742
731
743
732
Compute `x0` - initial approximation when `a` is large.
744
733
The inversion problem is rewritten as :
@@ -753,9 +742,10 @@ and it is possible to expand:
753
742
which is calculated by coeff1, coeff2 and coeff3 functions below.
754
743
This returns a tuple `(x0,fp)`, where `fp` is computed since it's an approximation for the coefficient after inverting the original power series.
755
744
"""
756
- function gamma_inc_inv_alarge (a:: Float64 , porq:: Float64 , s:: Integer )
757
- r = erfcinv (2 * porq)
758
- eta = s* r/ sqrt (a* 0.5 )
745
+ function gamma_inc_inv_alarge (a:: Float64 , minpq:: Float64 , pcase:: Bool )
746
+ r = erfcinv (2 * minpq)
747
+ s = r/ sqrt (a* 0.5 )
748
+ eta = pcase ? - s : s
759
749
eta += (coeff1 (eta) + (coeff2 (eta) + coeff3 (eta)/ a)/ a)/ a
760
750
x0 = a* lambdaeta (eta)
761
751
fp = - sqrt (inv2π* a)* exp (- 0.5 * a* eta* eta)/ gammax (a)
@@ -923,45 +913,50 @@ External links: [DLMF](https://dlmf.nist.gov/8.2.4), [Wikipedia](https://en.wiki
923
913
924
914
See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc).
925
915
"""
926
- gamma_inc_inv (a:: Real , p:: Real , q:: Real ) = _gamma_inc_inv ( promote ( float (a), float (p), float (q)) ... )
927
-
928
- function _gamma_inc_inv (a :: Float64 , p :: Float64 , q :: Float64 )
916
+ function gamma_inc_inv (a:: Real , p:: Real , q:: Real )
917
+ return _gamma_inc_inv ( map (float, promote (a, p, q)) ... )
918
+ end
929
919
920
+ # `gamma inc_inv` ensures that arguments of `_gamma_inc_inv` are
921
+ # floating point numbers of the same type
922
+ function _gamma_inc_inv (a:: T , p:: T , q:: T ) where {T<: Real }
930
923
if p + q != 1
931
924
throw (ArgumentError (" p + q must equal one but is $(p + q) " ))
932
925
end
933
926
934
927
if iszero (p)
935
- return 0.0
928
+ return zero (T)
936
929
elseif iszero (q)
937
- return Inf
930
+ return T ( Inf )
938
931
end
939
932
940
- if p < 0.5
941
- pcase = true
942
- porq = p
943
- s = - 1
944
- else
945
- pcase = false
946
- porq = q
947
- s = 1
948
- end
933
+ pcase = p < 0.5
934
+ minpq = pcase ? p : q
935
+ return __gamma_inc_inv (a, minpq, pcase)
936
+ end
937
+
938
+ function __gamma_inc_inv (a:: Float64 , minpq:: Float64 , pcase:: Bool )
949
939
haseta = false
950
940
951
- logr = (1.0 / a)* (log (p) + logabsgamma (a + 1.0 )[1 ])
941
+ logp = pcase ? log (minpq) : log1p (- minpq)
942
+ loggamma1pa = a <= 1.0 ? loggamma1p (a) : loggamma (a + 1.0 )
943
+ logr = (logp + loggamma1pa) / a
952
944
if logr < log (0.2 * (1 + a)) # small value of p
953
- x0 = gamma_inc_inv_psmall (a, p)
954
- elseif ((q < min (0.02 , exp (- 1.5 * a)/ gamma (a))) && (a < 10 )) # small q
955
- x0 = gamma_inc_inv_qsmall (a, q)
956
- elseif abs (porq - 0.5 ) < 1.0e-05
945
+ x0 = gamma_inc_inv_psmall (a, logr)
946
+ elseif ! pcase && a < 10 && minpq < 0.02 && (qgammaxa = minpq* gammax (a)* sqrt (twoπ/ a)) < 1 # small q
947
+ # This deviates from the original version. The qgammaxa variable
948
+ # here ensures that the argument of sqrt in gamma_inc_inv_qsmall
949
+ # is positive
950
+ x0 = gamma_inc_inv_qsmall (a, minpq, qgammaxa)
951
+ elseif abs (minpq - 0.5 ) < 1.0e-05
957
952
x0 = a - 1.0 / 3.0 + (8.0 / 405.0 + 184.0 / 25515.0 / a)/ a
958
953
elseif abs (a - 1.0 ) < 1.0e-4
959
- x0 = pcase ? - log1p (- p ) : - log (q )
954
+ x0 = pcase ? - log1p (- minpq ) : - log (minpq )
960
955
elseif a < 1.0 # small value of a
961
- x0 = gamma_inc_inv_asmall (a, p, q, pcase )
956
+ x0 = exp (logr )
962
957
else # large a
963
958
haseta = true
964
- x0, fp = gamma_inc_inv_alarge (a, porq, s )
959
+ x0, fp = gamma_inc_inv_alarge (a, minpq, pcase )
965
960
end
966
961
967
962
t = 1
@@ -985,7 +980,7 @@ function _gamma_inc_inv(a::Float64, p::Float64, q::Float64)
985
980
986
981
px, qx = gamma_inc (a, x, 0 )
987
982
988
- ck1 = pcase ? - r* (px - p ) : r* (qx - q )
983
+ ck1 = pcase ? - r* (px - minpq ) : r* (qx - minpq )
989
984
if a > 0.05
990
985
ck2 = (x - a + 1.0 )/ (2.0 * x)
991
986
@@ -1018,16 +1013,8 @@ function _gamma_inc_inv(a::Float64, p::Float64, q::Float64)
1018
1013
return x
1019
1014
end
1020
1015
1021
- function _gamma_inc_inv (a:: T , p:: T , q:: T ) where {T <: Union{Float16, Float32} }
1022
- if p + q != one (T)
1023
- throw (ArgumentError (" p + q must equal one but was $(p + q) " ))
1024
- end
1025
- p64, q64 = if p < q
1026
- (Float64 (p), 1 - Float64 (p))
1027
- else
1028
- (1 - Float64 (q), Float64 (q))
1029
- end
1030
- return T (_gamma_inc_inv (Float64 (a), p64, q64))
1016
+ function __gamma_inc_inv (a:: T , minpq:: T , pcase:: Bool ) where {T<: Union{Float16,Float32} }
1017
+ return T (__gamma_inc_inv (Float64 (a), Float64 (minpq), pcase))
1031
1018
end
1032
1019
1033
1020
# like promote(x,y), but don't complexify real values
0 commit comments