@@ -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
@@ -726,19 +725,7 @@ function gamma_inc_inv_qsmall(a::Float64, q::Float64)
726
725
end
727
726
728
727
"""
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)
728
+ gamma_inc_inv_alarge(a, minpq, pcase)
742
729
743
730
Compute `x0` - initial approximation when `a` is large.
744
731
The inversion problem is rewritten as :
@@ -753,9 +740,10 @@ and it is possible to expand:
753
740
which is calculated by coeff1, coeff2 and coeff3 functions below.
754
741
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
742
"""
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 )
743
+ function gamma_inc_inv_alarge (a:: Float64 , minpq:: Float64 , pcase:: Bool )
744
+ r = erfcinv (2 * minpq)
745
+ s = r/ sqrt (a* 0.5 )
746
+ eta = pcase ? - s : s
759
747
eta += (coeff1 (eta) + (coeff2 (eta) + coeff3 (eta)/ a)/ a)/ a
760
748
x0 = a* lambdaeta (eta)
761
749
fp = - sqrt (inv2π* a)* exp (- 0.5 * a* eta* eta)/ gammax (a)
@@ -919,45 +907,47 @@ External links: [DLMF](https://dlmf.nist.gov/8.2.4), [Wikipedia](https://en.wiki
919
907
920
908
See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc).
921
909
"""
922
- gamma_inc_inv (a:: Real , p:: Real , q:: Real ) = _gamma_inc_inv ( promote ( float (a), float (p), float (q)) ... )
923
-
924
- function _gamma_inc_inv (a :: Float64 , p :: Float64 , q :: Float64 )
910
+ function gamma_inc_inv (a:: Real , p:: Real , q:: Real )
911
+ return _gamma_inc_inv ( map (float, promote (a, p, q)) ... )
912
+ end
925
913
914
+ # `gamma inc_inv` ensures that arguments of `_gamma_inc_inv` are
915
+ # floating point numbers of the same type
916
+ function _gamma_inc_inv (a:: T , p:: T , q:: T ) where {T<: Real }
926
917
if p + q != 1
927
918
throw (ArgumentError (" p + q must equal one but is $(p + q) " ))
928
919
end
929
920
930
921
if iszero (p)
931
- return 0.0
922
+ return zero (T)
932
923
elseif iszero (q)
933
- return Inf
924
+ return T ( Inf )
934
925
end
935
926
936
- if p < 0.5
937
- pcase = true
938
- porq = p
939
- s = - 1
940
- else
941
- pcase = false
942
- porq = q
943
- s = 1
944
- end
927
+ pcase = p < 0.5
928
+ minpq = pcase ? p : q
929
+ return __gamma_inc_inv (a, minpq, pcase)
930
+ end
931
+
932
+ function __gamma_inc_inv (a:: Float64 , minpq:: Float64 , pcase:: Bool )
945
933
haseta = false
946
934
947
- logr = (1.0 / a)* (log (p) + logabsgamma (a + 1.0 )[1 ])
935
+ logp = pcase ? log (minpq) : log1p (- minpq)
936
+ loggamma1pa = a <= 1.0 ? loggamma1p (a) : loggamma (a + 1.0 )
937
+ logr = (logp + loggamma1pa) / a
948
938
if logr < log (0.2 * (1 + a)) # small value of p
949
- x0 = gamma_inc_inv_psmall (a, p )
950
- elseif ((q < min (0.02 , exp (- 1.5 * a)/ gamma (a))) && ( a < 10 )) # small q
951
- x0 = gamma_inc_inv_qsmall (a, q )
952
- elseif abs (porq - 0.5 ) < 1.0e-05
939
+ x0 = gamma_inc_inv_psmall (a, logr )
940
+ elseif ! pcase && minpq < min (0.02 , exp (- 1.5 * a)/ gamma (a)) && a < 10 # small q
941
+ x0 = gamma_inc_inv_qsmall (a, minpq )
942
+ elseif abs (minpq - 0.5 ) < 1.0e-05
953
943
x0 = a - 1.0 / 3.0 + (8.0 / 405.0 + 184.0 / 25515.0 / a)/ a
954
944
elseif abs (a - 1.0 ) < 1.0e-4
955
- x0 = pcase ? - log1p (- p ) : - log (q )
945
+ x0 = pcase ? - log1p (- minpq ) : - log (minpq )
956
946
elseif a < 1.0 # small value of a
957
- x0 = gamma_inc_inv_asmall (a, p, q, pcase )
947
+ x0 = exp (logr )
958
948
else # large a
959
949
haseta = true
960
- x0, fp = gamma_inc_inv_alarge (a, porq, s )
950
+ x0, fp = gamma_inc_inv_alarge (a, minpq, pcase )
961
951
end
962
952
963
953
t = 1
@@ -981,7 +971,7 @@ function _gamma_inc_inv(a::Float64, p::Float64, q::Float64)
981
971
982
972
px, qx = gamma_inc (a, x, 0 )
983
973
984
- ck1 = pcase ? - r* (px - p ) : r* (qx - q )
974
+ ck1 = pcase ? - r* (px - minpq ) : r* (qx - minpq )
985
975
if a > 0.05
986
976
ck2 = (x - a + 1.0 )/ (2.0 * x)
987
977
@@ -1014,16 +1004,8 @@ function _gamma_inc_inv(a::Float64, p::Float64, q::Float64)
1014
1004
return x
1015
1005
end
1016
1006
1017
- function _gamma_inc_inv (a:: T , p:: T , q:: T ) where {T <: Union{Float16, Float32} }
1018
- if p + q != one (T)
1019
- throw (ArgumentError (" p + q must equal one but was $(p + q) " ))
1020
- end
1021
- p64, q64 = if p < q
1022
- (Float64 (p), 1 - Float64 (p))
1023
- else
1024
- (1 - Float64 (q), Float64 (q))
1025
- end
1026
- return T (_gamma_inc_inv (Float64 (a), p64, q64))
1007
+ function __gamma_inc_inv (a:: T , minpq:: T , pcase:: Bool ) where {T<: Union{Float16,Float32} }
1008
+ return T (__gamma_inc_inv (Float64 (a), Float64 (minpq), pcase))
1027
1009
end
1028
1010
1029
1011
# like promote(x,y), but don't complexify real values
0 commit comments