Files
typthon/Objects/complexobject.c
copilot-swe-agent[bot] 0f2e4eb3fd Fix final Py_ patterns - uintptr, arithmetic shift, inc files
- Fixed Py_uintptr_t → Ty_uintptr_t
- Fixed Py_ARITHMETIC_RIGHT_SHIFT → Ty_ARITHMETIC_RIGHT_SHIFT
- Fixed PyTypeObject, PyNumberMethods, PyAsyncMethods in .inc files

Build is nearing completion.

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
2025-12-29 18:38:56 +00:00

1423 lines
42 KiB
C

/* Complex object implementation */
/* Borrows heavily from floatobject.c */
/* Submitted by Jim Hugunin */
#include "Python.h"
#include "pycore_call.h" // _TyObject_CallNoArgs()
#include "pycore_complexobject.h" // _TyComplex_FormatAdvancedWriter()
#include "pycore_floatobject.h" // _Ty_convert_int_to_double()
#include "pycore_long.h" // _TyLong_GetZero()
#include "pycore_object.h" // _TyObject_Init()
#include "pycore_pymath.h" // _Ty_ADJUST_ERANGE2()
#define _PyComplexObject_CAST(op) ((PyComplexObject *)(op))
/*[clinic input]
class complex "PyComplexObject *" "&TyComplex_Type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=819e057d2d10f5ec]*/
#include "clinic/complexobject.c.h"
/* elementary operations on complex numbers */
static Ty_complex c_1 = {1., 0.};
Ty_complex
_Ty_c_sum(Ty_complex a, Ty_complex b)
{
Ty_complex r;
r.real = a.real + b.real;
r.imag = a.imag + b.imag;
return r;
}
Ty_complex
_Ty_cr_sum(Ty_complex a, double b)
{
Ty_complex r = a;
r.real += b;
return r;
}
static inline Ty_complex
_Ty_rc_sum(double a, Ty_complex b)
{
return _Ty_cr_sum(b, a);
}
Ty_complex
_Ty_c_diff(Ty_complex a, Ty_complex b)
{
Ty_complex r;
r.real = a.real - b.real;
r.imag = a.imag - b.imag;
return r;
}
Ty_complex
_Ty_cr_diff(Ty_complex a, double b)
{
Ty_complex r = a;
r.real -= b;
return r;
}
Ty_complex
_Ty_rc_diff(double a, Ty_complex b)
{
Ty_complex r;
r.real = a - b.real;
r.imag = -b.imag;
return r;
}
Ty_complex
_Ty_c_neg(Ty_complex a)
{
Ty_complex r;
r.real = -a.real;
r.imag = -a.imag;
return r;
}
Ty_complex
_Ty_c_prod(Ty_complex z, Ty_complex w)
{
double a = z.real, b = z.imag, c = w.real, d = w.imag;
double ac = a*c, bd = b*d, ad = a*d, bc = b*c;
Ty_complex r = {ac - bd, ad + bc};
/* Recover infinities that computed as nan+nanj. See e.g. the C11,
Annex G.5.1, routine _Cmultd(). */
if (isnan(r.real) && isnan(r.imag)) {
int recalc = 0;
if (isinf(a) || isinf(b)) { /* z is infinite */
/* "Box" the infinity and change nans in the other factor to 0 */
a = copysign(isinf(a) ? 1.0 : 0.0, a);
b = copysign(isinf(b) ? 1.0 : 0.0, b);
if (isnan(c)) {
c = copysign(0.0, c);
}
if (isnan(d)) {
d = copysign(0.0, d);
}
recalc = 1;
}
if (isinf(c) || isinf(d)) { /* w is infinite */
/* "Box" the infinity and change nans in the other factor to 0 */
c = copysign(isinf(c) ? 1.0 : 0.0, c);
d = copysign(isinf(d) ? 1.0 : 0.0, d);
if (isnan(a)) {
a = copysign(0.0, a);
}
if (isnan(b)) {
b = copysign(0.0, b);
}
recalc = 1;
}
if (!recalc && (isinf(ac) || isinf(bd) || isinf(ad) || isinf(bc))) {
/* Recover infinities from overflow by changing nans to 0 */
if (isnan(a)) {
a = copysign(0.0, a);
}
if (isnan(b)) {
b = copysign(0.0, b);
}
if (isnan(c)) {
c = copysign(0.0, c);
}
if (isnan(d)) {
d = copysign(0.0, d);
}
recalc = 1;
}
if (recalc) {
r.real = Ty_INFINITY*(a*c - b*d);
r.imag = Ty_INFINITY*(a*d + b*c);
}
}
return r;
}
Ty_complex
_Ty_cr_prod(Ty_complex a, double b)
{
Ty_complex r = a;
r.real *= b;
r.imag *= b;
return r;
}
static inline Ty_complex
_Ty_rc_prod(double a, Ty_complex b)
{
return _Ty_cr_prod(b, a);
}
/* Avoid bad optimization on Windows ARM64 until the compiler is fixed */
#ifdef _M_ARM64
#pragma optimize("", off)
#endif
Ty_complex
_Ty_c_quot(Ty_complex a, Ty_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:
Ty_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).
*/
Ty_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 = Ty_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 = Ty_INFINITY * (x*b.real + y*b.imag);
r.imag = Ty_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;
}
Ty_complex
_Ty_cr_quot(Ty_complex a, double b)
{
Ty_complex r = a;
if (b) {
r.real /= b;
r.imag /= b;
}
else {
errno = EDOM;
r.real = r.imag = 0.0;
}
return r;
}
/* an equivalent of _Ty_c_quot() function, when 1st argument is real */
Ty_complex
_Ty_rc_quot(double a, Ty_complex b)
{
Ty_complex r;
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) {
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 / denom;
r.imag = (-a * ratio) / denom;
}
}
else if (abs_bimag >= abs_breal) {
const double ratio = b.real / b.imag;
const double denom = b.real * ratio + b.imag;
assert(b.imag != 0.0);
r.real = (a * ratio) / denom;
r.imag = (-a) / denom;
}
else {
r.real = r.imag = Ty_NAN;
}
if (isnan(r.real) && isnan(r.imag) && isfinite(a)
&& (isinf(abs_breal) || isinf(abs_bimag)))
{
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*x);
r.imag = 0.0 * (-a*y);
}
return r;
}
#ifdef _M_ARM64
#pragma optimize("", on)
#endif
Ty_complex
_Ty_c_pow(Ty_complex a, Ty_complex b)
{
Ty_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);
_Ty_ADJUST_ERANGE2(r.real, r.imag);
}
return r;
}
static Ty_complex
c_powu(Ty_complex x, long n)
{
Ty_complex r, p;
long mask = 1;
r = c_1;
p = x;
while (mask > 0 && n >= mask) {
if (n & mask)
r = _Ty_c_prod(r,p);
mask <<= 1;
p = _Ty_c_prod(p,p);
}
return r;
}
static Ty_complex
c_powi(Ty_complex x, long n)
{
if (n > 0)
return c_powu(x,n);
else
return _Ty_c_quot(c_1, c_powu(x,-n));
}
double
_Ty_c_abs(Ty_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 Ty_NAN;
}
result = hypot(z.real, z.imag);
if (!isfinite(result))
errno = ERANGE;
else
errno = 0;
return result;
}
static TyObject *
complex_subtype_from_c_complex(TyTypeObject *type, Ty_complex cval)
{
TyObject *op;
op = type->tp_alloc(type, 0);
if (op != NULL)
((PyComplexObject *)op)->cval = cval;
return op;
}
TyObject *
TyComplex_FromCComplex(Ty_complex cval)
{
/* Inline PyObject_New */
PyComplexObject *op = PyObject_Malloc(sizeof(PyComplexObject));
if (op == NULL) {
return TyErr_NoMemory();
}
_TyObject_Init((TyObject*)op, &TyComplex_Type);
op->cval = cval;
return (TyObject *) op;
}
static TyObject *
complex_subtype_from_doubles(TyTypeObject *type, double real, double imag)
{
Ty_complex c;
c.real = real;
c.imag = imag;
return complex_subtype_from_c_complex(type, c);
}
TyObject *
TyComplex_FromDoubles(double real, double imag)
{
Ty_complex c;
c.real = real;
c.imag = imag;
return TyComplex_FromCComplex(c);
}
static TyObject * try_complex_special_method(TyObject *);
double
TyComplex_RealAsDouble(TyObject *op)
{
double real = -1.0;
if (TyComplex_Check(op)) {
real = ((PyComplexObject *)op)->cval.real;
}
else {
TyObject* newop = try_complex_special_method(op);
if (newop) {
real = ((PyComplexObject *)newop)->cval.real;
Ty_DECREF(newop);
} else if (!TyErr_Occurred()) {
real = TyFloat_AsDouble(op);
}
}
return real;
}
double
TyComplex_ImagAsDouble(TyObject *op)
{
double imag = -1.0;
if (TyComplex_Check(op)) {
imag = ((PyComplexObject *)op)->cval.imag;
}
else {
TyObject* newop = try_complex_special_method(op);
if (newop) {
imag = ((PyComplexObject *)newop)->cval.imag;
Ty_DECREF(newop);
} else if (!TyErr_Occurred()) {
TyFloat_AsDouble(op);
if (!TyErr_Occurred()) {
imag = 0.0;
}
}
}
return imag;
}
static TyObject *
try_complex_special_method(TyObject *op)
{
TyObject *f;
f = _TyObject_LookupSpecial(op, &_Ty_ID(__complex__));
if (f) {
TyObject *res = _TyObject_CallNoArgs(f);
Ty_DECREF(f);
if (!res || TyComplex_CheckExact(res)) {
return res;
}
if (!TyComplex_Check(res)) {
TyErr_Format(TyExc_TypeError,
"__complex__ returned non-complex (type %.200s)",
Ty_TYPE(res)->tp_name);
Ty_DECREF(res);
return NULL;
}
/* Issue #29894: warn if 'res' not of exact type complex. */
if (TyErr_WarnFormat(TyExc_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.",
Ty_TYPE(res)->tp_name)) {
Ty_DECREF(res);
return NULL;
}
return res;
}
return NULL;
}
Ty_complex
TyComplex_AsCComplex(TyObject *op)
{
Ty_complex cv;
TyObject *newop = NULL;
assert(op);
/* If op is already of type TyComplex_Type, return its value */
if (TyComplex_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;
Ty_DECREF(newop);
return cv;
}
else if (TyErr_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 {
/* TyFloat_AsDouble will return -1 on failure */
cv.real = TyFloat_AsDouble(op);
return cv;
}
}
static TyObject *
complex_repr(TyObject *op)
{
int precision = 0;
char format_code = 'r';
TyObject *result = NULL;
PyComplexObject *v = _PyComplexObject_CAST(op);
/* 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 = TyOS_double_to_string(v->cval.imag, format_code,
precision, 0, NULL);
if (!im) {
TyErr_NoMemory();
goto done;
}
} else {
/* Format imaginary part with sign, real part without. Include
parens in the result. */
pre = TyOS_double_to_string(v->cval.real, format_code,
precision, 0, NULL);
if (!pre) {
TyErr_NoMemory();
goto done;
}
re = pre;
im = TyOS_double_to_string(v->cval.imag, format_code,
precision, Ty_DTSF_SIGN, NULL);
if (!im) {
TyErr_NoMemory();
goto done;
}
lead = "(";
tail = ")";
}
result = TyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail);
done:
TyMem_Free(im);
TyMem_Free(pre);
return result;
}
static Ty_hash_t
complex_hash(TyObject *op)
{
Ty_uhash_t hashreal, hashimag, combined;
PyComplexObject *v = _PyComplexObject_CAST(op);
hashreal = (Ty_uhash_t)_Ty_HashDouble(op, v->cval.real);
if (hashreal == (Ty_uhash_t)-1)
return -1;
hashimag = (Ty_uhash_t)_Ty_HashDouble(op, v->cval.imag);
if (hashimag == (Ty_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 == (Ty_uhash_t)-1)
combined = (Ty_uhash_t)-2;
return (Ty_hash_t)combined;
}
/* This macro may return! */
#define TO_COMPLEX(obj, c) \
if (TyComplex_Check(obj)) \
c = ((PyComplexObject *)(obj))->cval; \
else if (real_to_complex(&(obj), &(c)) < 0) \
return (obj)
static int
real_to_double(TyObject **pobj, double *dbl)
{
TyObject *obj = *pobj;
if (TyFloat_Check(obj)) {
*dbl = TyFloat_AS_DOUBLE(obj);
}
else if (_Ty_convert_int_to_double(pobj, dbl) < 0) {
return -1;
}
return 0;
}
static int
real_to_complex(TyObject **pobj, Ty_complex *pc)
{
pc->imag = 0.0;
return real_to_double(pobj, &(pc->real));
}
/* Complex arithmetic rules implement special mixed-mode case where combining
a pure-real (float or int) value and a complex value is performed directly
without first coercing the real value to a complex value.
Let us consider the addition as an example, assuming that ints are implicitly
converted to floats. We have the following rules (up to variants with changed
order of operands):
complex(a, b) + complex(c, d) = complex(a + c, b + d)
float(a) + complex(b, c) = complex(a + b, c)
Similar rules are implemented for subtraction, multiplication and division.
See C11's Annex G, sections G.5.1 and G.5.2.
*/
#define COMPLEX_BINOP(NAME, FUNC) \
static TyObject * \
complex_##NAME(TyObject *v, TyObject *w) \
{ \
Ty_complex a; \
errno = 0; \
if (TyComplex_Check(w)) { \
Ty_complex b = ((PyComplexObject *)w)->cval; \
if (TyComplex_Check(v)) { \
a = ((PyComplexObject *)v)->cval; \
a = _Ty_c_##FUNC(a, b); \
} \
else if (real_to_double(&v, &a.real) < 0) { \
return v; \
} \
else { \
a = _Ty_rc_##FUNC(a.real, b); \
} \
} \
else if (!TyComplex_Check(v)) { \
Py_RETURN_NOTIMPLEMENTED; \
} \
else { \
a = ((PyComplexObject *)v)->cval; \
double b; \
if (real_to_double(&w, &b) < 0) { \
return w; \
} \
a = _Ty_cr_##FUNC(a, b); \
} \
if (errno == EDOM) { \
TyErr_SetString(TyExc_ZeroDivisionError, \
"division by zero"); \
return NULL; \
} \
return TyComplex_FromCComplex(a); \
}
COMPLEX_BINOP(add, sum)
COMPLEX_BINOP(mul, prod)
COMPLEX_BINOP(sub, diff)
COMPLEX_BINOP(div, quot)
static TyObject *
complex_pow(TyObject *v, TyObject *w, TyObject *z)
{
Ty_complex p;
Ty_complex a, b;
TO_COMPLEX(v, a);
TO_COMPLEX(w, b);
if (z != Ty_None) {
TyErr_SetString(TyExc_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);
_Ty_ADJUST_ERANGE2(p.real, p.imag);
}
else {
p = _Ty_c_pow(a, b);
}
if (errno == EDOM) {
TyErr_SetString(TyExc_ZeroDivisionError,
"zero to a negative or complex power");
return NULL;
}
else if (errno == ERANGE) {
TyErr_SetString(TyExc_OverflowError,
"complex exponentiation");
return NULL;
}
return TyComplex_FromCComplex(p);
}
static TyObject *
complex_neg(TyObject *op)
{
PyComplexObject *v = _PyComplexObject_CAST(op);
Ty_complex neg;
neg.real = -v->cval.real;
neg.imag = -v->cval.imag;
return TyComplex_FromCComplex(neg);
}
static TyObject *
complex_pos(TyObject *op)
{
PyComplexObject *v = _PyComplexObject_CAST(op);
if (TyComplex_CheckExact(v)) {
return Ty_NewRef(v);
}
return TyComplex_FromCComplex(v->cval);
}
static TyObject *
complex_abs(TyObject *op)
{
PyComplexObject *v = _PyComplexObject_CAST(op);
double result = _Ty_c_abs(v->cval);
if (errno == ERANGE) {
TyErr_SetString(TyExc_OverflowError,
"absolute value too large");
return NULL;
}
return TyFloat_FromDouble(result);
}
static int
complex_bool(TyObject *op)
{
PyComplexObject *v = _PyComplexObject_CAST(op);
return v->cval.real != 0.0 || v->cval.imag != 0.0;
}
static TyObject *
complex_richcompare(TyObject *v, TyObject *w, int op)
{
TyObject *res;
Ty_complex i;
int equal;
if (op != Py_EQ && op != Py_NE) {
goto Unimplemented;
}
assert(TyComplex_Check(v));
TO_COMPLEX(v, i);
if (TyLong_Check(w)) {
/* Check for 0.0 imaginary part first to avoid the rich
* comparison when possible.
*/
if (i.imag == 0.0) {
TyObject *j, *sub_res;
j = TyFloat_FromDouble(i.real);
if (j == NULL)
return NULL;
sub_res = PyObject_RichCompare(j, w, op);
Ty_DECREF(j);
return sub_res;
}
else {
equal = 0;
}
}
else if (TyFloat_Check(w)) {
equal = (i.real == TyFloat_AsDouble(w) && i.imag == 0.0);
}
else if (TyComplex_Check(w)) {
Ty_complex j;
TO_COMPLEX(w, j);
equal = (i.real == j.real && i.imag == j.imag);
}
else {
goto Unimplemented;
}
if (equal == (op == Py_EQ))
res = Ty_True;
else
res = Ty_False;
return Ty_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 TyObject *
complex_conjugate_impl(PyComplexObject *self)
/*[clinic end generated code: output=5059ef162edfc68e input=5fea33e9747ec2c4]*/
{
Ty_complex c = self->cval;
c.imag = -c.imag;
return TyComplex_FromCComplex(c);
}
/*[clinic input]
complex.__getnewargs__
[clinic start generated code]*/
static TyObject *
complex___getnewargs___impl(PyComplexObject *self)
/*[clinic end generated code: output=689b8206e8728934 input=539543e0a50533d7]*/
{
Ty_complex c = self->cval;
return Ty_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 TyObject *
complex___format___impl(PyComplexObject *self, TyObject *format_spec)
/*[clinic end generated code: output=bfcb60df24cafea0 input=014ef5488acbe1d5]*/
{
_PyUnicodeWriter writer;
int ret;
_PyUnicodeWriter_Init(&writer);
ret = _TyComplex_FormatAdvancedWriter(
&writer,
(TyObject *)self,
format_spec, 0, TyUnicode_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 TyObject *
complex___complex___impl(PyComplexObject *self)
/*[clinic end generated code: output=e6b35ba3d275dc9c input=3589ada9d27db854]*/
{
if (TyComplex_CheckExact(self)) {
return Ty_NewRef(self);
}
else {
return TyComplex_FromCComplex(self->cval);
}
}
static TyObject *
complex_from_string_inner(const char *s, Ty_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 (Ty_ISSPACE(*s))
s++;
if (*s == '(') {
/* Skip over possible bracket from repr(). */
got_bracket = 1;
s++;
while (Ty_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 = TyOS_string_to_double(s, &end, NULL);
if (z == -1.0 && TyErr_Occurred()) {
if (TyErr_ExceptionMatches(TyExc_ValueError))
TyErr_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 = TyOS_string_to_double(s, &end, NULL);
if (y == -1.0 && TyErr_Occurred()) {
if (TyErr_ExceptionMatches(TyExc_ValueError))
TyErr_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 (Ty_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 (Ty_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(_TyType_CAST(type), x, y);
parse_error:
TyErr_SetString(TyExc_ValueError,
"complex() arg is a malformed string");
return NULL;
}
static TyObject *
complex_subtype_from_string(TyTypeObject *type, TyObject *v)
{
const char *s;
TyObject *s_buffer = NULL, *result = NULL;
Ty_ssize_t len;
if (TyUnicode_Check(v)) {
s_buffer = _TyUnicode_TransformDecimalAndSpaceToASCII(v);
if (s_buffer == NULL) {
return NULL;
}
assert(TyUnicode_IS_ASCII(s_buffer));
/* Simply get a pointer to existing ASCII characters. */
s = TyUnicode_AsUTF8AndSize(s_buffer, &len);
assert(s != NULL);
}
else {
TyErr_Format(TyExc_TypeError,
"complex() argument must be a string or a number, not %T",
v);
return NULL;
}
result = _Ty_string_to_number_with_underscores(s, len, "complex", v, type,
complex_from_string_inner);
Ty_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 TyObject *
actual_complex_new(TyTypeObject *type, TyObject *args, TyObject *kwargs)
{
TyObject *res = NULL;
TyNumberMethods *nbr;
if (TyTuple_GET_SIZE(args) > 1 || (kwargs != NULL && TyDict_GET_SIZE(kwargs))) {
return complex_new(type, args, kwargs);
}
if (!TyTuple_GET_SIZE(args)) {
return complex_subtype_from_doubles(type, 0, 0);
}
TyObject *arg = TyTuple_GET_ITEM(args, 0);
/* Special-case for a single argument when type(arg) is complex. */
if (TyComplex_CheckExact(arg) && type == &TyComplex_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 Ty_NewRef(arg);
}
if (TyUnicode_Check(arg)) {
return complex_subtype_from_string(type, arg);
}
TyObject *tmp = try_complex_special_method(arg);
if (tmp) {
Ty_complex c = ((PyComplexObject*)tmp)->cval;
res = complex_subtype_from_doubles(type, c.real, c.imag);
Ty_DECREF(tmp);
}
else if (TyErr_Occurred()) {
return NULL;
}
else if (TyComplex_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. */
Ty_complex c = ((PyComplexObject*)arg)->cval;
res = complex_subtype_from_doubles(type, c.real, c.imag);
}
else if ((nbr = Ty_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 = TyFloat_AsDouble(arg);
if (r != -1.0 || !TyErr_Occurred()) {
res = complex_subtype_from_doubles(type, r, 0);
}
}
else {
TyErr_Format(TyExc_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 TyObject *
complex_new_impl(TyTypeObject *type, TyObject *r, TyObject *i)
/*[clinic end generated code: output=b6c7dd577b537dc1 input=ff4268dc540958a4]*/
{
TyObject *tmp;
TyNumberMethods *nbr, *nbi = NULL;
Ty_complex cr, ci;
int own_r = 0;
int cr_is_complex = 0;
int ci_is_complex = 0;
if (r == NULL) {
r = _TyLong_GetZero();
}
TyObject *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 (TyErr_Occurred()) {
return NULL;
}
nbr = Ty_TYPE(r)->tp_as_number;
if (nbr == NULL ||
(nbr->nb_float == NULL && nbr->nb_index == NULL && !TyComplex_Check(r)))
{
TyErr_Format(TyExc_TypeError,
"complex() argument 'real' must be a real number, not %T",
r);
if (own_r) {
Ty_DECREF(r);
}
return NULL;
}
if (i != NULL) {
nbi = Ty_TYPE(i)->tp_as_number;
if (nbi == NULL ||
(nbi->nb_float == NULL && nbi->nb_index == NULL && !TyComplex_Check(i)))
{
TyErr_Format(TyExc_TypeError,
"complex() argument 'imag' must be a real number, not %T",
i);
if (own_r) {
Ty_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 (TyComplex_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. */
Ty_DECREF(r);
}
nbr = Ty_TYPE(orig_r)->tp_as_number;
if (nbr == NULL ||
(nbr->nb_float == NULL && nbr->nb_index == NULL))
{
if (TyErr_WarnFormat(TyExc_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(TyFloat_Check(tmp));
cr.real = TyFloat_AsDouble(tmp);
cr.imag = 0.0;
Ty_DECREF(tmp);
}
if (i == NULL) {
ci.real = cr.imag;
}
else if (TyComplex_Check(i)) {
if (TyErr_WarnFormat(TyExc_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 = TyFloat_AsDouble(tmp);
Ty_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 TyObject *
complex_from_number_impl(TyTypeObject *type, TyObject *number)
/*[clinic end generated code: output=7248bb593e1871e1 input=3f8bdd3a2bc3facd]*/
{
if (TyComplex_CheckExact(number) && type == &TyComplex_Type) {
Ty_INCREF(number);
return number;
}
Ty_complex cv = TyComplex_AsCComplex(number);
if (cv.real == -1.0 && TyErr_Occurred()) {
return NULL;
}
TyObject *result = TyComplex_FromCComplex(cv);
if (type != &TyComplex_Type && result != NULL) {
Ty_SETREF(result, PyObject_CallOneArg((TyObject *)type, result));
}
return result;
}
static TyMethodDef complex_methods[] = {
COMPLEX_FROM_NUMBER_METHODDEF
COMPLEX_CONJUGATE_METHODDEF
COMPLEX___COMPLEX___METHODDEF
COMPLEX___GETNEWARGS___METHODDEF
COMPLEX___FORMAT___METHODDEF
{NULL, NULL} /* sentinel */
};
static TyMemberDef complex_members[] = {
{"real", Ty_T_DOUBLE, offsetof(PyComplexObject, cval.real), Py_READONLY,
"the real part of a complex number"},
{"imag", Ty_T_DOUBLE, offsetof(PyComplexObject, cval.imag), Py_READONLY,
"the imaginary part of a complex number"},
{0},
};
static TyNumberMethods complex_as_number = {
complex_add, /* nb_add */
complex_sub, /* nb_subtract */
complex_mul, /* nb_multiply */
0, /* nb_remainder */
0, /* nb_divmod */
complex_pow, /* nb_power */
complex_neg, /* nb_negative */
complex_pos, /* nb_positive */
complex_abs, /* nb_absolute */
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 */
complex_div, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
};
TyTypeObject TyComplex_Type = {
TyVarObject_HEAD_INIT(&TyType_Type, 0)
"complex",
sizeof(PyComplexObject),
0,
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
complex_repr, /* tp_repr */
&complex_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
complex_hash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Ty_TPFLAGS_DEFAULT | Ty_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 */
TyType_GenericAlloc, /* tp_alloc */
actual_complex_new, /* tp_new */
PyObject_Free, /* tp_free */
.tp_version_tag = _Ty_TYPE_VERSION_COMPLEX,
};