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 ofInfandNaNoperands. - Trigonometric functions (
sin,cos,tan,asin,acos,atan) which are derived from the hyperbolic functions via the identitiessin(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
| Lines | Symbol | Role | gopy |
|---|---|---|---|
| 1-200 | cmath_sqrt, cmath_exp, cmath_log | Square root, exponential, and natural log with NaN/Inf branch tables. | module/cmath/ |
| 200-500 | cmath_sin, cmath_cos, cmath_tan, cmath_asin, cmath_acos, cmath_atan | Circular trig functions; derived from hyperbolic via axis rotation. | module/cmath/ |
| 500-700 | cmath_sinh, cmath_cosh, cmath_tanh, cmath_asinh, cmath_acosh, cmath_atanh | Hyperbolic functions, primary implementations for the trig functions above. | module/cmath/ |
| 700-900 | cmath_phase, cmath_polar, cmath_rect, cmath_isfinite, cmath_isinf, cmath_isnan, cmath_isclose, module constants, PyInit_cmath | Utility 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.