Skip to main content

Modules/cmathmodule.c

cpython 3.14 @ ab2d84fe1023/Modules/cmathmodule.c

cmathmodule.c is the C implementation of the cmath standard library module. It provides transcendental and trigonometric functions for complex numbers, as well as phase, polar/rectangular conversion, and IEEE 754 predicates.

The file is organized as follows:

  • Elementary functions (sqrt, exp, log) that require careful handling of Inf and NaN operands.
  • Trigonometric functions (sin, cos, tan, asin, acos, atan) which are derived from the hyperbolic functions via the identities sin(z) = -i * sinh(iz) and so on.
  • Hyperbolic functions (sinh, cosh, tanh, asinh, acosh, atanh) which are the primary implementations because their branch cuts are simpler to reason about.
  • Utility functions (phase, polar, rect, isfinite, isinf, isnan, isclose) and the module constants.

CPython follows the C99 Annex G recommendations for complex arithmetic throughout this file. Infinite and NaN inputs are handled by explicit if/else trees rather than relying on hardware propagation, because hardware behaviour for complex operations varies across platforms.

Map

LinesSymbolRolegopy
1-200cmath_sqrt, cmath_exp, cmath_logSquare root, exponential, and natural log with NaN/Inf branch tables.module/cmath/
200-500cmath_sin, cmath_cos, cmath_tan, cmath_asin, cmath_acos, cmath_atanCircular trig functions; derived from hyperbolic via axis rotation.module/cmath/
500-700cmath_sinh, cmath_cosh, cmath_tanh, cmath_asinh, cmath_acosh, cmath_atanhHyperbolic functions, primary implementations for the trig functions above.module/cmath/
700-900cmath_phase, cmath_polar, cmath_rect, cmath_isfinite, cmath_isinf, cmath_isnan, cmath_isclose, module constants, PyInit_cmathUtility functions, the pi/e/tau/inf/nan constants, and module entry point.module/cmath/

Reading

cmath_sqrt branch cuts (lines 1 to 200)

cpython 3.14 @ ab2d84fe1023/Modules/cmathmodule.c#L1-200

sqrt(z) for z = x + iy uses the formula from Numerical Recipes in C. The real part is computed as r = sqrt((|z| + |x|) / 2) and the imaginary part as i = y / (2*r). This form avoids catastrophic cancellation near the negative real axis, which is the branch cut for complex square root.

The special-value table handles all combinations of finite, infinite, and NaN inputs explicitly:

static Py_complex
c_sqrt(Py_complex z)
{
Py_complex r;
double ax, s;

if (!Py_IS_FINITE(z.real) || !Py_IS_FINITE(z.imag)) {
if (Py_IS_INFINITY(z.imag))
return cmath_special_value(z, sqrt_special_values);
if (Py_IS_INFINITY(z.real)) {
if (z.real > 0.0) {
r.real = z.real;
r.imag = copysign(0.0, z.imag);
} else {
r.real = copysign(0.0, z.imag);
r.imag = copysign(z.real == -Py_HUGE_VAL
? Py_HUGE_VAL : 0.0, z.imag);
}
return r;
}
r.real = r.imag = Py_NAN;
return r;
}

/* Normal case. */
ax = fabs(z.real);
s = sqrt((cmath_hypot(ax, fabs(z.imag)) + ax) * 0.5);
if (z.real >= 0.0) {
r.real = s;
r.imag = (s == 0.0) ? 0.0 : z.imag / (2.0 * s);
} else {
r.real = (s == 0.0) ? 0.0 : fabs(z.imag) / (2.0 * s);
r.imag = copysign(s, z.imag);
}
return r;
}

The branch cut is the negative real axis. On that cut, sqrt returns a result with non-negative imaginary part, matching the mathematical principal value.

cmath_exp with Inf/NaN propagation (lines 1 to 200)

cpython 3.14 @ ab2d84fe1023/Modules/cmathmodule.c#L1-200

exp(x + iy) = e^x * (cos y + i sin y). When x is infinite or y is NaN the individual component formulas produce undefined results, so CPython again uses an explicit special-value lookup table:

static Py_complex
c_exp(Py_complex z)
{
Py_complex r;
double l;

if (!Py_IS_FINITE(z.real) || !Py_IS_FINITE(z.imag)) {
if (Py_IS_INFINITY(z.real) && Py_IS_FINITE(z.imag) && z.imag != 0.) {
if (z.real > 0) {
r.real = copysign(Py_HUGE_VAL, cos(z.imag));
r.imag = copysign(Py_HUGE_VAL, sin(z.imag));
} else {
r.real = copysign(0., cos(z.imag));
r.imag = copysign(0., sin(z.imag));
}
return r;
}
return cmath_special_value(z, exp_special_values);
}

l = exp(z.real);
r.real = l * cos(z.imag);
r.imag = l * sin(z.imag);
return r;
}

cmath_special_value indexes a 3x3 lookup table (negative-inf, finite, positive-inf for each component) to return the mathematically correct result for each degenerate case without triggering IEEE 754 exceptions.

cmath_phase, cmath_polar, cmath_rect (lines 700 to 900)

cpython 3.14 @ ab2d84fe1023/Modules/cmathmodule.c#L700-900

These three functions implement the conversion between rectangular and polar form:

/* phase(z) = atan2(z.imag, z.real) */
static PyObject *
cmath_phase(PyObject *module, PyObject *arg)
{
Py_complex z;
if (!PyArg_Parse(arg, "D:phase", &z)) return NULL;
return PyFloat_FromDouble(atan2(z.imag, z.real));
}

/* polar(z) -> (r, phi) where r = abs(z), phi = phase(z) */
static PyObject *
cmath_polar(PyObject *module, PyObject *arg)
{
Py_complex z;
double r, phi;
if (!PyArg_Parse(arg, "D:polar", &z)) return NULL;
r = cmath_hypot(z.real, z.imag);
phi = atan2(z.imag, z.real);
return Py_BuildValue("dd", r, phi);
}

/* rect(r, phi) -> r * exp(i*phi) = r*cos(phi) + i*r*sin(phi) */
static PyObject *
cmath_rect(PyObject *module, PyObject *args)
{
double r, phi;
if (!PyArg_ParseTuple(args, "dd:rect", &r, &phi)) return NULL;
if (!Py_IS_FINITE(r) || !Py_IS_FINITE(phi)) {
/* special value handling omitted for brevity */
}
return PyComplex_FromDoubles(r * cos(phi), r * sin(phi));
}

phase is a thin wrapper over atan2, which already handles the positive-zero / negative-zero sign on both axes correctly.

gopy mirror

module/cmath/ (pending). Each function maps to a Go function that accepts and returns complex128. The special-value lookup tables map to Go switch blocks on math.IsInf/math.IsNaN conditions. Phase, Polar, and Rect delegate to math.Atan2, math.Hypot, math.Cos, and math.Sin. IsClose mirrors the CPython formula abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol).

CPython 3.14 changes

cmathmodule.c has been stable since the branch-cut corrections landed in 3.2 (following recommendations from Kahan and Hull et al.). The isclose function was added in 3.5. The tau constant and infj/nanj complex constants were added in 3.6. No structural changes between 3.12 and 3.14.