From e4fc322604e2194b446dded0da12b5d9cc9f8795 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 2 Oct 2024 05:27:51 +0300 Subject: [PATCH] address review: * more tests for multiplication * rename to _Py_convert_int_to_double * rename to real_to_float/complex * slightly optimize code --- Include/internal/pycore_floatobject.h | 2 +- Lib/test/test_complex.py | 6 ++++ Objects/complexobject.c | 52 +++++++++++++-------------- Objects/floatobject.c | 10 +++--- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index fd52fe006392b2..f44b081b06cea5 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -54,7 +54,7 @@ extern PyObject* _Py_string_to_number_with_underscores( extern double _Py_parse_inf_or_nan(const char *p, char **endptr); -extern int _Py_convert_to_double(PyObject **v, double *dbl); +extern int _Py_convert_int_to_double(PyObject **v, double *dbl); #ifdef __cplusplus diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index f8ac15d2fc4813..545b696b04ad24 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -302,6 +302,12 @@ def test_mul(self): self.assertEqual(1j * int(20), complex(0, 20)) self.assertEqual(1j * int(-1), complex(0, -1)) self.assertEqual(2j * imaginary(3), -6.0) + for c, r in [(2, complex(INF, 2)), (INF, complex(INF, INF)), + (0, complex(NAN, 0)), (-0.0, complex(NAN, -0.0)), + (NAN, complex(NAN, NAN))]: + with self.subTest(c=c, r=r): + self.assertComplexesAreIdentical(complex(INF, 1) * c, r) + self.assertComplexesAreIdentical(c * complex(INF, 1), r) self.assertRaises(OverflowError, operator.mul, 1j, 10**1000) self.assertRaises(TypeError, operator.mul, 1j, None) self.assertRaises(TypeError, operator.mul, 1+1j, None) diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 50b41cfcce3195..f5b45ce5375370 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -8,7 +8,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter() -#include "pycore_floatobject.h" // _Py_convert_to_double() +#include "pycore_floatobject.h" // _Py_convert_int_to_double() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_object.h" // _PyObject_Init() #include "pycore_pymath.h" // _Py_ADJUST_ERANGE2() @@ -523,31 +523,31 @@ complex_hash(PyComplexObject *v) } /* This macro may return! */ -#define TO_COMPLEX(obj, c) \ - if (PyComplex_Check(obj)) \ - c = ((PyComplexObject *)(obj))->cval; \ - else if (to_complex(&(obj), &(c)) < 0) \ +#define TO_COMPLEX(obj, c) \ + if (PyComplex_Check(obj)) \ + c = ((PyComplexObject *)(obj))->cval; \ + else if (real_to_complex(&(obj), &(c)) < 0) \ return (obj) static int -to_float(PyObject **pobj, double *dbl) +real_to_float(PyObject **pobj, double *dbl) { PyObject *obj = *pobj; if (PyFloat_Check(obj)) { *dbl = PyFloat_AS_DOUBLE(obj); } - else if (_Py_convert_to_double(pobj, dbl) < 0) { + else if (_Py_convert_int_to_double(pobj, dbl) < 0) { return -1; } return 0; } static int -to_complex(PyObject **pobj, Py_complex *pc) +real_to_complex(PyObject **pobj, Py_complex *pc) { pc->imag = 0.0; - return to_float(pobj, &(pc->real)); + return real_to_float(pobj, &(pc->real)); } /* Complex arithmetic rules implement special mixed-mode cases, i.e. combining @@ -578,7 +578,7 @@ to_complex(PyObject **pobj, Py_complex *pc) static PyObject * complex_add(PyObject *v, PyObject *w) { - if (PyComplex_Check(w)) { + if (!PyComplex_Check(v)) { PyObject *tmp = v; v = w; w = tmp; @@ -591,7 +591,7 @@ complex_add(PyObject *v, PyObject *w) Py_complex b = ((PyComplexObject *)(w))->cval; a = _Py_c_sum(a, b); } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } else { @@ -614,19 +614,19 @@ complex_sub(PyObject *v, PyObject *w) errno = 0; a = _Py_c_diff(a, b); } - else if (to_float(&v, &a.real) < 0) { + else if (real_to_float(&v, &a.real) < 0) { return v; } else { - a = (Py_complex) {a.real, -b.imag}; a.real -= b.real; + a.imag = -b.imag; } } else { a = ((PyComplexObject *)(v))->cval; double b; - if (to_float(&w, &b) < 0) { + if (real_to_float(&w, &b) < 0) { return w; } a.real -= b; @@ -638,7 +638,7 @@ complex_sub(PyObject *v, PyObject *w) static PyObject * complex_mul(PyObject *v, PyObject *w) { - if (PyComplex_Check(w)) { + if (!PyComplex_Check(v)) { PyObject *tmp = v; v = w; w = tmp; @@ -651,7 +651,7 @@ complex_mul(PyObject *v, PyObject *w) Py_complex b = ((PyComplexObject *)(w))->cval; a = _Py_c_prod(a, b); } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } else { @@ -676,7 +676,7 @@ complex_div(PyObject *v, PyObject *w) a = ((PyComplexObject *)(v))->cval; a = _Py_c_quot(a, b); } - else if (to_float(&v, &a.real) < 0) { + else if (real_to_float(&v, &a.real) < 0) { return v; } else { @@ -686,7 +686,7 @@ complex_div(PyObject *v, PyObject *w) else { double b; - if (to_float(&w, &b) < 0) { + if (real_to_float(&w, &b) < 0) { return w; } if (b) { @@ -1483,7 +1483,7 @@ imaginary_pos(PyComplexObject *v) static PyObject * imaginary_add(PyObject *v, PyObject *w) { - if (PyImaginary_Check(w)) { + if (!PyImaginary_Check(v)) { PyObject *tmp = v; v = w; w = tmp; @@ -1496,7 +1496,7 @@ imaginary_add(PyObject *v, PyObject *w) a += ((PyComplexObject *)(w))->cval.imag; b = ((PyComplexObject *)(w))->cval.real; } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } @@ -1518,7 +1518,7 @@ imaginary_sub(PyObject *v, PyObject *w) a = ((PyComplexObject *)(v))->cval.real; b += ((PyComplexObject *)(v))->cval.imag; } - else if (to_float(&v, &a) < 0) { + else if (real_to_float(&v, &a) < 0) { return v; } return PyComplex_FromDoubles(a, b); @@ -1531,7 +1531,7 @@ imaginary_sub(PyObject *v, PyObject *w) a -= ((PyComplexObject *)(w))->cval.imag; b = ((PyComplexObject *)(w))->cval.real; } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } @@ -1541,7 +1541,7 @@ imaginary_sub(PyObject *v, PyObject *w) static PyObject * imaginary_mul(PyObject *v, PyObject *w) { - if (PyImaginary_Check(w)) { + if (!PyImaginary_Check(v)) { PyObject *tmp = v; v = w; w = tmp; @@ -1558,7 +1558,7 @@ imaginary_mul(PyObject *v, PyObject *w) a *= ((PyComplexObject *)(w))->cval.real; return PyComplex_FromDoubles(b, a); } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } @@ -1581,7 +1581,7 @@ imaginary_div(PyObject *v, PyObject *w) Py_complex a = ((PyComplexObject *)(v))->cval; return PyComplex_FromDoubles(a.imag/b, -a.real/b); } - if (to_float(&v, &a) < 0) { + if (real_to_float(&v, &a) < 0) { return v; } return PyImaginary_FromDouble(-a/b); @@ -1600,7 +1600,7 @@ imaginary_div(PyObject *v, PyObject *w) return PyComplex_FromDoubles(b.real, b.imag); } } - else if (to_float(&w, &b) < 0) { + else if (real_to_float(&w, &b) < 0) { return w; } else if (b) { diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 74903a0049f9e4..6859bd542dcb10 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -306,16 +306,16 @@ PyFloat_AsDouble(PyObject *op) obj is not of float or int type, Py_NotImplemented is incref'ed, stored in obj, and returned from the function invoking this macro. */ -#define CONVERT_TO_DOUBLE(obj, dbl) \ - if (PyFloat_Check(obj)) \ - dbl = PyFloat_AS_DOUBLE(obj); \ - else if (_Py_convert_to_double(&(obj), &(dbl)) < 0) \ +#define CONVERT_TO_DOUBLE(obj, dbl) \ + if (PyFloat_Check(obj)) \ + dbl = PyFloat_AS_DOUBLE(obj); \ + else if (_Py_convert_int_to_double(&(obj), &(dbl)) < 0) \ return obj; /* Methods */ int -_Py_convert_to_double(PyObject **v, double *dbl) +_Py_convert_int_to_double(PyObject **v, double *dbl) { PyObject *obj = *v;