Skip to content

fix: stabilize Gamma PDF for finite in-range parameters - #442

Open
day01 wants to merge 1 commit into
statrs-dev:mainfrom
day01:feat/fix-gamma-pdf-stability
Open

fix: stabilize Gamma PDF for finite in-range parameters#442
day01 wants to merge 1 commit into
statrs-dev:mainfrom
day01:feat/fix-gamma-pdf-stability

Conversation

@day01

@day01 day01 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • evaluate the non-trivial Gamma PDF through ln_pdf().exp() to avoid overflow/underflow in separately evaluated factors
  • preserve exact boundary behavior for x = 0, x = +inf, and shape = 1
  • use a compensated sum for ln(rate) + ln(x) before multiplying by shape
  • add a regression test for Gamma(80, 1e-5).pdf(8e6)

Root cause

The previous formula evaluated rate.powf(shape) independently. For valid finite parameters this factor could underflow to zero while the remaining factors compensated it mathematically, producing NaN instead of a finite density.

TDD and independent numerical references

The regression case is Gamma(shape=80, rate=1e-5).pdf(8e6).

Implementation Result Relative error vs. mpmath Outcome
statrs (this PR) 4.455666577034977970e-7 2.63e-14 correct
Boost.Math 1.90 4.455666577035076430e-7 4.22e-15 agrees
R 4.2.1 dgamma 4.455666577035096020e-7 1.81e-16 agrees
mpmath 1.4.1, 136-bit 4.45566657703509521452812298721e-7 reference reference
SciPy 1.18.0 4.455666577035271250e-7 3.95e-14 agrees

Upstream statrs returns NaN; the regression test is red on upstream and green with this change. R and Boost.Math are more accurate for this input; this change is more accurate than SciPy.

Performance

Case Upstream This change Difference
issue input: Gamma(80, 1e-5).pdf(8e6) 34.58 ns, returns NaN 30.86 ns, finite result 10.8% faster
typical finite input 37.74 ns 27.06 ns 28.3% faster
large-shape input 26.70 ns 27.32 ns 2.3% slower
Implementation Execution mode Median time per call Time relative
statrs (this PR) Rust release, default std features 26.05 ns 1.00x
Boost.Math 1.90 C++17, -O3 -march=native 27.54 ns 1.06x
R 4.2.1 dgamma scalar R call 755 ns 29.0x
mpmath 1.4.1, 136-bit scalar Python call 16.95 us 650.7x
SciPy 1.18.0 gamma.pdf scalar Python call 21.91 us 841.0x

Related issue

Fixes #422Gamma::pdf returns NaN for ordinary, finite, in-range parameters.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.07%. Comparing base (92819b6) to head (e0c56d3).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #442   +/-   ##
=======================================
  Coverage   95.07%   95.07%           
=======================================
  Files          62       62           
  Lines       14191    14203   +12     
=======================================
+ Hits        13492    13504   +12     
  Misses        699      699           

☔ 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.

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.

Gamma::pdf returns NaN for ordinary, finite, in-range parameters

1 participant