#8435·pymc

BUG: Cauchy and StudentT logcdf return -inf in the lower tail where the true value is finite

Author: siddhant-shahhhCreated Sep 14, 2026Updated Sep 14, 2026
Labelsbug

Describe the issue:

logcdf for Cauchy and StudentT drifts in the lower tail and eventually returns -inf, where the true value is finite and nowhere near the limits of a float. In both cases it comes from cancellation in the argument handed to log.

Cauchy(0, 1):

value pm.logcdf scipy abs err
-1e12 -28.7759535 -28.7757510 2.0e-04
-1e14 -33.3868965 -33.3809212 6.0e-03
-1e15 -35.8205098 -35.6835063 1.4e-01
-1e16 -inf -37.9860914
-1e20 -inf -47.1964317

StudentT(nu, 0, 1) — the -inf kicks in somewhere between -7e7 (nu=1) and -4e8 (nu=30), and the last finite values before that are already off by up to ~2 nats:

nu value pm.logcdf scipy
1 -1e8 -inf -19.5654106
2 -1e8 -37.4299478 -37.5345087
2 -1e9 -inf -42.1396789
5 -1e8 -91.8824720 -89.8531475
5 -1e9 -inf -101.366073

PyMC's own logp is still finite at those same points. For Cauchy(0, 1) at value=-1e16, logp gives -74.83 while logcdf gives -inf: the density is finite but the cumulative probability is reported as exactly zero, and those can't both be right.

This isn't just a precision complaint. logcdf is what pm.Censored and the truncated distributions call, so a censored or truncated Cauchy/StudentT with a low bound ends up with an -inf logp and the sampler is stuck.

Reproduceable code example:

python
import numpy as np
import pymc as pm

from scipy import stats

rv = pm.Cauchy.dist(alpha=0.0, beta=1.0)
xs = np.array([-1e12, -1e14, -1e15, -1e16, -1e20])
print("pymc :", pm.logcdf(rv, xs).eval())
print("scipy:", stats.cauchy(0, 1).logcdf(xs))
print("logp :", pm.logp(rv, xs).eval())

t = pm.StudentT.dist(nu=5.0, mu=0.0, sigma=1.0)
xs = np.array([-1e7, -1e8, -1e9])
print("pymc :", pm.logcdf(t, xs).eval())
print("scipy:", stats.t(5.0).logcdf(xs))

Error message:

bash
No exception is raised. logcdf simply returns -inf.

PyMC version information:

Environment
  • PyMC version: 6.3.2+3.g3f3b1082e
  • PyTensor version: 3.3.1
  • Python version: 3.12.13
  • OS: macOS 26.6.2 (arm64)
  • Install method: pip, editable install from main

Context for the issue:

Cauchy.logcdf computes log(0.5 + arctan(z) / pi). As z goes to -inf, arctan(z) approaches -pi/2, so the argument is 0.5 - 0.5.

StudentT.logcdf computes x = (t + sqrt(t**2 + nu)) / (2 * sqrt(t**2 + nu)). For t << 0, t + sqrt(t**2 + nu) subtracts two nearly equal numbers, x underflows to zero, and betainc(a, b, 0) == 0.

Both have exact equivalents that avoid the cancellation. I have a patch with regression tests and will open a PR.

One scope note on StudentT: the rewrite removes the cancellation in x, which fixes the tail wherever betainc can still represent the result. For large nu far out in the tail, betainc(nu/2, nu/2, x) underflows on its own scipy.stats.t.logcdf returns -inf at the same points so that would need a log-space incomplete beta, which I'm leaving out of this.