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-112019: Add Py_complex_abs() function #112107

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
34 changes: 28 additions & 6 deletions Doc/c-api/complex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,31 @@ pointers. This is consistent throughout the API.
} Py_complex;


.. c:function:: Py_complex _Py_c_sum(Py_complex left, Py_complex right)
.. c:function:: Py_complex Py_complex_sum(Py_complex left, Py_complex right)

Return the sum of two complex numbers, using the C :c:type:`Py_complex`
representation.


.. c:function:: Py_complex _Py_c_diff(Py_complex left, Py_complex right)
.. c:function:: Py_complex Py_complex_diff(Py_complex left, Py_complex right)

Return the difference between two complex numbers, using the C
:c:type:`Py_complex` representation.


.. c:function:: Py_complex _Py_c_neg(Py_complex num)
.. c:function:: Py_complex Py_complex_neg(Py_complex num)

Return the negation of the complex number *num*, using the C
:c:type:`Py_complex` representation.


.. c:function:: Py_complex _Py_c_prod(Py_complex left, Py_complex right)
.. c:function:: Py_complex Py_complex_prod(Py_complex left, Py_complex right)

Return the product of two complex numbers, using the C :c:type:`Py_complex`
representation.


.. c:function:: Py_complex _Py_c_quot(Py_complex dividend, Py_complex divisor)
.. c:function:: Py_complex Py_complex_quot(Py_complex dividend, Py_complex divisor)

Return the quotient of two complex numbers, using the C :c:type:`Py_complex`
representation.
Expand All @@ -67,7 +67,7 @@ pointers. This is consistent throughout the API.
:c:data:`errno` to :c:macro:`!EDOM`.


.. c:function:: Py_complex _Py_c_pow(Py_complex num, Py_complex exp)
.. c:function:: Py_complex Py_complex_pow(Py_complex num, Py_complex exp)

Return the exponentiation of *num* by *exp*, using the C :c:type:`Py_complex`
representation.
Expand All @@ -76,6 +76,28 @@ pointers. This is consistent throughout the API.
this method returns zero and sets :c:data:`errno` to :c:macro:`!EDOM`.


.. c:function:: double Py_complex_abs(Py_complex num)

Return the absolute value (or modulus or magnitude) of *num*, using the C
:c:type:`Py_complex` representation.

.. versionadded:: 3.5


In Python 3.13, these functions have been made public. Previously, they were
known as these private functions:

* ``Py_complex_sum()``: ``_Py_c_sum()``
* ``Py_complex_diff()``: ``_Py_c_diff()``
* ``Py_complex_neg()``: ``_Py_c_neg()``
* ``Py_complex_prod()``: ``_Py_c_prod()``
* ``Py_complex_quot()``: ``_Py_c_quot()``
* ``Py_complex_pow()``: ``_Py_c_pow()``
* ``Py_complex_abs()``: ``_Py_c_abs()``

Old names are kept for backward compatibility.


Complex Numbers as Python Objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
14 changes: 14 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,20 @@ New Features
:exc:`KeyError` if the key missing.
(Contributed by Stefan Behnel and Victor Stinner in :gh:`111262`.)

* Add public functions operating on ``Py_complex`` numbers:

* :c:func:`Py_complex_sum`: previously known as ``_Py_c_sum()``
* :c:func:`Py_complex_diff`: previously known as ``_Py_c_diff()``
* :c:func:`Py_complex_neg`: previously known as ``_Py_c_neg()``
* :c:func:`Py_complex_prod`: previously known as ``_Py_c_prod()``
* :c:func:`Py_complex_quot`: previously known as ``_Py_c_quot()``
* :c:func:`Py_complex_pow`: previously known as ``_Py_c_pow()``
* :c:func:`Py_complex_abs`: previously known as ``_Py_c_abs()``

The old names with the ``_Py_c`` prefix are kept for backward compatibility.

(Contributed by Victor Stinner in :gh:`111481`.)


Porting to Python 3.13
----------------------
Expand Down
19 changes: 19 additions & 0 deletions Include/cpython/complexobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ typedef struct {
double imag;
} Py_complex;

// Operations on complex numbers.
PyAPI_FUNC(Py_complex) Py_complex_sum(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) Py_complex_diff(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) Py_complex_neg(Py_complex);
PyAPI_FUNC(Py_complex) Py_complex_prod(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) Py_complex_quot(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) Py_complex_pow(Py_complex, Py_complex);
PyAPI_FUNC(double) Py_complex_abs(Py_complex);

// Keep old Python 3.12 names as aliases to new functions
#define _Py_c_sum Py_complex_sum
#define _Py_c_diff Py_complex_diff
#define _Py_c_neg Py_complex_neg
#define _Py_c_prod Py_complex_prod
#define _Py_c_quot Py_complex_quot
#define _Py_c_pow Py_complex_pow
#define _Py_c_abs Py_complex_abs


/* Complex object interface */

