Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-69639: add mixed-mode rules for complex arithmetic (C-like) #124829

Merged
merged 29 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3980363
gh-69639: add mixed-mode rules for complex arithmetic (C-like)
skirpichev Apr 23, 2024
46521c3
address review:
skirpichev Oct 2, 2024
1323f4d
Update Objects/complexobject.c
skirpichev Oct 2, 2024
5021a9b
address review: -> real_to_double
skirpichev Oct 2, 2024
c7308ef
Add _Py_cd_* and _Py_dc_* functions
skirpichev Oct 2, 2024
ee1aa01
+ what's new
skirpichev Oct 2, 2024
da566dd
+ trying to document new coersion rules in the reference
skirpichev Oct 2, 2024
714b731
address review: expressions.rst
skirpichev Oct 3, 2024
7a04eb0
address review: reword what's new
skirpichev Oct 3, 2024
1d42c10
cleanup: just one macro
skirpichev Oct 4, 2024
d6e9d14
renamed c-api helpers: _dc_ -> _rc_ and _cd_ -> _cr_
skirpichev Oct 6, 2024
2db0072
1d42c10202 +1
skirpichev Oct 6, 2024
46bed69
+ tests for semi-private C-API
skirpichev Oct 6, 2024
d6e4504
Merge branch 'master' into complex-float-arith-69639
skirpichev Oct 6, 2024
cc298e5
Apply suggestions from code review
skirpichev Oct 8, 2024
ee22926
Apply suggestions from code review
skirpichev Oct 13, 2024
220c551
Apply suggestions from code review
skirpichev Oct 14, 2024
f068384
Apply suggestions from code review
skirpichev Oct 14, 2024
8cdd514
Merge branch 'main' into complex-float-arith-69639
skirpichev Oct 30, 2024
7fb1be1
+ move news
skirpichev Oct 30, 2024
badf492
address review:
skirpichev Oct 31, 2024
3ef5287
Merge branch 'master' into complex-float-arith-69639
skirpichev Oct 31, 2024
38762b3
address review: rename symbols in commentary to avoid clash with macro
skirpichev Oct 31, 2024
e685bd9
Update Objects/complexobject.c
skirpichev Oct 31, 2024
76bad15
Merge branch 'main' into complex-float-arith-69639
skirpichev Nov 19, 2024
de5f353
Merge branch 'master' into complex-float-arith-69639
skirpichev Nov 26, 2024
2b46a96
added sum() test
skirpichev Nov 26, 2024
759a6d0
Update Lib/test/test_builtin.py
serhiy-storchaka Nov 26, 2024
ed67dc2
I'LL NEVER USE WEB-EDITOR... I'LL NEVER USE WEB-EDITOR... I'LL NEVER …
skirpichev Nov 26, 2024
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
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
10 changes: 6 additions & 4 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,12 @@ def test_sub(self):
def test_mul(self):
self.assertEqual(1j * int(20), complex(0, 20))
self.assertEqual(1j * int(-1), complex(0, -1))
self.assertComplexesAreIdentical(complex(INF, NAN) * 2,
complex(INF, NAN))
self.assertComplexesAreIdentical(2 * complex(INF, NAN),
complex(INF, NAN))
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, None, 1j)
Expand Down
35 changes: 17 additions & 18 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 @@ -475,31 +475,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)
skirpichev marked this conversation as resolved.
Show resolved Hide resolved
{
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)
picnixz marked this conversation as resolved.
Show resolved Hide resolved
{
pc->imag = 0.0;
return to_float(pobj, &(pc->real));
return real_to_float(pobj, &(pc->real));
}

/* Complex arithmetic rules implement special mixed-mode case: combining
Expand All @@ -523,7 +523,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 @@ -536,7 +536,7 @@ complex_add(PyObject *v, PyObject *w)
Py_complex b = ((PyComplexObject *)(w))->cval;
skirpichev marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -556,22 +556,21 @@ complex_sub(PyObject *v, PyObject *w)

if (PyComplex_Check(v)) {
a = ((PyComplexObject *)(v))->cval;
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 @@ -583,7 +582,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 @@ -596,7 +595,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 @@ -621,7 +620,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
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
Loading