From 503fd4a211b14054df3e5d9fbeb152c2fe354437 Mon Sep 17 00:00:00 2001 From: Paul Caprioli Date: Sun, 5 Jul 2026 11:58:17 -0700 Subject: [PATCH] gh-153144: Avoid checking `errno` for `atan2` --- Modules/cmathmodule.c | 6 +----- Modules/mathmodule.c | 45 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 7c736f4610bb988..b0b48c22cb87d5d 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1004,12 +1004,8 @@ cmath_phase_impl(PyObject *module, Py_complex z) { double phi; - errno = 0; phi = atan2(z.imag, z.real); /* should not cause any exception */ - if (errno != 0) - return math_error(); - else - return PyFloat_FromDouble(phi); + return PyFloat_FromDouble(phi); } /*[clinic input] diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 64e5372d73d2f29..34afed55bde3bb3 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -916,7 +916,7 @@ is_error(double x, int raise_edom) C89 but for which HUGE_VAL is not an infinity. For the majority of one-argument functions these rules are enough - to ensure that Python's functions behave as specified in 'Annex F' + to ensure that Python's functions behave as specified in Annex F of the C99 standard, with the 'invalid' and 'divide-by-zero' floating-point exceptions mapping to Python's ValueError and the 'overflow' floating-point exception mapping to OverflowError. @@ -1011,12 +1011,11 @@ math_1a(PyObject *arg, double (*func) (double), const char *err_msg) The last rule is used to catch overflow on platforms which follow C89 but for which HUGE_VAL is not an infinity. - For most two-argument functions (copysign, fmod, hypot, atan2) - these rules are enough to ensure that Python's functions behave as - specified in 'Annex F' of the C99 standard, with the 'invalid' and - 'divide-by-zero' floating-point exceptions mapping to Python's - ValueError and the 'overflow' floating-point exception mapping to - OverflowError. + For most two-argument functions (copysign, fmod, hypot) these rules + are enough to ensure that Python's functions behave as specified in + Annex F of the C99 standard, with the 'invalid' and 'divide-by-zero' + floating-point exceptions mapping to Python's ValueError and the + 'overflow' floating-point exception mapping to OverflowError. */ static PyObject * @@ -1054,6 +1053,28 @@ math_2(PyObject *const *args, Py_ssize_t nargs, return PyFloat_FromDouble(r); } +/* variant of math_2, to be used when the function being wrapped is known NOT + to need error checking (i.e., no overflow, invalid, or divide-by-zero). */ + +static PyObject * +math_2ne(PyObject *const *args, Py_ssize_t nargs, + double (*func) (double, double), const char *funcname) +{ + double x, y, r; + if (!_PyArg_CheckPositional(funcname, nargs, 2, 2)) + return NULL; + x = PyFloat_AsDouble(args[0]); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + y = PyFloat_AsDouble(args[1]); + if (y == -1.0 && PyErr_Occurred()) { + return NULL; + } + r = (*func)(x, y); + return PyFloat_FromDouble(r); +} + #define FUNC1(funcname, func, can_overflow, docstring) \ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ return math_1(args, func, can_overflow, NULL); \ @@ -1084,6 +1105,12 @@ math_2(PyObject *const *args, Py_ssize_t nargs, }\ PyDoc_STRVAR(math_##funcname##_doc, docstring); +#define FUNC2NE(funcname, func, docstring) \ + static PyObject * math_##funcname(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { \ + return math_2ne(args, nargs, func, #funcname); \ + }\ + PyDoc_STRVAR(math_##funcname##_doc, docstring); + FUNC1D(acos, acos, 0, "acos($module, x, /)\n--\n\n" "Return the arc cosine (measured in radians) of x.\n\n" @@ -1115,11 +1142,11 @@ FUNC1(atan, atan, 0, "atan($module, x, /)\n--\n\n" "Return the arc tangent (measured in radians) of x.\n\n" "The result is between -pi/2 and pi/2.") -FUNC2(atan2, atan2, +FUNC2NE(atan2, atan2, "atan2($module, y, x, /)\n--\n\n" "Return the arc tangent (measured in radians) of y/x.\n\n" "Unlike atan(y/x), the signs of both x and y are considered.") -FUNC2(atan2pi, m_atan2pi, +FUNC2NE(atan2pi, m_atan2pi, "atan2pi($module, y, x, /)\n--\n\n" "Return the arc tangent (measured in half-turns) of y/x.\n\n" "Unlike atanpi(y/x), the signs of both x and y are considered.")