/*
Expand Down
10 changes: 0 additions & 10 deletions Include/internal/pycore_complexobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,6 @@ extern "C" {

#include "pycore_unicodeobject.h" // _PyUnicodeWriter

// Operations on complex numbers.
// Export functions for 'cmath' shared extension.
PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex);
PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex);
PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex);
PyAPI_FUNC(double) _Py_c_abs(Py_complex);

/* Format the object based on the format_spec, as defined in PEP 3101
(Advanced String Formatting). */
extern int _PyComplex_FormatAdvancedWriter(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Add public functions operating on ``Py_complex`` numbers:

* :c:func:`Py_complex_sum`: previously known as ``_Py_c_sum()``
* :c:func:`Py_complex_diff`: previously known as ``_Py_c_diff()``
* :c:func:`Py_complex_neg`: previously known as ``_Py_c_neg()``
* :c:func:`Py_complex_prod`: previously known as ``_Py_c_prod()``
* :c:func:`Py_complex_quot`: previously known as ``_Py_c_quot()``
* :c:func:`Py_complex_pow`: previously known as ``_Py_c_pow()``
* :c:func:`Py_complex_abs`: previously known as ``_Py_c_abs()``

The old names with the ``_Py_c`` prefix are kept for backward compatibility.
47 changes: 47 additions & 0 deletions Modules/_testcapi/complex.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,52 @@ complex_asccomplex(PyObject *Py_UNUSED(module), PyObject *obj)
}


static PyObject *
test_py_complex(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
// Basic tests on Py_complex functions:
//
// - Py_complex_sum()
// - Py_complex_diff()
// - Py_complex_neg()
// - Py_complex_prod()
// - Py_complex_quot()
// - Py_complex_pow()
// - Py_complex_abs()

Py_complex a = {1.0, 5.0};
Py_complex b = {1.5, 0.5};
Py_complex x = Py_complex_sum(a, b);
assert(x.real == 2.5 && x.imag == 5.5);

x = Py_complex_diff(a, b);
assert(x.real == -0.5 && x.imag == 4.5);

x = Py_complex_neg(a);
assert(x.real == -1.0 && x.imag == -5.0);

a = (Py_complex){1.0, -2.0};
b = (Py_complex){3.0, 4.0};
x = Py_complex_prod(a, b);
assert(x.real == 11.0 && x.imag == -2.0);

a = (Py_complex){6.9, -3.2};
x = Py_complex_quot(a, a);
assert(x.real == 1.0 && x.imag == 0.0);

a = (Py_complex){1.3, 2.7};
Py_complex zero = {0.0, 0.0};
x = Py_complex_pow(a, zero);
assert(x.real == 1.0 && x.imag == 0.0);

x = (Py_complex){3.0, 4.0};
double mod = Py_complex_abs(x);
assert(mod == hypot(3.0, 4.0));

Py_RETURN_NONE;
}


static PyMethodDef test_methods[] = {
{"complex_check", complex_check, METH_O},
{"complex_checkexact", complex_checkexact, METH_O},
Expand All @@ -94,6 +140,7 @@ static PyMethodDef test_methods[] = {
{"complex_realasdouble", complex_realasdouble, METH_O},
{"complex_imagasdouble", complex_imagasdouble, METH_O},
{"complex_asccomplex", complex_asccomplex, METH_O},
{"test_py_complex", test_py_complex, METH_NOARGS},
{NULL},
};

Expand Down
13 changes: 6 additions & 7 deletions Modules/cmathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#endif

#include "Python.h"
#include "pycore_complexobject.h" // _Py_c_neg()
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
/* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from
float.h. We assume that FLT_RADIX is either 2 or 16. */
Expand Down Expand Up @@ -374,7 +373,7 @@ cmath_atanh_impl(PyObject *module, Py_complex z)

/* Reduce to case where z.real >= 0., using atanh(z) = -atanh(-z). */
if (z.real < 0.) {
return _Py_c_neg(cmath_atanh_impl(module, _Py_c_neg(z)));
return Py_complex_neg(cmath_atanh_impl(module, Py_complex_neg(z)));
}

ay = fabs(z.imag);
Expand Down Expand Up @@ -927,7 +926,7 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj)
return NULL;
}
y = c_log(y);
x = _Py_c_quot(x, y);
x = Py_complex_quot(x, y);
}
if (errno != 0)
return math_error();
Expand Down Expand Up @@ -992,7 +991,7 @@ cmath_polar_impl(PyObject *module, Py_complex z)

errno = 0;
phi = c_atan2(z); /* should not cause any exception */
r = _Py_c_abs(z); /* sets errno to ERANGE on overflow */
r = Py_complex_abs(z); /* sets errno to ERANGE on overflow */
if (errno != 0)
return math_error();
else
Expand Down Expand Up @@ -1176,10 +1175,10 @@ cmath_isclose_impl(PyObject *module, Py_complex a, Py_complex b,
this is essentially the "weak" test from the Boost library
*/

diff = _Py_c_abs(_Py_c_diff(a, b));
diff = Py_complex_abs(Py_complex_diff(a, b));

return (((diff <= rel_tol * _Py_c_abs(b)) ||
(diff <= rel_tol * _Py_c_abs(a))) ||
return (((diff <= rel_tol * Py_complex_abs(b)) ||
(diff <= rel_tol * Py_complex_abs(a))) ||
(diff <= abs_tol));
}

Expand Down
Loading
Loading