Skip to content

Fix #11108: preserve incomplete-gamma upper tails for small shapes - #11109

Merged
thewilsonator merged 1 commit into
dlang:masterfrom
jmh530:codex/fix-igamma-small-shape
Oct 14, 2026
Merged

thewilsonator merged 1 commit into
dlang:masterfrom
jmh530:codex/fix-igamma-small-shape

Conversation

@jmh530

@jmh530 jmh530 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #11108.

For small positive shape parameters and x < 1, gammaIncompleteCompl computes Q by subtracting P from one. Since P is close to one, cancellation can overwhelm the upper tail. For example, gammaIncompleteCompl(1e-20L, 0.5L) returns approximately 2.92735e-18 on Windows DMD instead of 5.597735947761608e-21.

Evaluate Q directly for a <= 1/8 and x < 1 using the series in DLMF 8.7.3. Use expm1 and evaluate logGamma(1+a)/a without forming 1+a. For tiny arguments, factor out a to preserve representable subnormal results. Other parameter ranges retain their existing algorithms.

Validation

  • DMD 2.113.0: std.internal.math.gammafunction and std.mathspecial unit tests pass, with and without optimization.
  • LDC 1.43.0: the new regression tests pass with -O2 --noasm. The complete module suite still encounters an existing igammaTemmeLarge assertion (original line 295), also observed on the baseline.
  • An independent 72-case comparison against references calculated with 100 decimal digits passes on both compilers, including branch boundaries. Additional regression tests check representable subnormal tails.
  • Tested Windows real with 64 mantissa bits under DMD and 53 under LDC; 113-bit real was not tested.

Performance

Compared with original commit 1877367354fadf001365292d74e39ffd15c21bbc, in ns/call (original → patched):

Inputs DMD LDC
a = 0.01, x = 0.1..0.9 837.6 → 655.9 (-21.7%) 77.6 → 60.1 (-22.6%)
a = 1e-20, x = 0.1..0.9 806.3 → 400.6 (-50.3%) 76.0 → 38.7 (-49.1%)
a = 1e-20, x around 1e-100 783.4 → 288.1 (-63.2%) 56.2 → 15.2 (-73.0%)
a = 0.125, x = 0.1..0.9 996.8 → 710.0 (-28.8%) 69.8 → 60.5 (-13.4%)
Subnormal a, x = 0.5 10804.2 → 5501.3 (-49.1%) 589.0 → 150.0 (-74.5%)
Unchanged: a = 2.5, x = 0.1..0.9 840.4 → 837.4 (-0.4%) 70.1 → 69.4 (-1.0%)
Unchanged: a = 1e-20, x = 1..5 3282.4 → 3133.7 (-4.5%) 189.1 → 191.9 (+1.5%)

Measured on Windows x64, Intel Core Ultra 7 258V, using DMD -O -inline and LDC -O2 --noasm. Both implementations run in one process pinned to one logical processor, with 512 input pairs repeated 100 times per sample. Values are medians of ten samples after one warm-up, alternating execution order.

The direct series avoids the general logGamma evaluation. The tiny-shape shortcut also avoids rational-approximation arithmetic on subnormal operands. All affected benchmark cases improved.

These are local microbenchmarks, and the original results in the affected range are inaccurate. The small differences in unchanged paths, including the 1.5% LDC slowdown for x >= 1, do not establish a systematic performance change.

This PR was written entirely by an LLM/AI.

AI-Assisted-By: Codex (GPT-6 Astra Medium)

Avoid cancellation in gammaIncompleteCompl when the lower tail is
close to one. For example, Q(1e-20, 0.5) should be approximately
5.59774e-21, but Windows DMD returns approximately 2.92735e-18.

Evaluate the upper tail directly for a <= 1/8 and x < 1 using
expm1 and a stable evaluation of logGamma(1+a)/a. Factor out a
for tiny arguments to preserve representable subnormal results.
Keep the existing algorithms outside this range.

Add reference cases covering tiny shapes, branch boundaries, and
subnormal tails. Regression tests pass on DMD and LDC. Local
benchmarks improve across the affected cases on both compilers.

Fixes dlang#11108.

AI-Assisted-By: Codex (GPT-6 Astra Medium)
@thewilsonator
thewilsonator merged commit 24ba1b1 into dlang:master Oct 14, 2026
8 of 9 checks passed
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.

gammaIncompleteCompl loses upper-tail accuracy for tiny shape parameters

2 participants