mirror of
https://github.com/python/cpython.git
synced 2024-11-30 18:51:15 +01:00
1255 lines
36 KiB
C
1255 lines
36 KiB
C
|
|
/* Complex object implementation */
|
|
|
|
/* Borrows heavily from floatobject.c */
|
|
|
|
/* Submitted by Jim Hugunin */
|
|
|
|
#include "Python.h"
|
|
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
|
#include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter()
|
|
#include "pycore_long.h" // _PyLong_GetZero()
|
|
#include "pycore_object.h" // _PyObject_Init()
|
|
#include "pycore_pymath.h" // _Py_ADJUST_ERANGE2()
|
|
|
|
|
|
|
|
/*[clinic input]
|
|
class complex "PyComplexObject *" "&PyComplex_Type"
|
|
[clinic start generated code]*/
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=819e057d2d10f5ec]*/
|
|
|
|
#include "clinic/complexobject.c.h"
|
|
|
|
/* elementary operations on complex numbers */
|
|
|
|
static Py_complex c_1 = {1., 0.};
|
|
|
|
Py_complex
|
|
_Py_c_sum(Py_complex a, Py_complex b)
|
|
{
|
|
Py_complex r;
|
|
r.real = a.real + b.real;
|
|
r.imag = a.imag + b.imag;
|
|
return r;
|
|
}
|
|
|
|
Py_complex
|
|
_Py_c_diff(Py_complex a, Py_complex b)
|
|
{
|
|
Py_complex r;
|
|
r.real = a.real - b.real;
|
|
r.imag = a.imag - b.imag;
|
|
return r;
|
|
}
|
|
|
|
Py_complex
|
|
_Py_c_neg(Py_complex a)
|
|
{
|
|
Py_complex r;
|
|
r.real = -a.real;
|
|
r.imag = -a.imag;
|
|
return r;
|
|
}
|
|
|
|
Py_complex
|
|
_Py_c_prod(Py_complex a, Py_complex b)
|
|
{
|
|
Py_complex r;
|
|
r.real = a.real*b.real - a.imag*b.imag;
|
|
r.imag = a.real*b.imag + a.imag*b.real;
|
|
return r;
|
|
}
|
|
|
|
/* Avoid bad optimization on Windows ARM64 until the compiler is fixed */
|
|
#ifdef _M_ARM64
|
|
#pragma optimize("", off)
|
|
#endif
|
|
Py_complex
|
|
_Py_c_quot(Py_complex a, Py_complex b)
|
|
{
|
|
/******************************************************************
|
|
This was the original algorithm. It's grossly prone to spurious
|
|
overflow and underflow errors. It also merrily divides by 0 despite
|
|
checking for that(!). The code still serves a doc purpose here, as
|
|
the algorithm following is a simple by-cases transformation of this
|
|
one:
|
|
|
|
Py_complex r;
|
|
double d = b.real*b.real + b.imag*b.imag;
|
|
if (d == 0.)
|
|
errno = EDOM;
|
|
r.real = (a.real*b.real + a.imag*b.imag)/d;
|
|
r.imag = (a.imag*b.real - a.real*b.imag)/d;
|
|
return r;
|
|
******************************************************************/
|
|
|
|
/* This algorithm is better, and is pretty obvious: first divide the
|
|
* numerators and denominator by whichever of {b.real, b.imag} has
|
|
* larger magnitude. The earliest reference I found was to CACM
|
|
* Algorithm 116 (Complex Division, Robert L. Smith, Stanford
|
|
* University).
|
|
*/
|
|
Py_complex r; /* the result */
|
|
const double abs_breal = b.real < 0 ? -b.real : b.real;
|
|
const double abs_bimag = b.imag < 0 ? -b.imag : b.imag;
|
|
|
|
if (abs_breal >= abs_bimag) {
|
|
/* divide tops and bottom by b.real */
|
|
if (abs_breal == 0.0) {
|
|
errno = EDOM;
|
|
r.real = r.imag = 0.0;
|
|
}
|
|
else {
|
|
const double ratio = b.imag / b.real;
|
|
const double denom = b.real + b.imag * ratio;
|
|
r.real = (a.real + a.imag * ratio) / denom;
|
|
r.imag = (a.imag - a.real * ratio) / denom;
|
|
}
|
|
}
|
|
else if (abs_bimag >= abs_breal) {
|
|
/* divide tops and bottom by b.imag */
|
|
const double ratio = b.real / b.imag;
|
|
const double denom = b.real * ratio + b.imag;
|
|
assert(b.imag != 0.0);
|
|
r.real = (a.real * ratio + a.imag) / denom;
|
|
r.imag = (a.imag * ratio - a.real) / denom;
|
|
}
|
|
else {
|
|
/* At least one of b.real or b.imag is a NaN */
|
|
r.real = r.imag = Py_NAN;
|
|
}
|
|
|
|
/* Recover infinities and zeros that computed as nan+nanj. See e.g.
|
|
the C11, Annex G.5.2, routine _Cdivd(). */
|
|
if (isnan(r.real) && isnan(r.imag)) {
|
|
if ((isinf(a.real) || isinf(a.imag))
|
|
&& isfinite(b.real) && isfinite(b.imag))
|
|
{
|
|
const double x = copysign(isinf(a.real) ? 1.0 : 0.0, a.real);
|
|
const double y = copysign(isinf(a.imag) ? 1.0 : 0.0, a.imag);
|
|
r.real = Py_INFINITY * (x*b.real + y*b.imag);
|
|
r.imag = Py_INFINITY * (y*b.real - x*b.imag);
|
|
}
|
|
else if ((isinf(abs_breal) || isinf(abs_bimag))
|
|
&& isfinite(a.real) && isfinite(a.imag))
|
|
{
|
|
const double x = copysign(isinf(b.real) ? 1.0 : 0.0, b.real);
|
|
const double y = copysign(isinf(b.imag) ? 1.0 : 0.0, b.imag);
|
|
r.real = 0.0 * (a.real*x + a.imag*y);
|
|
r.imag = 0.0 * (a.imag*x - a.real*y);
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
#ifdef _M_ARM64
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
Py_complex
|
|
_Py_c_pow(Py_complex a, Py_complex b)
|
|
{
|
|
Py_complex r;
|
|
double vabs,len,at,phase;
|
|
if (b.real == 0. && b.imag == 0.) {
|
|
r.real = 1.;
|
|
r.imag = 0.;
|
|
}
|
|
else if (a.real == 0. && a.imag == 0.) {
|
|
if (b.imag != 0. || b.real < 0.)
|
|
errno = EDOM;
|
|
r.real = 0.;
|
|
r.imag = 0.;
|
|
}
|
|
else {
|
|
vabs = hypot(a.real,a.imag);
|
|
len = pow(vabs,b.real);
|
|
at = atan2(a.imag, a.real);
|
|
phase = at*b.real;
|
|
if (b.imag != 0.0) {
|
|
len /= exp(at*b.imag);
|
|
phase += b.imag*log(vabs);
|
|
}
|
|
r.real = len*cos(phase);
|
|
r.imag = len*sin(phase);
|
|
|
|
_Py_ADJUST_ERANGE2(r.real, r.imag);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static Py_complex
|
|
c_powu(Py_complex x, long n)
|
|
{
|
|
Py_complex r, p;
|
|
long mask = 1;
|
|
r = c_1;
|
|
p = x;
|
|
while (mask > 0 && n >= mask) {
|
|
if (n & mask)
|
|
r = _Py_c_prod(r,p);
|
|
mask <<= 1;
|
|
p = _Py_c_prod(p,p);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static Py_complex
|
|
c_powi(Py_complex x, long n)
|
|
{
|
|
if (n > 0)
|
|
return c_powu(x,n);
|
|
else
|
|
return _Py_c_quot(c_1, c_powu(x,-n));
|
|
|
|
}
|
|
|
|
double
|
|
_Py_c_abs(Py_complex z)
|
|
{
|
|
/* sets errno = ERANGE on overflow; otherwise errno = 0 */
|
|
double result;
|
|
|
|
if (!isfinite(z.real) || !isfinite(z.imag)) {
|
|
/* C99 rules: if either the real or the imaginary part is an
|
|
infinity, return infinity, even if the other part is a
|
|
NaN. */
|
|
if (isinf(z.real)) {
|
|
result = fabs(z.real);
|
|
errno = 0;
|
|
return result;
|
|
}
|
|
if (isinf(z.imag)) {
|
|
result = fabs(z.imag);
|
|
errno = 0;
|
|
return result;
|
|
}
|
|
/* either the real or imaginary part is a NaN,
|
|
and neither is infinite. Result should be NaN. */
|
|
return Py_NAN;
|
|
}
|
|
result = hypot(z.real, z.imag);
|
|
if (!isfinite(result))
|
|
errno = ERANGE;
|
|
else
|
|
errno = 0;
|
|
return result;
|
|
}
|
|
|
|
static PyObject *
|
|
complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
|
|
{
|
|
PyObject *op;
|
|
|
|
op = type->tp_alloc(type, 0);
|
|
if (op != NULL)
|
|
((PyComplexObject *)op)->cval = cval;
|
|
return op;
|
|
}
|
|
|
|
PyObject *
|
|
PyComplex_FromCComplex(Py_complex cval)
|
|
{
|
|
/* Inline PyObject_New */
|
|
PyComplexObject *op = PyObject_Malloc(sizeof(PyComplexObject));
|
|
if (op == NULL) {
|
|
return PyErr_NoMemory();
|
|
}
|
|
_PyObject_Init((PyObject*)op, &PyComplex_Type);
|
|
op->cval = cval;
|
|
return (PyObject *) op;
|
|
}
|
|
|
|
static PyObject *
|
|
complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
|
|
{
|
|
Py_complex c;
|
|
c.real = real;
|
|
c.imag = imag;
|
|
return complex_subtype_from_c_complex(type, c);
|
|
}
|
|
|
|
PyObject *
|
|
PyComplex_FromDoubles(double real, double imag)
|
|
{
|
|
Py_complex c;
|
|
c.real = real;
|
|
c.imag = imag;
|
|
return PyComplex_FromCComplex(c);
|
|
}
|
|
|
|
static PyObject * try_complex_special_method(PyObject *);
|
|
|
|
double
|
|
PyComplex_RealAsDouble(PyObject *op)
|
|
{
|
|
double real = -1.0;
|
|
|
|
if (PyComplex_Check(op)) {
|
|
real = ((PyComplexObject *)op)->cval.real;
|
|
}
|
|
else {
|
|
PyObject* newop = try_complex_special_method(op);
|
|
if (newop) {
|
|
real = ((PyComplexObject *)newop)->cval.real;
|
|
Py_DECREF(newop);
|
|
} else if (!PyErr_Occurred()) {
|
|
real = PyFloat_AsDouble(op);
|
|
}
|
|
}
|
|
|
|
return real;
|
|
}
|
|
|
|
double
|
|
PyComplex_ImagAsDouble(PyObject *op)
|
|
{
|
|
double imag = -1.0;
|
|
|
|
if (PyComplex_Check(op)) {
|
|
imag = ((PyComplexObject *)op)->cval.imag;
|
|
}
|
|
else {
|
|
PyObject* newop = try_complex_special_method(op);
|
|
if (newop) {
|
|
imag = ((PyComplexObject *)newop)->cval.imag;
|
|
Py_DECREF(newop);
|
|
} else if (!PyErr_Occurred()) {
|
|
PyFloat_AsDouble(op);
|
|
if (!PyErr_Occurred()) {
|
|
imag = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return imag;
|
|
}
|
|
|
|
static PyObject *
|
|
try_complex_special_method(PyObject *op)
|
|
{
|
|
PyObject *f;
|
|
|
|
f = _PyObject_LookupSpecial(op, &_Py_ID(__complex__));
|
|
if (f) {
|
|
PyObject *res = _PyObject_CallNoArgs(f);
|
|
Py_DECREF(f);
|
|
if (!res || PyComplex_CheckExact(res)) {
|
|
return res;
|
|
}
|
|
if (!PyComplex_Check(res)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"__complex__ returned non-complex (type %.200s)",
|
|
Py_TYPE(res)->tp_name);
|
|
Py_DECREF(res);
|
|
return NULL;
|
|
}
|
|
/* Issue #29894: warn if 'res' not of exact type complex. */
|
|
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
"__complex__ returned non-complex (type %.200s). "
|
|
"The ability to return an instance of a strict subclass of complex "
|
|
"is deprecated, and may be removed in a future version of Python.",
|
|
Py_TYPE(res)->tp_name)) {
|
|
Py_DECREF(res);
|
|
return NULL;
|
|
}
|
|
return res;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Py_complex
|
|
PyComplex_AsCComplex(PyObject *op)
|
|
{
|
|
Py_complex cv;
|
|
PyObject *newop = NULL;
|
|
|
|
assert(op);
|
|
/* If op is already of type PyComplex_Type, return its value */
|
|
if (PyComplex_Check(op)) {
|
|
return ((PyComplexObject *)op)->cval;
|
|
}
|
|
/* If not, use op's __complex__ method, if it exists */
|
|
|
|
/* return -1 on failure */
|
|
cv.real = -1.;
|
|
cv.imag = 0.;
|
|
|
|
newop = try_complex_special_method(op);
|
|
|
|
if (newop) {
|
|
cv = ((PyComplexObject *)newop)->cval;
|
|
Py_DECREF(newop);
|
|
return cv;
|
|
}
|
|
else if (PyErr_Occurred()) {
|
|
return cv;
|
|
}
|
|
/* If neither of the above works, interpret op as a float giving the
|
|
real part of the result, and fill in the imaginary part as 0. */
|
|
else {
|
|
/* PyFloat_AsDouble will return -1 on failure */
|
|
cv.real = PyFloat_AsDouble(op);
|
|
return cv;
|
|
}
|
|
}
|
|
|
|
static PyObject *
|
|
complex_repr(PyComplexObject *v)
|
|
{
|
|
int precision = 0;
|
|
char format_code = 'r';
|
|
PyObject *result = NULL;
|
|
|
|
/* If these are non-NULL, they'll need to be freed. */
|
|
char *pre = NULL;
|
|
char *im = NULL;
|
|
|
|
/* These do not need to be freed. re is either an alias
|
|
for pre or a pointer to a constant. lead and tail
|
|
are pointers to constants. */
|
|
const char *re = NULL;
|
|
const char *lead = "";
|
|
const char *tail = "";
|
|
|
|
if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) {
|
|
/* Real part is +0: just output the imaginary part and do not
|
|
include parens. */
|
|
re = "";
|
|
im = PyOS_double_to_string(v->cval.imag, format_code,
|
|
precision, 0, NULL);
|
|
if (!im) {
|
|
PyErr_NoMemory();
|
|
goto done;
|
|
}
|
|
} else {
|
|
/* Format imaginary part with sign, real part without. Include
|
|
parens in the result. */
|
|
pre = PyOS_double_to_string(v->cval.real, format_code,
|
|
precision, 0, NULL);
|
|
if (!pre) {
|
|
PyErr_NoMemory();
|
|
goto done;
|
|
}
|
|
re = pre;
|
|
|
|
im = PyOS_double_to_string(v->cval.imag, format_code,
|
|
precision, Py_DTSF_SIGN, NULL);
|
|
if (!im) {
|
|
PyErr_NoMemory();
|
|
goto done;
|
|
}
|
|
lead = "(";
|
|
tail = ")";
|
|
}
|
|
result = PyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail);
|
|
done:
|
|
PyMem_Free(im);
|
|
PyMem_Free(pre);
|
|
|
|
return result;
|
|
}
|
|
|
|
static Py_hash_t
|
|
complex_hash(PyComplexObject *v)
|
|
{
|
|
Py_uhash_t hashreal, hashimag, combined;
|
|
hashreal = (Py_uhash_t)_Py_HashDouble((PyObject *) v, v->cval.real);
|
|
if (hashreal == (Py_uhash_t)-1)
|
|
return -1;
|
|
hashimag = (Py_uhash_t)_Py_HashDouble((PyObject *)v, v->cval.imag);
|
|
if (hashimag == (Py_uhash_t)-1)
|
|
return -1;
|
|
/* Note: if the imaginary part is 0, hashimag is 0 now,
|
|
* so the following returns hashreal unchanged. This is
|
|
* important because numbers of different types that
|
|
* compare equal must have the same hash value, so that
|
|
* hash(x + 0*j) must equal hash(x).
|
|
*/
|
|
combined = hashreal + _PyHASH_IMAG * hashimag;
|
|
if (combined == (Py_uhash_t)-1)
|
|
combined = (Py_uhash_t)-2;
|
|
return (Py_hash_t)combined;
|
|
}
|
|
|
|
/* This macro may return! */
|
|
#define TO_COMPLEX(obj, c) \
|
|
if (PyComplex_Check(obj)) \
|
|
c = ((PyComplexObject *)(obj))->cval; \
|
|
else if (to_complex(&(obj), &(c)) < 0) \
|
|
return (obj)
|
|
|
|
static int
|
|
to_complex(PyObject **pobj, Py_complex *pc)
|
|
{
|
|
PyObject *obj = *pobj;
|
|
|
|
pc->real = pc->imag = 0.0;
|
|
if (PyLong_Check(obj)) {
|
|
pc->real = PyLong_AsDouble(obj);
|
|
if (pc->real == -1.0 && PyErr_Occurred()) {
|
|
*pobj = NULL;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
if (PyFloat_Check(obj)) {
|
|
pc->real = PyFloat_AsDouble(obj);
|
|
return 0;
|
|
}
|
|
*pobj = Py_NewRef(Py_NotImplemented);
|
|
return -1;
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
complex_add(PyObject *v, PyObject *w)
|
|
{
|
|
Py_complex result;
|
|
Py_complex a, b;
|
|
TO_COMPLEX(v, a);
|
|
TO_COMPLEX(w, b);
|
|
result = _Py_c_sum(a, b);
|
|
return PyComplex_FromCComplex(result);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_sub(PyObject *v, PyObject *w)
|
|
{
|
|
Py_complex result;
|
|
Py_complex a, b;
|
|
TO_COMPLEX(v, a);
|
|
TO_COMPLEX(w, b);
|
|
result = _Py_c_diff(a, b);
|
|
return PyComplex_FromCComplex(result);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_mul(PyObject *v, PyObject *w)
|
|
{
|
|
Py_complex result;
|
|
Py_complex a, b;
|
|
TO_COMPLEX(v, a);
|
|
TO_COMPLEX(w, b);
|
|
result = _Py_c_prod(a, b);
|
|
return PyComplex_FromCComplex(result);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_div(PyObject *v, PyObject *w)
|
|
{
|
|
Py_complex quot;
|
|
Py_complex a, b;
|
|
TO_COMPLEX(v, a);
|
|
TO_COMPLEX(w, b);
|
|
errno = 0;
|
|
quot = _Py_c_quot(a, b);
|
|
if (errno == EDOM) {
|
|
PyErr_SetString(PyExc_ZeroDivisionError, "division by zero");
|
|
return NULL;
|
|
}
|
|
return PyComplex_FromCComplex(quot);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_pow(PyObject *v, PyObject *w, PyObject *z)
|
|
{
|
|
Py_complex p;
|
|
Py_complex a, b;
|
|
TO_COMPLEX(v, a);
|
|
TO_COMPLEX(w, b);
|
|
|
|
if (z != Py_None) {
|
|
PyErr_SetString(PyExc_ValueError, "complex modulo");
|
|
return NULL;
|
|
}
|
|
errno = 0;
|
|
// Check whether the exponent has a small integer value, and if so use
|
|
// a faster and more accurate algorithm.
|
|
if (b.imag == 0.0 && b.real == floor(b.real) && fabs(b.real) <= 100.0) {
|
|
p = c_powi(a, (long)b.real);
|
|
_Py_ADJUST_ERANGE2(p.real, p.imag);
|
|
}
|
|
else {
|
|
p = _Py_c_pow(a, b);
|
|
}
|
|
|
|
if (errno == EDOM) {
|
|
PyErr_SetString(PyExc_ZeroDivisionError,
|
|
"zero to a negative or complex power");
|
|
return NULL;
|
|
}
|
|
else if (errno == ERANGE) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"complex exponentiation");
|
|
return NULL;
|
|
}
|
|
return PyComplex_FromCComplex(p);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_neg(PyComplexObject *v)
|
|
{
|
|
Py_complex neg;
|
|
neg.real = -v->cval.real;
|
|
neg.imag = -v->cval.imag;
|
|
return PyComplex_FromCComplex(neg);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_pos(PyComplexObject *v)
|
|
{
|
|
if (PyComplex_CheckExact(v)) {
|
|
return Py_NewRef(v);
|
|
}
|
|
else
|
|
return PyComplex_FromCComplex(v->cval);
|
|
}
|
|
|
|
static PyObject *
|
|
complex_abs(PyComplexObject *v)
|
|
{
|
|
double result;
|
|
|
|
result = _Py_c_abs(v->cval);
|
|
|
|
if (errno == ERANGE) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"absolute value too large");
|
|
return NULL;
|
|
}
|
|
return PyFloat_FromDouble(result);
|
|
}
|
|
|
|
static int
|
|
complex_bool(PyComplexObject *v)
|
|
{
|
|
return v->cval.real != 0.0 || v->cval.imag != 0.0;
|
|
}
|
|
|
|
static PyObject *
|
|
complex_richcompare(PyObject *v, PyObject *w, int op)
|
|
{
|
|
PyObject *res;
|
|
Py_complex i;
|
|
int equal;
|
|
|
|
if (op != Py_EQ && op != Py_NE) {
|
|
goto Unimplemented;
|
|
}
|
|
|
|
assert(PyComplex_Check(v));
|
|
TO_COMPLEX(v, i);
|
|
|
|
if (PyLong_Check(w)) {
|
|
/* Check for 0.0 imaginary part first to avoid the rich
|
|
* comparison when possible.
|
|
*/
|
|
if (i.imag == 0.0) {
|
|
PyObject *j, *sub_res;
|
|
j = PyFloat_FromDouble(i.real);
|
|
if (j == NULL)
|
|
return NULL;
|
|
|
|
sub_res = PyObject_RichCompare(j, w, op);
|
|
Py_DECREF(j);
|
|
return sub_res;
|
|
}
|
|
else {
|
|
equal = 0;
|
|
}
|
|
}
|
|
else if (PyFloat_Check(w)) {
|
|
equal = (i.real == PyFloat_AsDouble(w) && i.imag == 0.0);
|
|
}
|
|
else if (PyComplex_Check(w)) {
|
|
Py_complex j;
|
|
|
|
TO_COMPLEX(w, j);
|
|
equal = (i.real == j.real && i.imag == j.imag);
|
|
}
|
|
else {
|
|
goto Unimplemented;
|
|
}
|
|
|
|
if (equal == (op == Py_EQ))
|
|
res = Py_True;
|
|
else
|
|
res = Py_False;
|
|
|
|
return Py_NewRef(res);
|
|
|
|
Unimplemented:
|
|
Py_RETURN_NOTIMPLEMENTED;
|
|
}
|
|
|
|
/*[clinic input]
|
|
complex.conjugate
|
|
|
|
Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex_conjugate_impl(PyComplexObject *self)
|
|
/*[clinic end generated code: output=5059ef162edfc68e input=5fea33e9747ec2c4]*/
|
|
{
|
|
Py_complex c = self->cval;
|
|
c.imag = -c.imag;
|
|
return PyComplex_FromCComplex(c);
|
|
}
|
|
|
|
/*[clinic input]
|
|
complex.__getnewargs__
|
|
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex___getnewargs___impl(PyComplexObject *self)
|
|
/*[clinic end generated code: output=689b8206e8728934 input=539543e0a50533d7]*/
|
|
{
|
|
Py_complex c = self->cval;
|
|
return Py_BuildValue("(dd)", c.real, c.imag);
|
|
}
|
|
|
|
|
|
/*[clinic input]
|
|
complex.__format__
|
|
|
|
format_spec: unicode
|
|
/
|
|
|
|
Convert to a string according to format_spec.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex___format___impl(PyComplexObject *self, PyObject *format_spec)
|
|
/*[clinic end generated code: output=bfcb60df24cafea0 input=014ef5488acbe1d5]*/
|
|
{
|
|
_PyUnicodeWriter writer;
|
|
int ret;
|
|
_PyUnicodeWriter_Init(&writer);
|
|
ret = _PyComplex_FormatAdvancedWriter(
|
|
&writer,
|
|
(PyObject *)self,
|
|
format_spec, 0, PyUnicode_GET_LENGTH(format_spec));
|
|
if (ret == -1) {
|
|
_PyUnicodeWriter_Dealloc(&writer);
|
|
return NULL;
|
|
}
|
|
return _PyUnicodeWriter_Finish(&writer);
|
|
}
|
|
|
|
/*[clinic input]
|
|
complex.__complex__
|
|
|
|
Convert this value to exact type complex.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex___complex___impl(PyComplexObject *self)
|
|
/*[clinic end generated code: output=e6b35ba3d275dc9c input=3589ada9d27db854]*/
|
|
{
|
|
if (PyComplex_CheckExact(self)) {
|
|
return Py_NewRef(self);
|
|
}
|
|
else {
|
|
return PyComplex_FromCComplex(self->cval);
|
|
}
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
complex_from_string_inner(const char *s, Py_ssize_t len, void *type)
|
|
{
|
|
double x=0.0, y=0.0, z;
|
|
int got_bracket=0;
|
|
const char *start;
|
|
char *end;
|
|
|
|
/* position on first nonblank */
|
|
start = s;
|
|
while (Py_ISSPACE(*s))
|
|
s++;
|
|
if (*s == '(') {
|
|
/* Skip over possible bracket from repr(). */
|
|
got_bracket = 1;
|
|
s++;
|
|
while (Py_ISSPACE(*s))
|
|
s++;
|
|
}
|
|
|
|
/* a valid complex string usually takes one of the three forms:
|
|
|
|
<float> - real part only
|
|
<float>j - imaginary part only
|
|
<float><signed-float>j - real and imaginary parts
|
|
|
|
where <float> represents any numeric string that's accepted by the
|
|
float constructor (including 'nan', 'inf', 'infinity', etc.), and
|
|
<signed-float> is any string of the form <float> whose first
|
|
character is '+' or '-'.
|
|
|
|
For backwards compatibility, the extra forms
|
|
|
|
<float><sign>j
|
|
<sign>j
|
|
j
|
|
|
|
are also accepted, though support for these forms may be removed from
|
|
a future version of Python.
|
|
*/
|
|
|
|
/* first look for forms starting with <float> */
|
|
z = PyOS_string_to_double(s, &end, NULL);
|
|
if (z == -1.0 && PyErr_Occurred()) {
|
|
if (PyErr_ExceptionMatches(PyExc_ValueError))
|
|
PyErr_Clear();
|
|
else
|
|
return NULL;
|
|
}
|
|
if (end != s) {
|
|
/* all 4 forms starting with <float> land here */
|
|
s = end;
|
|
if (*s == '+' || *s == '-') {
|
|
/* <float><signed-float>j | <float><sign>j */
|
|
x = z;
|
|
y = PyOS_string_to_double(s, &end, NULL);
|
|
if (y == -1.0 && PyErr_Occurred()) {
|
|
if (PyErr_ExceptionMatches(PyExc_ValueError))
|
|
PyErr_Clear();
|
|
else
|
|
return NULL;
|
|
}
|
|
if (end != s)
|
|
/* <float><signed-float>j */
|
|
s = end;
|
|
else {
|
|
/* <float><sign>j */
|
|
y = *s == '+' ? 1.0 : -1.0;
|
|
s++;
|
|
}
|
|
if (!(*s == 'j' || *s == 'J'))
|
|
goto parse_error;
|
|
s++;
|
|
}
|
|
else if (*s == 'j' || *s == 'J') {
|
|
/* <float>j */
|
|
s++;
|
|
y = z;
|
|
}
|
|
else
|
|
/* <float> */
|
|
x = z;
|
|
}
|
|
else {
|
|
/* not starting with <float>; must be <sign>j or j */
|
|
if (*s == '+' || *s == '-') {
|
|
/* <sign>j */
|
|
y = *s == '+' ? 1.0 : -1.0;
|
|
s++;
|
|
}
|
|
else
|
|
/* j */
|
|
y = 1.0;
|
|
if (!(*s == 'j' || *s == 'J'))
|
|
goto parse_error;
|
|
s++;
|
|
}
|
|
|
|
/* trailing whitespace and closing bracket */
|
|
while (Py_ISSPACE(*s))
|
|
s++;
|
|
if (got_bracket) {
|
|
/* if there was an opening parenthesis, then the corresponding
|
|
closing parenthesis should be right here */
|
|
if (*s != ')')
|
|
goto parse_error;
|
|
s++;
|
|
while (Py_ISSPACE(*s))
|
|
s++;
|
|
}
|
|
|
|
/* we should now be at the end of the string */
|
|
if (s-start != len)
|
|
goto parse_error;
|
|
|
|
return complex_subtype_from_doubles(_PyType_CAST(type), x, y);
|
|
|
|
parse_error:
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"complex() arg is a malformed string");
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *
|
|
complex_subtype_from_string(PyTypeObject *type, PyObject *v)
|
|
{
|
|
const char *s;
|
|
PyObject *s_buffer = NULL, *result = NULL;
|
|
Py_ssize_t len;
|
|
|
|
if (PyUnicode_Check(v)) {
|
|
s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v);
|
|
if (s_buffer == NULL) {
|
|
return NULL;
|
|
}
|
|
assert(PyUnicode_IS_ASCII(s_buffer));
|
|
/* Simply get a pointer to existing ASCII characters. */
|
|
s = PyUnicode_AsUTF8AndSize(s_buffer, &len);
|
|
assert(s != NULL);
|
|
}
|
|
else {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"complex() argument must be a string or a number, not %T",
|
|
v);
|
|
return NULL;
|
|
}
|
|
|
|
result = _Py_string_to_number_with_underscores(s, len, "complex", v, type,
|
|
complex_from_string_inner);
|
|
Py_DECREF(s_buffer);
|
|
return result;
|
|
}
|
|
|
|
/* The constructor should only accept a string as a positional argument,
|
|
* not as by the 'real' keyword. But Argument Clinic does not allow
|
|
* to distinguish between argument passed positionally and by keyword.
|
|
* So the constructor must be split into two parts: actual_complex_new()
|
|
* handles the case of no arguments and one positional argument, and calls
|
|
* complex_new(), implemented with Argument Clinic, to handle the remaining
|
|
* cases: 'real' and 'imag' arguments. This separation is well suited
|
|
* for different constructor roles: converting a string or number to a complex
|
|
* number and constructing a complex number from real and imaginary parts.
|
|
*/
|
|
static PyObject *
|
|
actual_complex_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|
{
|
|
PyObject *res = NULL;
|
|
PyNumberMethods *nbr;
|
|
|
|
if (PyTuple_GET_SIZE(args) > 1 || (kwargs != NULL && PyDict_GET_SIZE(kwargs))) {
|
|
return complex_new(type, args, kwargs);
|
|
}
|
|
if (!PyTuple_GET_SIZE(args)) {
|
|
return complex_subtype_from_doubles(type, 0, 0);
|
|
}
|
|
|
|
PyObject *arg = PyTuple_GET_ITEM(args, 0);
|
|
/* Special-case for a single argument when type(arg) is complex. */
|
|
if (PyComplex_CheckExact(arg) && type == &PyComplex_Type) {
|
|
/* Note that we can't know whether it's safe to return
|
|
a complex *subclass* instance as-is, hence the restriction
|
|
to exact complexes here. If either the input or the
|
|
output is a complex subclass, it will be handled below
|
|
as a non-orthogonal vector. */
|
|
return Py_NewRef(arg);
|
|
}
|
|
if (PyUnicode_Check(arg)) {
|
|
return complex_subtype_from_string(type, arg);
|
|
}
|
|
PyObject *tmp = try_complex_special_method(arg);
|
|
if (tmp) {
|
|
Py_complex c = ((PyComplexObject*)tmp)->cval;
|
|
res = complex_subtype_from_doubles(type, c.real, c.imag);
|
|
Py_DECREF(tmp);
|
|
}
|
|
else if (PyErr_Occurred()) {
|
|
return NULL;
|
|
}
|
|
else if (PyComplex_Check(arg)) {
|
|
/* Note that if arg is of a complex subtype, we're only
|
|
retaining its real & imag parts here, and the return
|
|
value is (properly) of the builtin complex type. */
|
|
Py_complex c = ((PyComplexObject*)arg)->cval;
|
|
res = complex_subtype_from_doubles(type, c.real, c.imag);
|
|
}
|
|
else if ((nbr = Py_TYPE(arg)->tp_as_number) != NULL &&
|
|
(nbr->nb_float != NULL || nbr->nb_index != NULL))
|
|
{
|
|
/* The argument really is entirely real, and contributes
|
|
nothing in the imaginary direction.
|
|
Just treat it as a double. */
|
|
double r = PyFloat_AsDouble(arg);
|
|
if (r != -1.0 || !PyErr_Occurred()) {
|
|
res = complex_subtype_from_doubles(type, r, 0);
|
|
}
|
|
}
|
|
else {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"complex() argument must be a string or a number, not %T",
|
|
arg);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*[clinic input]
|
|
@classmethod
|
|
complex.__new__ as complex_new
|
|
real as r: object(c_default="NULL") = 0
|
|
imag as i: object(c_default="NULL") = 0
|
|
|
|
Create a complex number from a string or numbers.
|
|
|
|
If a string is given, parse it as a complex number.
|
|
If a single number is given, convert it to a complex number.
|
|
If the 'real' or 'imag' arguments are given, create a complex number
|
|
with the specified real and imaginary components.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
|
|
/*[clinic end generated code: output=b6c7dd577b537dc1 input=ff4268dc540958a4]*/
|
|
{
|
|
PyObject *tmp;
|
|
PyNumberMethods *nbr, *nbi = NULL;
|
|
Py_complex cr, ci;
|
|
int own_r = 0;
|
|
int cr_is_complex = 0;
|
|
int ci_is_complex = 0;
|
|
|
|
if (r == NULL) {
|
|
r = _PyLong_GetZero();
|
|
}
|
|
PyObject *orig_r = r;
|
|
|
|
/* DEPRECATED: The call of try_complex_special_method() for the "real"
|
|
* part will be dropped after the end of the deprecation period. */
|
|
tmp = try_complex_special_method(r);
|
|
if (tmp) {
|
|
r = tmp;
|
|
own_r = 1;
|
|
}
|
|
else if (PyErr_Occurred()) {
|
|
return NULL;
|
|
}
|
|
|
|
nbr = Py_TYPE(r)->tp_as_number;
|
|
if (nbr == NULL ||
|
|
(nbr->nb_float == NULL && nbr->nb_index == NULL && !PyComplex_Check(r)))
|
|
{
|
|
PyErr_Format(PyExc_TypeError,
|
|
"complex() argument 'real' must be a real number, not %T",
|
|
r);
|
|
if (own_r) {
|
|
Py_DECREF(r);
|
|
}
|
|
return NULL;
|
|
}
|
|
if (i != NULL) {
|
|
nbi = Py_TYPE(i)->tp_as_number;
|
|
if (nbi == NULL ||
|
|
(nbi->nb_float == NULL && nbi->nb_index == NULL && !PyComplex_Check(i)))
|
|
{
|
|
PyErr_Format(PyExc_TypeError,
|
|
"complex() argument 'imag' must be a real number, not %T",
|
|
i);
|
|
if (own_r) {
|
|
Py_DECREF(r);
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* If we get this far, then the "real" and "imag" parts should
|
|
both be treated as numbers, and the constructor should return a
|
|
complex number equal to (real + imag*1j).
|
|
|
|
The following is DEPRECATED:
|
|
Note that we do NOT assume the input to already be in canonical
|
|
form; the "real" and "imag" parts might themselves be complex
|
|
numbers, which slightly complicates the code below. */
|
|
if (PyComplex_Check(r)) {
|
|
/* Note that if r is of a complex subtype, we're only
|
|
retaining its real & imag parts here, and the return
|
|
value is (properly) of the builtin complex type. */
|
|
cr = ((PyComplexObject*)r)->cval;
|
|
cr_is_complex = 1;
|
|
if (own_r) {
|
|
/* r was a newly created complex number, rather
|
|
than the original "real" argument. */
|
|
Py_DECREF(r);
|
|
}
|
|
nbr = Py_TYPE(orig_r)->tp_as_number;
|
|
if (nbr == NULL ||
|
|
(nbr->nb_float == NULL && nbr->nb_index == NULL))
|
|
{
|
|
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
"complex() argument 'real' must be a real number, not %T",
|
|
orig_r)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* The "real" part really is entirely real, and contributes
|
|
nothing in the imaginary direction.
|
|
Just treat it as a double. */
|
|
tmp = PyNumber_Float(r);
|
|
assert(!own_r);
|
|
if (tmp == NULL)
|
|
return NULL;
|
|
assert(PyFloat_Check(tmp));
|
|
cr.real = PyFloat_AsDouble(tmp);
|
|
cr.imag = 0.0;
|
|
Py_DECREF(tmp);
|
|
}
|
|
if (i == NULL) {
|
|
ci.real = cr.imag;
|
|
}
|
|
else if (PyComplex_Check(i)) {
|
|
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
"complex() argument 'imag' must be a real number, not %T",
|
|
i)) {
|
|
return NULL;
|
|
}
|
|
ci = ((PyComplexObject*)i)->cval;
|
|
ci_is_complex = 1;
|
|
} else {
|
|
/* The "imag" part really is entirely imaginary, and
|
|
contributes nothing in the real direction.
|
|
Just treat it as a double. */
|
|
tmp = PyNumber_Float(i);
|
|
if (tmp == NULL)
|
|
return NULL;
|
|
ci.real = PyFloat_AsDouble(tmp);
|
|
Py_DECREF(tmp);
|
|
}
|
|
/* If the input was in canonical form, then the "real" and "imag"
|
|
parts are real numbers, so that ci.imag and cr.imag are zero.
|
|
We need this correction in case they were not real numbers. */
|
|
|
|
if (ci_is_complex) {
|
|
cr.real -= ci.imag;
|
|
}
|
|
if (cr_is_complex && i != NULL) {
|
|
ci.real += cr.imag;
|
|
}
|
|
return complex_subtype_from_doubles(type, cr.real, ci.real);
|
|
}
|
|
|
|
/*[clinic input]
|
|
@classmethod
|
|
complex.from_number
|
|
|
|
number: object
|
|
/
|
|
|
|
Convert number to a complex floating-point number.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
complex_from_number(PyTypeObject *type, PyObject *number)
|
|
/*[clinic end generated code: output=658a7a5fb0de074d input=3f8bdd3a2bc3facd]*/
|
|
{
|
|
if (PyComplex_CheckExact(number) && type == &PyComplex_Type) {
|
|
Py_INCREF(number);
|
|
return number;
|
|
}
|
|
Py_complex cv = PyComplex_AsCComplex(number);
|
|
if (cv.real == -1.0 && PyErr_Occurred()) {
|
|
return NULL;
|
|
}
|
|
PyObject *result = PyComplex_FromCComplex(cv);
|
|
if (type != &PyComplex_Type && result != NULL) {
|
|
Py_SETREF(result, PyObject_CallOneArg((PyObject *)type, result));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static PyMethodDef complex_methods[] = {
|
|
COMPLEX_FROM_NUMBER_METHODDEF
|
|
COMPLEX_CONJUGATE_METHODDEF
|
|
COMPLEX___COMPLEX___METHODDEF
|
|
COMPLEX___GETNEWARGS___METHODDEF
|
|
COMPLEX___FORMAT___METHODDEF
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static PyMemberDef complex_members[] = {
|
|
{"real", Py_T_DOUBLE, offsetof(PyComplexObject, cval.real), Py_READONLY,
|
|
"the real part of a complex number"},
|
|
{"imag", Py_T_DOUBLE, offsetof(PyComplexObject, cval.imag), Py_READONLY,
|
|
"the imaginary part of a complex number"},
|
|
{0},
|
|
};
|
|
|
|
static PyNumberMethods complex_as_number = {
|
|
(binaryfunc)complex_add, /* nb_add */
|
|
(binaryfunc)complex_sub, /* nb_subtract */
|
|
(binaryfunc)complex_mul, /* nb_multiply */
|
|
0, /* nb_remainder */
|
|
0, /* nb_divmod */
|
|
(ternaryfunc)complex_pow, /* nb_power */
|
|
(unaryfunc)complex_neg, /* nb_negative */
|
|
(unaryfunc)complex_pos, /* nb_positive */
|
|
(unaryfunc)complex_abs, /* nb_absolute */
|
|
(inquiry)complex_bool, /* nb_bool */
|
|
0, /* nb_invert */
|
|
0, /* nb_lshift */
|
|
0, /* nb_rshift */
|
|
0, /* nb_and */
|
|
0, /* nb_xor */
|
|
0, /* nb_or */
|
|
0, /* nb_int */
|
|
0, /* nb_reserved */
|
|
0, /* nb_float */
|
|
0, /* nb_inplace_add */
|
|
0, /* nb_inplace_subtract */
|
|
0, /* nb_inplace_multiply*/
|
|
0, /* nb_inplace_remainder */
|
|
0, /* nb_inplace_power */
|
|
0, /* nb_inplace_lshift */
|
|
0, /* nb_inplace_rshift */
|
|
0, /* nb_inplace_and */
|
|
0, /* nb_inplace_xor */
|
|
0, /* nb_inplace_or */
|
|
0, /* nb_floor_divide */
|
|
(binaryfunc)complex_div, /* nb_true_divide */
|
|
0, /* nb_inplace_floor_divide */
|
|
0, /* nb_inplace_true_divide */
|
|
};
|
|
|
|
PyTypeObject PyComplex_Type = {
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
"complex",
|
|
sizeof(PyComplexObject),
|
|
0,
|
|
0, /* tp_dealloc */
|
|
0, /* tp_vectorcall_offset */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_as_async */
|
|
(reprfunc)complex_repr, /* tp_repr */
|
|
&complex_as_number, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
(hashfunc)complex_hash, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
complex_new__doc__, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
complex_richcompare, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
complex_methods, /* tp_methods */
|
|
complex_members, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
PyType_GenericAlloc, /* tp_alloc */
|
|
actual_complex_new, /* tp_new */
|
|
PyObject_Free, /* tp_free */
|
|
.tp_version_tag = _Py_TYPE_VERSION_COMPLEX,
|
|
};
|