Skip to content

Expand the minimax Temme series in 1/a rather than z - #534

Merged
devmotion merged 2 commits into
JuliaMath:masterfrom
gaoflow:fix-minimax-temme-expansion-variable
Jul 31, 2026
Merged

Expand the minimax Temme series in 1/a rather than z#534
devmotion merged 2 commits into
JuliaMath:masterfrom
gaoflow:fix-minimax-temme-expansion-variable

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

The abs(s) <= 1e-3 branch of gamma_inc_minimax evaluates the outer sum of T(a,λ) = Σ cₖ(z)·a⁻ᵏ with @evalpoly(z, c0, ..., d80), but that sum runs in a⁻ᵏ — the docstring three lines above says so, and the other three paths built from the same d tables already do it: the rational branch twenty lines below uses @evalpoly(1.0/a, ...), gamma_inc_temme uses 1.0/a, and gamma_inc_temme_1 uses u = 1.0/a over coefficients constructed identically to these. The existing suite already pins that convention in all three — applying the same 1.0/a → z swap to gamma_inc_temme_1 reddens test/gamma_inc.jl:18, to gamma_inc_temme reddens :27, and to the minimax rational branch reddens both :19 and :26; the one path of the four that no existing test pins is the one that got z. It is the same one-token transcription shape as #418#419, which fixed ind_ind in gamma_inc_temme_1; the minimax branch wasn't looked at then.

In that band |z| is only 2–5% of 1/a, so every term past c0 is weighted 20–40× too small, and the worst relative error over the branch drops from 1.16e-5 to 8.2e-14 — e.g. gamma_inc(134.0, 134.05)[2] returns 0.48679041818186286 where the true value is 0.4867899733251702445. The change is contained: over 2331 evaluations spanning a ∈ [25, 1.2e6], |1 - x/a| ∈ [1e-7, 0.4], both signs and all three ind values, only the 301 points inside this branch move at all — every minimax_rational, temme_1, temme and ind=1/ind=2 result is bit-identical. The band was effectively untested, which is presumably how it survived: test/gamma_inc.jl enters it twice with a single unique input, gamma_inc(1e7, 1e7 + 1), and that point happens to sit where |z|/(1/a) = 1.0000, so it is bit-identical either way. The new testset pins 16 points across the band at rtol=1e-13 (reference values from mpmath at 50+ digits, cross-checked against the DLMF 8.7.1 series and the 8.9.2 continued fraction); full Pkg.test() is green on 1.12, with gamma_inc going from 1001809 to 1001841 assertions.

gamma_inc_minimax evaluates the |1 - x/a| <= 1e-3 branch of

    T(a,lambda) = sum_k c_k(z) a^-k

with @evalpoly(z, c0, ..., d80).  The outer sum is in a^-k, as the
function's own docstring states and as the other three code paths
built from the same d tables already do: the rational branch ten lines
below uses @evalpoly(1.0/a, ...), gamma_inc_temme uses @evalpoly(1.0/a, ...)
and gamma_inc_temme_1 uses @evalpoly(u, ...) with u = 1.0/a.

In the affected band |z| is 2-5% of 1/a, so every correction term past
c0 is weighted 20-40x too small.  Over 300 points with a in [25, 1.2e6]
the worst relative error drops from 1.16e-5 to 8.2e-14; afterwards it
sits at or below the 1-ulp conditioning limit of x.  No point regresses,
and every other branch is bit-identical.

The band was covered by exactly one existing assertion, gamma_inc(1e7,
1e7 + 1), where |z| and 1/a happen to coincide to 1e-7 and the defect
cancels.  The new testset pins 16 points across the band against mpmath.
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.34%. Comparing base (02a51af) to head (8a25843).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #534      +/-   ##
==========================================
+ Coverage   94.28%   94.34%   +0.06%     
==========================================
  Files          14       14              
  Lines        3026     3026              
==========================================
+ Hits         2853     2855       +2     
+ Misses        173      171       -2     
Flag Coverage Δ
unittests 94.34% <100.00%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread test/gamma_inc.jl
Comment on lines +64 to +83
@testset "a=$a, x=$x" for (a, x, p, q) in (
(25.0, 24.97525, 0.5246323715433058506793, 0.4753676284566941493207),
(25.0, 25.02475, 0.5285687428518152079350, 0.4714312571481847920650),
(25.0, 24.9925, 0.5260050200501651608654, 0.4739949799498348391346),
(50.0, 50.0495, 0.5215950013484762091395, 0.4784049986515237908605),
(50.0, 49.975, 0.5173998411006592979910, 0.4826001588993407020090),
(134.0, 134.05, 0.5132100266748297555471, 0.4867899733251702444529),
(134.0, 133.86734, 0.5069170257485132637813, 0.4930829742514867362187),
(400.0, 400.396, 0.5145421195364036819570, 0.4854578804635963180430),
(400.0, 399.92, 0.5050535378251085332799, 0.4949464621748914667201),
(2000.0, 2001.98, 0.5206211429087569237891, 0.4793788570912430762109),
(2000.0, 1998.5, 0.4895906656999191847208, 0.5104093343000808152792),
(10000.0, 9990.1, 0.4618797888026423050784, 0.5381202111973576949216),
(10000.0, 10005.0, 0.5212634681357695888112, 0.4787365318642304111888),
(100000.0, 100099.0, 0.6232456486261727122096, 0.3767543513738272877904),
(100000.0, 99901.0, 0.3774766852491783530590, 0.6225233147508216469410),
(100000.0, 99985.0, 0.4815027198019921823376, 0.5184972801980078176624),
)
@test gamma_inc(a, x)[1] ≈ p rtol=1e-13
@test gamma_inc(a, x)[2] ≈ q rtol=1e-13

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU these tests are failing on master?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — all 32 assertions fail on master (02a51af), worst relative error 1.16e-5 at a=25, x=24.97525, shrinking to ~7.8e-10 by a=1e5. With the one-line change they pass at rtol=1e-13.

The red CI isn't them, though: that's the pre-existing gamma_inc allocations testset on Julia pre. It fails 12 times on master too — https://github.com/JuliaMath/SpecialFunctions.jl/actions/runs/27935023667 on 02a51af (2026-06-22) has the same 12 failures at test/gamma_inc.jl:301/303/305/310, all three OSes, everything else green. Here they show as :328/:330/:332/:337 only because this PR inserts 27 lines above them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — bumped to 2.8.1 in 8a25843, ready to tag after merge.

@devmotion devmotion left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the version number, so we can tag a release with the fix once it is merged?

@devmotion
devmotion merged commit c9ff360 into JuliaMath:master Jul 31, 2026
12 of 15 checks passed
@devmotion

Copy link
Copy Markdown
Member

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants