Skip to main content

Modules/_statisticsmodule.c

cpython 3.14 @ ab2d84fe1023/Modules/_statisticsmodule.c

_statisticsmodule.c is one of the smallest accelerator modules in CPython. It exports a single function, _normal_dist_inv_cdf, which computes the inverse cumulative distribution function of the standard normal distribution (also called the probit function or quantile function). The bulk of Lib/statistics.py is pure Python; this file exists solely because the rational-approximation loop in NormalDist.inv_cdf is called in tight loops by Monte Carlo and confidence-interval code, where even a modest C speedup is measurable. There is no Python fallback inside the C file itself; if the extension fails to import, CPython falls back to the pure-Python implementation in statistics.py.

Map

LinesSymbolRolegopy
1-20includesPython.h, math.h
21-110_statistics__normal_dist_inv_cdf_implAcklam rational approximation
111-130_statistics_methods[]Module method table (one entry)
131-145_statisticsmodule struct, PyInit__statisticsModule definition and init

Reading

Acklam rational approximation (lines 21 to 110)

cpython 3.14 @ ab2d84fe1023/Modules/_statisticsmodule.c#L21-110

The implementation follows Peter Acklam's algorithm (published 2003) for approximating the inverse normal CDF to full double precision. The domain is split into three regions: the lower tail (p < p_low), the central region (p_low <= p <= p_high), and the upper tail (p > p_high), where p_low = 0.02023 and p_high = 1 - p_low. In the central region the approximation is a ratio of two degree-6 polynomials in (p - 0.5)^2. In the tails the approximation is a ratio of two degree-6 polynomials in sqrt(-2 * log(p)). The function raises StatisticsError for p <= 0 or p >= 1 and returns the exact signed infinities at the boundaries by convention.

/* Coefficients for the central region */
static const double A[] = {
-3.969683028665376e+01, 2.209460984245205e+02, ...
};
static const double B[] = {
-5.447609879822406e+01, 1.615858368580409e+02, ...
};

The polynomials are evaluated with Horner's method to minimise floating-point rounding.

Method table and module init (lines 111 to 145)

cpython 3.14 @ ab2d84fe1023/Modules/_statisticsmodule.c#L111-145

The method table has a single entry using METH_O (one positional argument, no keyword arguments). The module struct uses the PyModuleDef_HEAD_INIT macro and carries no per-module state. PyInit__statistics is the sole exported symbol; it creates the module, adds no constants, and returns immediately.

static PyMethodDef statistics_methods[] = {
{"_normal_dist_inv_cdf", statistics__normal_dist_inv_cdf,
METH_O, NULL},
{NULL, NULL}
};

PyMODINIT_FUNC
PyInit__statistics(void)
{
return PyModule_Create(&statisticsmodule);
}

Error handling for out-of-domain input (lines 60 to 80)

cpython 3.14 @ ab2d84fe1023/Modules/_statisticsmodule.c#L60-80

Before entering either approximation branch the function validates the input. A non-finite or out-of-[0,1] probability is rejected with a StatisticsError raised via PyErr_Format. The check uses !isfinite(p) from <math.h> rather than explicit isinf / isnan tests, which covers both cases in one branch. The StatisticsError class is obtained at runtime by importing statistics and fetching its StatisticsError attribute, so the C module does not define or own the exception type.

if (!isfinite(p) || p <= 0.0 || p >= 1.0) {
PyErr_Format(PyExc_ValueError,
"p must be in the open interval (0, 1)");
return NULL;
}

gopy mirror

_statisticsmodule.c has no gopy port and is unlikely to need one soon. The statistics module is pure Python for all gopy purposes; the C accelerator is an optional performance detail. If the probit function ever becomes a bottleneck, the equivalent Go code is three constants arrays plus a Horner evaluator, all inlinable in a single file under module/statistics/. No CPython internal APIs are used, so the port would be a straight mathematical translation.

CPython 3.14 changes

CPython 3.14 converted _statisticsmodule.c to the argument clinic (Modules/clinic/_statisticsmodule.c.h). The hand-written argument parsing in _statistics__normal_dist_inv_cdf was replaced by a clinic-generated wrapper that handles type checking and the METH_O dispatch automatically. The visible behaviour is unchanged; the change purely reduces boilerplate and aligns the file with CPython's ongoing clinic migration effort.