Commit 0d2fac1f authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().

parent 94870434
from test.test_support import run_unittest from test.test_support import run_unittest, cpython_only
from test.test_math import parse_testfile, test_file from test.test_math import parse_testfile, test_file
import unittest import unittest
import cmath, math import cmath, math
...@@ -351,17 +351,48 @@ class CMathTests(unittest.TestCase): ...@@ -351,17 +351,48 @@ class CMathTests(unittest.TestCase):
self.rAssertAlmostEqual(expected.imag, actual.imag, self.rAssertAlmostEqual(expected.imag, actual.imag,
msg=error_message) msg=error_message)
def assertCISEqual(self, a, b): def check_polar(self, func):
eps = 1E-7 def check(arg, expected):
if abs(a[0] - b[0]) > eps or abs(a[1] - b[1]) > eps: got = func(arg)
self.fail((a ,b)) for e, g in zip(expected, got):
self.rAssertAlmostEqual(e, g)
check(0, (0., 0.))
check(1, (1., 0.))
check(-1, (1., pi))
check(1j, (1., pi / 2))
check(-3j, (3., -pi / 2))
inf = float('inf')
check(complex(inf, 0), (inf, 0.))
check(complex(-inf, 0), (inf, pi))
check(complex(3, inf), (inf, pi / 2))
check(complex(5, -inf), (inf, -pi / 2))
check(complex(inf, inf), (inf, pi / 4))
check(complex(inf, -inf), (inf, -pi / 4))
check(complex(-inf, inf), (inf, 3 * pi / 4))
check(complex(-inf, -inf), (inf, -3 * pi / 4))
nan = float('nan')
check(complex(nan, 0), (nan, nan))
check(complex(0, nan), (nan, nan))
check(complex(nan, nan), (nan, nan))
check(complex(inf, nan), (inf, nan))
check(complex(-inf, nan), (inf, nan))
check(complex(nan, inf), (inf, nan))
check(complex(nan, -inf), (inf, nan))
def test_polar(self): def test_polar(self):
self.assertCISEqual(polar(0), (0., 0.)) self.check_polar(polar)
self.assertCISEqual(polar(1.), (1., 0.))
self.assertCISEqual(polar(-1.), (1., pi)) @cpython_only
self.assertCISEqual(polar(1j), (1., pi/2)) def test_polar_errno(self):
self.assertCISEqual(polar(-1j), (1., -pi/2)) # Issue #24489: check a previously set C errno doesn't disturb polar()
from _testcapi import set_errno
def polar_with_errno_set(z):
set_errno(11)
try:
return polar(z)
finally:
set_errno(0)
self.check_polar(polar_with_errno_set)
def test_phase(self): def test_phase(self):
self.assertAlmostEqual(phase(0), 0.) self.assertAlmostEqual(phase(0), 0.)
......
+++++++++++ +++++++++++
Python News Python News
+++++++++++ +++++++++++
...@@ -30,6 +30,8 @@ Core and Builtins ...@@ -30,6 +30,8 @@ Core and Builtins
Library Library
------- -------
- Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
- Issue #19543: io.TextIOWrapper (and hence io.open()) now uses the internal - Issue #19543: io.TextIOWrapper (and hence io.open()) now uses the internal
codec marking system added to emit deprecation warning for known non-text codec marking system added to emit deprecation warning for known non-text
encodings at stream construction time when Python is ran with the -3 option. encodings at stream construction time when Python is ran with the -3 option.
......
...@@ -1373,6 +1373,17 @@ raise_exception(PyObject *self, PyObject *args) ...@@ -1373,6 +1373,17 @@ raise_exception(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
static PyObject *
set_errno(PyObject *self, PyObject *args)
{
int new_errno;
if (!PyArg_ParseTuple(args, "i:set_errno", &new_errno))
return NULL;
errno = new_errno;
Py_RETURN_NONE;
}
static int test_run_counter = 0; static int test_run_counter = 0;
...@@ -2032,6 +2043,7 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args) ...@@ -2032,6 +2043,7 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args)
static PyMethodDef TestMethods[] = { static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS},
{"set_errno", set_errno, METH_VARARGS},
{"test_config", (PyCFunction)test_config, METH_NOARGS}, {"test_config", (PyCFunction)test_config, METH_NOARGS},
{"test_datetime_capi", test_datetime_capi, METH_NOARGS}, {"test_datetime_capi", test_datetime_capi, METH_NOARGS},
{"test_list_api", (PyCFunction)test_list_api, METH_NOARGS}, {"test_list_api", (PyCFunction)test_list_api, METH_NOARGS},
......
...@@ -941,9 +941,10 @@ cmath_polar(PyObject *self, PyObject *args) ...@@ -941,9 +941,10 @@ cmath_polar(PyObject *self, PyObject *args)
double r, phi; double r, phi;
if (!PyArg_ParseTuple(args, "D:polar", &z)) if (!PyArg_ParseTuple(args, "D:polar", &z))
return NULL; return NULL;
errno = 0;
PyFPE_START_PROTECT("polar function", return 0) PyFPE_START_PROTECT("polar function", return 0)
phi = c_atan2(z); /* should not cause any exception */ phi = c_atan2(z); /* should not cause any exception */
r = c_abs(z); /* sets errno to ERANGE on overflow; otherwise 0 */ r = c_abs(z); /* sets errno to ERANGE on overflow */
PyFPE_END_PROTECT(r) PyFPE_END_PROTECT(r)
if (errno != 0) if (errno != 0)
return math_error(); return math_error();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment