Visitar URL original
gh-153144: Avoid checking `errno` for `atan2` by hpkfft · Pull Request #153148 · python/cpython · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
gh-153144: Avoid checking errno for atan2
  • Loading branch information
hpkfft committed Jul 5, 2026
commit 503fd4a211b14054df3e5d9fbeb152c2fe354437
6 changes: 1 addition & 5 deletions Modules/cmathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Comment thread
hpkfft marked this conversation as resolved.
Outdated
if (errno != 0)
return math_error();
Comment thread
skirpichev marked this conversation as resolved.
else
return PyFloat_FromDouble(phi);
return PyFloat_FromDouble(phi);
}

/*[clinic input]
Expand Down
45 changes: 36 additions & 9 deletions Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
hpkfft marked this conversation as resolved.
Outdated
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.
Expand Down Expand Up @@ -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.
Comment thread
hpkfft marked this conversation as resolved.
Outdated
*/

static PyObject *
Expand Down Expand Up @@ -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). */
Comment on lines +1064 to +1065

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest expand this with atan2() example and remove other comments below.


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;
Comment thread
picnixz marked this conversation as resolved.
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);
Comment thread
hpkfft marked this conversation as resolved.
Outdated
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); \
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Comment thread
hpkfft marked this conversation as resolved.
"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.")
Expand Down
Loading