Skip to content

Commit

Permalink
address review:
Browse files Browse the repository at this point in the history
* more tests for multiplication
* rename to _Py_convert_int_to_double
* rename to real_to_float/complex
* slightly optimize code
  • Loading branch information
skirpichev committed Oct 2, 2024
1 parent db12274 commit e4fc322
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Include/internal/pycore_floatobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
52 changes: 26 additions & 26 deletions Objects/complexobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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) {
Expand Down
10 changes: 5 additions & 5 deletions Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit e4fc322

Please sign in to comment.