Published
SciPy’s noncentral t distribution returns NaN for small-sample power calculations
With few observations and a large effect, scipy.special.nctdtr returns nan for a lower-tail probability near 1e-28, so a two-sided t-test power calculation returns nan instead of about 1.
Earlier version. nomue was an earlier version of SciGround. Its verification capabilities are now part of SciGround; earlier publications, packages, and records keep the nomue name as a historical record.
A power calculation returns NaN
Plan a two-group t-test with three animals per group and a very large standardized effect (d = 10). The two-sided power is about 0.9999999999. Computed with SciPy’s noncentral t distribution, it is nan.
The upper tail is fine. The lower tail, a probability near 10−39, comes back as nan, and adding nan to anything gives nan. The same happens for other small-sample designs with a large noncentrality, the situation in which a power or sample-size tool is checking that a planned study is large enough.
Tasuku Kobayashi submitted six additional reproducers with high-precision references to SciPy’s existing open issue #25470 on November 10, 2026. Upstream confirmation and a correction remain pending.
| df | Noncentrality | x | SciPy result | Reference |
|---|---|---|---|---|
| 3 | 10 | −4.0 | nan | 8.97477150238e-28 |
| 5 | 10 | −4.0 | nan | 2.11688539267e-29 |
| 5 | 10 | −2.0 | nan | 6.04531916789e-28 |
| 30 | 6 | −4.0 | nan | 8.48464854021e-20 |
| 100 | 6 | −4.0 | nan | 2.82672896313e-22 |
| 4 | 12.25 | −2.776 | nan | 2.67205583146e-39 |
Both scipy.special.nctdtr and scipy.stats.nct.cdf return nan for every case, with no warning, on the stable release and on the development build listed below. Every reference is a normal binary64 number well above the smallest representable value.
Where the NaN comes from
The issue was opened on June 22, 2026 with a large-df example. A SciPy maintainer explained in the thread that the Boost.Math function SciPy uses returns a slightly negative value there, and SciPy’s wrapper replaces any result outside 0 to 1 with nan because it cannot be trusted. Our cases show the same behaviour at small df, which is where power calculations for small studies live.
Boost.Math issues #1430 and #1524 describe negative lower-tail values of this distribution and were closed with fixes in August and October 2026. The SciPy development build of November 8, 2026 still returned nan for all six cases. We did not test SciPy against Boost’s development branch, so whether updating SciPy’s vendored Boost resolves these cases is open.
An independent reference
The noncentral t lower tail can be written as a one-dimensional integral over a chi-square variable:
P(T <= x) = ∫₀^∞ Φ(x·sqrt(v/df) − nc) · f_chi2(v; df) dvThe reference calculation evaluates it with mpmath quadrature twice, at 50 and 60 significant digits with different interval splits. The two runs agree to all twelve printed digits for every case (output).
Reproduce the observation
from scipy import special, stats
print(special.nctdtr(3, 10, -4.0)) # nan; reference 8.97e-28
df, nc = 4, 12.247448713915890 # n = 3 per group, d = 10
crit = stats.t.ppf(0.975, df)
print(stats.nct.sf(crit, df, nc) + stats.nct.cdf(-crit, df, nc)) # nan; expected ≈ 1The recorded runs used SciPy 1.18.1 with NumPy 2.5.4, and the official development build 2.0.0.dev0+git20261108.c9073e6 with NumPy 2.6.0.dev0+git20261107.80049a0. Both ran on Python 3.13.18, Linux x86_64. The references used mpmath 1.4.1.
- Code: reproduce.py, reference.py.
- Outputs: stable release, development build, reference.
- SHA-256 hashes for the five files.
What the case demonstrates
We found these cases while checking our free sample-size calculator against SciPy, statsmodels and R. The calculator computes the noncentral t distribution with its own implementation, which returns a value at rounding level instead of nan, so its power results are unaffected. The affected cases are excluded from the SciPy comparison and listed on the calculator page. Cross-checking against more than one reference is what made the gap visible.
This submission adds small-sample reproducers to a known, open problem; it makes no claim to a new problem family or to a repair. The numerical outputs came from Python execution in the recorded environments, and the reporter reviewed the submission before posting. This work does not add noncentral t verification to nomue’s supported scope.