Published

jStat returns zero for a probability near 44%

Independent integration and a mathematical lower bound expose a noncentral-t probability collapse that remains after an earlier convergence safeguard.

A substantial probability disappears

jStat 1.9.6 returns zero for a probability of approximately 44.10%. Another nearby example returns about 1.89 × 10−40 instead of 44.14%. Both calls use small, exactly represented integer arguments and return without an exception. A plausible-looking number within the range from zero to one can therefore conceal a large numerical error.

The affected function evaluates the noncentral t distribution, which is used in statistical power calculations and some confidence intervals for effect sizes. A wrong probability can affect calculations that search for an interval endpoint by repeatedly evaluating the distribution.

Tasuku Kobayashi submitted the reproducer and independent evidence in jStat issue #300 on September 23, 2026. The issue is open; upstream confirmation and a repair remain pending. This follows up a convergence concern discussed during the original implementation, rather than claiming that the general limitation was previously unknown.

Reproduce the result

npm install jstat@1.9.6
const { jStat } = require('jstat');
for (const ncp of [25, 30, 40]) {
  console.log(ncp, jStat.noncentralt.cdf(ncp, 10, ncp));
}

The arguments are the evaluation point, degrees of freedom, and noncentrality parameter, respectively. The CDF is the probability of a value at or below the evaluation point.

Evaluation point / noncentralityDegrees of freedomjStat 1.9.6Independent reference
25 / 25100.4418566336902760.4418566371100132
30 / 30101.8920048548927194e-400.4414484587168333
40 / 401000.4410353509508114

The recorded environment used Node.js v24.19.0 on Linux x86_64. The first row is a control near the largest noncentrality in the existing CDF tests; the report concerns the large failures in the next two rows.

A mathematical bound rules out the returned values

The noncentral t variable is defined as T = (Z + delta) / sqrt(V / nu), where Z is standard normal and V is an independent chi-square variable withnu degrees of freedom. When the evaluation point equals a positive delta, the event Z ≤ 0 andV ≥ nu implies T ≤ delta.

At ten degrees of freedom, this gives an elementary lower bound of0.5 × exp(−5) × Σ(k=0…4) 5^k/k! ≈ 0.2202466425326062. The probability must be at least 22.02%. This disproves both near-zero results without relying on agreement with another statistical library.

Integrating the defining distribution independently with mpmath at 50 and 80 decimal digits gives the reference values above, agreeing to more than 45 decimal places. That agreement is a precision check, not a certified interval error bound. SciPy 1.17.0 provides an additional cross-check. The public evidence bundle contains the integration script and outputs.

Two failures in the same forward sum

The implementation sums a series from its first term and allows termination after at least 200 iterations when the last two contributions are small. For noncentrality 30, the important weights lie farther into the series: the Poisson weight has mean 450. Small early terms do not establish that the remaining sum is small.

Increasing the minimum to 1000 iterations as a diagnostic recovers an approximation near 0.44144846 for that example. It does not recover the noncentrality-40 example: the initial coefficients involveexp(−800), which rounds to zero in binary64, so subsequent multiplications cannot recover them. Simply raising a fixed iteration count does not address both failures.

The unchanged distribution module from upstream commit 72f367f reproduced the same results when evaluated over the released package's core and special functions. This was a module-level check, not a clean build of the entire upstream repository.

What this establishes

The report supplies concrete failures beyond the original implementation's tested noncentralities of 2, 5 and 25. It extends the earlier discussion in issue #131 and pull request #135, which introduced the 200-iteration safeguard.

This demonstrates Licklider's verification approach: use the mathematical definition to check an implementation, then make the failure and evidence reproducible upstream. The finding does not establish practical prevalence, a completed repair, or nomue's superiority on these cases. It adds no new supported product method.

Public evidence