For valid truncated-normal intervals sufficiently far into either tail, pdf, cdf, and ppf do not produce the finite values expected from the documented SciPy-compatible interface.
Reproduced at commit 33cf0c05d3a7e7273aeb68c7c2124a58f80628f9, flopscope 0.12.1, NumPy 2.4.6, SciPy 1.18.1, Python 3.12:
from flopscope.stats import truncnorm
truncnorm.pdf(9.5, 9.0, 10.0) # inf; expected 0.08930284783811084
truncnorm.cdf(9.5, 9.0, 10.0) # ZeroDivisionError; expected 0.9907680958375221
truncnorm.ppf(0.5, 9.0, 10.0) # inf; expected 9.075779713738546
The mirrored interval [-10, -9] also produces infinite PDF/quantile output and a CDF exception. These are valid parameters, and the median must lie inside its finite support. The reference values above come from the corresponding scipy.stats.truncnorm calls.
All three methods form their normalization or inverse target from Phi(b) - Phi(a), where Phi is computed as 0.5 * (1 + erf(x / sqrt(2))). At these bounds both CDF values round to the same float. The resulting zero interval mass causes the observed division failure and infinite quantiles.
This likely needs a tail-aware normal mass calculation and inverse path, with tests for both tails and narrow intervals. Merely clipping the denominator would not restore the correct density or quantile. The current private _erfc helper also computes 1 - erf, so swapping to that helper alone would retain the cancellation.
This is a separate numerical-stability issue from NaN propagation in #258; no tail implementation change is included in that patch. Reproduction uses public statistical APIs locally, with SciPy as an independent reference.
Investigated with AI assistance.
For valid truncated-normal intervals sufficiently far into either tail,
pdf,cdf, andppfdo not produce the finite values expected from the documented SciPy-compatible interface.Reproduced at commit
33cf0c05d3a7e7273aeb68c7c2124a58f80628f9, flopscope 0.12.1, NumPy 2.4.6, SciPy 1.18.1, Python 3.12:The mirrored interval
[-10, -9]also produces infinite PDF/quantile output and a CDF exception. These are valid parameters, and the median must lie inside its finite support. The reference values above come from the correspondingscipy.stats.truncnormcalls.All three methods form their normalization or inverse target from
Phi(b) - Phi(a), wherePhiis computed as0.5 * (1 + erf(x / sqrt(2))). At these bounds both CDF values round to the same float. The resulting zero interval mass causes the observed division failure and infinite quantiles.This likely needs a tail-aware normal mass calculation and inverse path, with tests for both tails and narrow intervals. Merely clipping the denominator would not restore the correct density or quantile. The current private
_erfchelper also computes1 - erf, so swapping to that helper alone would retain the cancellation.This is a separate numerical-stability issue from NaN propagation in #258; no tail implementation change is included in that patch. Reproduction uses public statistical APIs locally, with SciPy as an independent reference.
Investigated with AI assistance.