Skip to content

Commit 42ec04a

Browse files
gaoflowdevmotion
andauthored
Fix the iop=2 Temme expansion variable and the ind=2 wide-band truncation (#538)
* Fix the iop=2 Temme expansion variable and the ind=2 wide-band truncation The iop=2 branch expanded c0/c1 in d00/d10 instead of z (NSWC gratio label 270), dropping the z-dependence of the expansion, and the ind=2 wide band discarded its computed 4-term expansion (label 230) in favour of the narrow-band 2-term form (label 280). Add reference-point regression tests for both branches. * refactor: share the Temme (P,Q) combine step; tighten wide/narrow-band tolerances Extract the c/w/t -> (P,Q) combine into _gamma_inc_temme_combine, used by both gamma_inc_temme_1 and the ind=2 wide-band branch in _gamma_inc that previously duplicated it inline. Measured actual error against the mpmath references: wide-band tops out at 1.3e-4, narrow-band at 4.6e-5, so tighten rtol from 5e-4 to 2e-4/1e-4 respectively (~1.5-2x margin) to catch regressions sooner. * Extend the Temme (P,Q) combine helper to all 5 call sites Fixes the docstring being pushed off gamma_inc_temme_1 by the helper's insertion point; also folds in gamma_inc_minimax and gamma_inc_temme, which had the same duplicated block. * Bump version from 2.8.1 to 2.8.2 --------- Co-authored-by: David Müller-Widmann <devmotion@users.noreply.github.com>
1 parent 172df8d commit 42ec04a

3 files changed

Lines changed: 80 additions & 32 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "SpecialFunctions"
22
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
3-
version = "2.8.1"
3+
version = "2.8.2"
44

55
[deps]
66
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

src/gamma_inc.jl

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,19 @@ function gamma_inc_taylor_x(a::Float64, x::Float64, ind::Integer)
542542
end
543543
end
544544

545+
# Combine the Temme series value `t` with the Gaussian-tail term `c*w` into (P, Q);
546+
# shared by gamma_inc_minimax, gamma_inc_temme, gamma_inc_temme_1's three branches,
547+
# and the ind=2 wide-band case in _gamma_inc.
548+
function _gamma_inc_temme_combine(c::Float64, w::Float64, t::Float64, rta::Float64, l::Float64)
549+
if l < 1.0
550+
p = c*(w - rt2pin*t/rta)
551+
return (p, 1.0 - p)
552+
else
553+
q = c*(w + rt2pin*t/rta)
554+
return (1.0 - q, q)
555+
end
556+
end
557+
545558
@doc raw"""
546559
gamma_inc_minimax(a,x,z)
547560
@@ -580,13 +593,7 @@ function gamma_inc_minimax(a::Float64, x::Float64, z::Float64)
580593
c6 = @evalpoly(z, d60, d6)
581594

582595
t = @evalpoly(1.0/a, c0, c1, c2, c3, c4, c5, c6, d70, d80)
583-
if l < 1.0
584-
p = c*(w - rt2pin*t/sqrt(a))
585-
return (p, 1.0 - p)
586-
else
587-
q = c*(w + rt2pin*t/sqrt(a))
588-
return (1.0 - q, q)
589-
end
596+
return _gamma_inc_temme_combine(c, w, t, sqrt(a), l)
590597
end
591598
#---USING THE MINIMAX APPROXIMATIONS---
592599
c0 = @evalpoly(z, -.333333333333333E+00, -.159840143443990E+00, -.335378520024220E-01, -.231272501940775E-02)/(@evalpoly(z, 1.0, .729520430331981E+00, .238549219145773E+00, .376245718289389E-01, .239521354917408E-02, -.939001940478355E-05, .633763414209504E-06))
@@ -600,13 +607,7 @@ function gamma_inc_minimax(a::Float64, x::Float64, z::Float64)
600607
c8 = @evalpoly(z, -.686013280418038E-03, .878371203603888E-03)
601608

602609
t = @evalpoly(1.0/a, c0, c1, c2, c3, c4, c5, c6, c7, c8)
603-
if l < 1.0
604-
p = c*(w - rt2pin*t/sqrt(a))
605-
return (p, 1.0 - p)
606-
else
607-
q = c*(w + rt2pin*t/sqrt(a))
608-
return (1.0 - q, q)
609-
end
610+
return _gamma_inc_temme_combine(c, w, t, sqrt(a), l)
610611
end
611612

612613
@doc raw"""
@@ -635,13 +636,7 @@ function gamma_inc_temme(a::Float64, x::Float64, z::Float64)
635636
c1 = @evalpoly(z, d10, d1[1], d1[2], d1[3], d1[4])
636637
c2 = @evalpoly(z, d20, d2[1])
637638
t = @evalpoly(1.0/a, c0, c1, c2)
638-
if l < 1.0
639-
p = c*(w - rt2pin*t/sqrt(a))
640-
return (p, 1.0 - p)
641-
else
642-
q = c*(w + rt2pin*t/sqrt(a))
643-
return (1.0 - q, q)
644-
end
639+
return _gamma_inc_temme_combine(c, w, t, sqrt(a), l)
645640
end
646641

647642
@doc raw"""
@@ -681,21 +676,15 @@ function gamma_inc_temme_1(a::Float64, x::Float64, z::Float64, ind::Integer)
681676
t = @evalpoly(u, c0, c1, c2, c3, c4, c5, c6, d70, d80)
682677

683678
elseif iop == 2
684-
c0 = @evalpoly(d00, d0[1], d0[2])
685-
c1 = @evalpoly(d10, d1[1])
679+
c0 = @evalpoly(z, d00, d0[1], d0[2])
680+
c1 = @evalpoly(z, d10, d1[1])
686681
t = @evalpoly(u, c0, c1, d20)
687682

688683
else
689684
t = @evalpoly(z, d00, d0[1])
690685

691686
end
692-
if l < 1.0
693-
p = c*(w - rt2pin*t/sqrt(a))
694-
return (p, 1.0 - p)
695-
else
696-
q = c*(w + rt2pin*t/sqrt(a))
697-
return (1.0 - q, q)
698-
end
687+
return _gamma_inc_temme_combine(c, w, t, sqrt(a), l)
699688
end
700689

701690
"""
@@ -919,7 +908,7 @@ function _gamma_inc(a::Float64, x::Float64, ind::Integer)
919908
return gamma_inc_temme(a, x, z)
920909
else
921910
t = @evalpoly(z, d00, d0[1], d0[2], d0[3])
922-
return gamma_inc_temme_1(a, x, z, ind)
911+
return _gamma_inc_temme_combine(c, w, t, rta, l)
923912
end
924913
else
925914
return _gamma_inc_choose_algorithm(a, x, ind)

test/gamma_inc.jl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,65 @@ end
8484
end
8585
end
8686

87+
# Temme expansions for ind=1 (iop==2) and the ind=2 wide band (iop==3): reference
88+
# values from mpmath at 80+ digits (DLMF 8.7.1 series and 8.9.2 continued fraction).
89+
@testset "incomplete gamma ratios: Temme iop 2/3 expansions" begin
90+
@testset "ind=1 iop=2: a=$a, x=$x" for (a, x, p, q) in (
91+
(14.0, 13.911135637064119, 0.5261046500921642, 0.4738953499078358),
92+
(14.0, 14.088864362935881, 0.5449404484556186, 0.4550595515443813),
93+
(100.0, 99.7625, 0.5038214442269839, 0.4961785557730161),
94+
(100.0, 100.2375, 0.522753673458071, 0.477246326541929),
95+
(1000.0, 999.24895905571, 0.4947284864885412, 0.5052715135114588),
96+
(1000.0, 1000.7510409442899, 0.5136748881127599, 0.4863251118872402),
97+
(10000.0, 9997.625, 0.4918547737457385, 0.5081452262542615),
98+
(10000.0, 10002.374999999998, 0.5108025931978544, 0.48919740680214563),
99+
(10000000.0, 9999924.895905571, 0.4905680282181972, 0.5094319717818028),
100+
(10000000.0, 10000075.104094429, 0.5095160050557511, 0.4904839949442488),
101+
(14.0, 13.906552106765321, 0.525615807496999, 0.474384192503001),
102+
)
103+
@test gamma_inc(a, x, 1)[1] p rtol=5e-7
104+
@test gamma_inc(a, x, 1)[2] q rtol=5e-7
105+
end
106+
@testset "ind=2 wide band: a=$a, x=$x" for (a, x, p, q) in (
107+
(10.0, 6.5, 0.12261595071018043, 0.8773840492898196),
108+
(10.0, 13.5, 0.8647360050511872, 0.1352639949488128),
109+
(25.0, 16.25, 0.02613839150563149, 0.9738616084943685),
110+
(25.0, 33.75, 0.9499593482838966, 0.05004065171610339),
111+
(100.0, 65.0, 3.372775722939482e-05, 0.9999662722427706),
112+
(100.0, 135.0, 0.999292148107214, 0.0007078518927860074),
113+
(1000.0, 650.0, 2.957759012559303e-37, 1.0),
114+
(1000.0, 1350.0, 1.0, 7.635408516228592e-24),
115+
)
116+
@test gamma_inc(a, x, 2)[1] p rtol=2e-4
117+
@test gamma_inc(a, x, 2)[2] q rtol=2e-4
118+
end
119+
@testset "ind=2 narrow band: a=$a, x=$x" for (a, x, p, q) in (
120+
(10.0, 9.778640563788214, 0.5140881193058611, 0.485911880694139),
121+
(10.0, 10.221359436211785, 0.5694405131522309, 0.43055948684776907),
122+
(100000.0, 99977.86405637882, 0.47251429019620883, 0.5274857098037912),
123+
(100000.0, 100022.13594362116, 0.5283205849613148, 0.4716794150386851),
124+
)
125+
@test gamma_inc(a, x, 2)[1] p rtol=1e-4
126+
@test gamma_inc(a, x, 2)[2] q rtol=1e-4
127+
end
128+
@testset "ind=0 unchanged: a=$a, x=$x" for (a, x, p, q) in (
129+
(14.0, 13.911135637064119, 0.5261046500921642, 0.4738953499078358),
130+
(14.0, 14.088864362935881, 0.5449404484556186, 0.4550595515443813),
131+
(100.0, 99.7625, 0.5038214442269839, 0.4961785557730161),
132+
(100.0, 100.2375, 0.522753673458071, 0.477246326541929),
133+
(1000.0, 999.24895905571, 0.4947284864885412, 0.5052715135114588),
134+
(1000.0, 1000.7510409442899, 0.5136748881127599, 0.4863251118872402),
135+
(10000.0, 9997.625, 0.4918547737457385, 0.5081452262542615),
136+
(10000.0, 10002.374999999998, 0.5108025931978544, 0.48919740680214563),
137+
(10000000.0, 9999924.895905571, 0.4905680282181972, 0.5094319717818028),
138+
(10000000.0, 10000075.104094429, 0.5095160050557511, 0.4904839949442488),
139+
(14.0, 13.906552106765321, 0.525615807496999, 0.474384192503001),
140+
)
141+
@test gamma_inc(a, x)[1] p rtol=1e-12
142+
@test gamma_inc(a, x)[2] q rtol=1e-12
143+
end
144+
end
145+
87146
@testset "inverse of incomplete gamma ratios" begin
88147
#Compared with Scipy.special.gammaincinv
89148
@test gamma_inc_inv(1.0,0.5,0.5) 0.69314718055994529

0 commit comments

Comments
 (0)