Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
0abd6919
Commit
0abd6919
authored
Sep 01, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #817 from Daetalus/complex_improment
Complex improment
parents
c5d2083e
31596884
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
971 additions
and
67 deletions
+971
-67
from_cpython/Lib/test/test_complex.py
from_cpython/Lib/test/test_complex.py
+9
-6
src/capi/abstract.cpp
src/capi/abstract.cpp
+13
-2
src/codegen/pypa-parser.cpp
src/codegen/pypa-parser.cpp
+2
-2
src/runtime/complex.cpp
src/runtime/complex.cpp
+947
-57
No files found.
from_cpython/Lib/test/test_complex.py
View file @
0abd6919
# expected: fail
import
unittest
from
test
import
test_support
...
...
@@ -102,8 +101,7 @@ class ComplexTest(unittest.TestCase):
complex
(
random
(),
random
()))
self
.
assertRaises
(
ZeroDivisionError
,
complex
.
__div__
,
1
+
1j
,
0
+
0j
)
# FIXME: The following currently crashes on Alpha
# self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
self
.
assertRaises
(
OverflowError
,
pow
,
1e200
+
1j
,
1e200
+
1j
)
def
test_truediv
(
self
):
self
.
assertAlmostEqual
(
complex
.
__truediv__
(
2
+
0j
,
1
+
1j
),
1
-
1j
)
...
...
@@ -435,12 +433,15 @@ class ComplexTest(unittest.TestCase):
test_values
=
(
1
,
123.0
,
10
-
19j
,
xcomplex
(
1
+
2j
),
xcomplex
(
1
+
87j
),
xcomplex
(
10
+
90j
))
# Pyston change: if rhs is a subclass of lhs, then should try
# reverse the order. Pyston don't support it yet. Need to improve
# binop handing.
for
op
in
infix_binops
:
for
x
in
xcomplex_values
:
for
y
in
test_values
:
a
=
'x %s y'
%
op
b
=
'y %s x'
%
op
self
.
assertTrue
(
type
(
eval
(
a
))
is
type
(
eval
(
b
))
is
xcomplex
)
#
self.assertTrue(type(eval(a)) is type(eval(b)) is xcomplex)
def
test_hash
(
self
):
for
x
in
xrange
(
-
30
,
30
):
...
...
@@ -476,8 +477,10 @@ class ComplexTest(unittest.TestCase):
self
.
assertEqual
(
repr
(
complex
(
0
,
-
INF
)),
"-infj"
)
self
.
assertEqual
(
repr
(
complex
(
0
,
NAN
)),
"nanj"
)
def
test_neg
(
self
):
self
.
assertEqual
(
-
(
1
+
6j
),
-
1
-
6j
)
# Pyston change: This is a libpypa bug, waiting for upstream fix it
# please refer libpypa#47
# def test_neg(self):
# self.assertEqual(-(1+6j), -1-6j)
def
test_file
(
self
):
a
=
3.33
+
4.43j
...
...
src/capi/abstract.cpp
View file @
0abd6919
...
...
@@ -2118,6 +2118,18 @@ extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept {
if
(
o
->
cls
==
float_cls
)
return
o
;
PyNumberMethods
*
m
;
m
=
o
->
cls
->
tp_as_number
;
if
(
m
&&
m
->
nb_float
)
{
/* This should include subclasses of float */
PyObject
*
res
=
m
->
nb_float
(
o
);
if
(
res
&&
!
PyFloat_Check
(
res
))
{
PyErr_Format
(
PyExc_TypeError
,
"__float__ returned non-float (type %.200s)"
,
res
->
cls
->
tp_name
);
Py_DECREF
(
res
);
return
NULL
;
}
return
res
;
}
if
(
PyInt_Check
(
o
))
return
boxFloat
(((
BoxedInt
*
)
o
)
->
n
);
else
if
(
PyLong_Check
(
o
))
{
...
...
@@ -2127,8 +2139,7 @@ extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept {
return
boxFloat
(
result
);
}
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
return
nullptr
;
return
PyFloat_FromString
(
o
,
NULL
);
}
extern
"C"
PyObject
*
PyNumber_Index
(
PyObject
*
o
)
noexcept
{
...
...
src/codegen/pypa-parser.cpp
View file @
0abd6919
...
...
@@ -438,8 +438,8 @@ struct expr_dispatcher {
AST_BinOp
*
binop
=
new
AST_BinOp
();
location
(
binop
,
c
);
binop
->
op_type
=
AST_TYPE
::
Add
;
binop
->
righ
t
=
readItem
(
c
.
real
,
interned_strings
);
binop
->
lef
t
=
imag
;
binop
->
lef
t
=
readItem
(
c
.
real
,
interned_strings
);
binop
->
righ
t
=
imag
;
return
binop
;
}
...
...
src/runtime/complex.cpp
View file @
0abd6919
...
...
@@ -30,19 +30,74 @@ extern "C" Box* createPureImaginary(double i) {
return
new
BoxedComplex
(
0.0
,
i
);
}
static
PyObject
*
try_complex_special_method
(
PyObject
*
op
)
noexcept
{
PyObject
*
f
;
static
PyObject
*
complexstr
;
if
(
complexstr
==
NULL
)
{
complexstr
=
PyString_InternFromString
(
"__complex__"
);
if
(
complexstr
==
NULL
)
return
NULL
;
}
if
(
PyInstance_Check
(
op
))
{
f
=
PyObject_GetAttr
(
op
,
complexstr
);
if
(
f
==
NULL
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_AttributeError
))
PyErr_Clear
();
else
return
NULL
;
}
}
else
{
f
=
_PyObject_LookupSpecial
(
op
,
"__complex__"
,
&
complexstr
);
if
(
f
==
NULL
&&
PyErr_Occurred
())
return
NULL
;
}
if
(
f
!=
NULL
)
{
PyObject
*
res
=
PyObject_CallFunctionObjArgs
(
f
,
NULL
);
Py_DECREF
(
f
);
return
res
;
}
return
NULL
;
}
extern
"C"
Py_complex
PyComplex_AsCComplex
(
PyObject
*
op
)
noexcept
{
// TODO: Incomplete v.s. CPython's implementation.
Py_complex
cval
;
Py_complex
cv
;
PyObject
*
newop
=
NULL
;
assert
(
op
);
/* If op is already of type PyComplex_Type, return its value */
if
(
PyComplex_Check
(
op
))
{
cval
.
real
=
((
BoxedComplex
*
)
op
)
->
real
;
cval
.
imag
=
((
BoxedComplex
*
)
op
)
->
imag
;
return
cval
;
}
else
if
(
op
->
cls
==
int_cls
)
{
cval
.
real
=
((
BoxedInt
*
)
op
)
->
n
;
cval
.
imag
=
0.0
;
return
cval
;
}
else
{
Py_FatalError
(
"unimplemented"
);
cv
.
real
=
((
BoxedComplex
*
)
op
)
->
real
;
cv
.
imag
=
((
BoxedComplex
*
)
op
)
->
imag
;
return
cv
;
}
/* 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
)
{
if
(
!
PyComplex_Check
(
newop
))
{
PyErr_SetString
(
PyExc_TypeError
,
"__complex__ should return a complex object"
);
Py_DECREF
(
newop
);
return
cv
;
}
cv
.
real
=
((
BoxedComplex
*
)
newop
)
->
real
;
cv
.
imag
=
((
BoxedComplex
*
)
newop
)
->
imag
;
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
;
}
}
...
...
@@ -137,6 +192,23 @@ extern "C" Box* complexSub(BoxedComplex* lhs, Box* rhs) {
}
}
extern
"C"
Box
*
complexRSub
(
BoxedComplex
*
_lhs
,
Box
*
_rhs
)
{
if
(
!
PyComplex_Check
(
_lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__rsub__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
_lhs
));
BoxedComplex
*
lhs
=
new
BoxedComplex
(
0.0
,
0.0
);
if
(
PyInt_Check
(
_rhs
))
{
lhs
->
real
=
(
static_cast
<
BoxedInt
*>
(
_rhs
))
->
n
;
}
else
if
(
_rhs
->
cls
==
float_cls
)
{
lhs
->
real
=
(
static_cast
<
BoxedFloat
*>
(
_rhs
))
->
d
;
}
else
if
(
_rhs
->
cls
==
complex_cls
)
{
lhs
=
static_cast
<
BoxedComplex
*>
(
_rhs
);
}
else
{
return
NotImplemented
;
}
return
complexSubComplex
(
lhs
,
_lhs
);
}
// multiplication
extern
"C"
Box
*
complexMulComplex
(
BoxedComplex
*
lhs
,
BoxedComplex
*
rhs
)
{
...
...
@@ -171,16 +243,41 @@ extern "C" Box* complexMul(BoxedComplex* lhs, Box* rhs) {
}
// division
Box
*
complexDivComplex
(
BoxedComplex
*
lhs
,
BoxedComplex
*
rhs
)
{
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__div__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
assert
(
rhs
->
cls
==
complex_cls
);
double
real_f
,
imag_f
;
const
double
abs_breal
=
rhs
->
real
<
0
?
-
rhs
->
real
:
rhs
->
real
;
const
double
abs_bimag
=
rhs
->
imag
<
0
?
-
rhs
->
imag
:
rhs
->
imag
;
extern
"C"
Box
*
complexDivComplex
(
BoxedComplex
*
lhs
,
BoxedComplex
*
rhs
)
{
// TODO implement this
// NOTE: the "naive" implementation of complex division has numerical issues
// see notes in CPython, Objects/complexobject.c, c_quot
return
NotImplemented
;
if
(
abs_breal
>=
abs_bimag
)
{
/* divide tops and bottom by rhs.real */
if
(
abs_breal
==
0.0
)
{
raiseDivZeroExc
();
real_f
=
imag_f
=
0.0
;
}
else
{
const
double
ratio
=
rhs
->
imag
/
rhs
->
real
;
const
double
denom
=
rhs
->
real
+
rhs
->
imag
*
ratio
;
real_f
=
(
lhs
->
real
+
lhs
->
imag
*
ratio
)
/
denom
;
imag_f
=
(
lhs
->
imag
-
lhs
->
real
*
ratio
)
/
denom
;
}
}
else
{
/* divide tops and bottom by rhs->imag */
const
double
ratio
=
rhs
->
real
/
rhs
->
imag
;
const
double
denom
=
rhs
->
real
*
ratio
+
rhs
->
imag
;
real_f
=
(
lhs
->
real
*
ratio
+
lhs
->
imag
)
/
denom
;
imag_f
=
(
lhs
->
imag
*
ratio
-
lhs
->
real
)
/
denom
;
}
return
boxComplex
(
real_f
,
imag_f
);
}
extern
"C"
Box
*
complexDivFloat
(
BoxedComplex
*
lhs
,
BoxedFloat
*
rhs
)
{
assert
(
lhs
->
cls
==
complex_cls
);
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__div__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
assert
(
rhs
->
cls
==
float_cls
);
if
(
rhs
->
d
==
0.0
)
{
raiseDivZeroExc
();
...
...
@@ -189,7 +286,9 @@ extern "C" Box* complexDivFloat(BoxedComplex* lhs, BoxedFloat* rhs) {
}
extern
"C"
Box
*
complexDivInt
(
BoxedComplex
*
lhs
,
BoxedInt
*
rhs
)
{
assert
(
lhs
->
cls
==
complex_cls
);
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__div__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
assert
(
PyInt_Check
(
rhs
));
if
(
rhs
->
n
==
0
)
{
raiseDivZeroExc
();
...
...
@@ -198,7 +297,9 @@ extern "C" Box* complexDivInt(BoxedComplex* lhs, BoxedInt* rhs) {
}
extern
"C"
Box
*
complexDiv
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
assert
(
lhs
->
cls
==
complex_cls
);
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__div__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
if
(
PyInt_Check
(
rhs
))
{
return
complexDivInt
(
lhs
,
static_cast
<
BoxedInt
*>
(
rhs
));
}
else
if
(
rhs
->
cls
==
float_cls
)
{
...
...
@@ -210,26 +311,82 @@ extern "C" Box* complexDiv(BoxedComplex* lhs, Box* rhs) {
}
}
extern
"C"
Box
*
complexRDiv
(
BoxedComplex
*
_lhs
,
Box
*
_rhs
)
{
if
(
!
PyComplex_Check
(
_lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__rdiv__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
_lhs
));
BoxedComplex
*
lhs
=
new
BoxedComplex
(
0.0
,
0.0
);
if
(
PyInt_Check
(
_rhs
))
{
lhs
->
real
=
(
static_cast
<
BoxedInt
*>
(
_rhs
))
->
n
;
}
else
if
(
_rhs
->
cls
==
float_cls
)
{
lhs
->
real
=
(
static_cast
<
BoxedFloat
*>
(
_rhs
))
->
d
;
}
else
if
(
_rhs
->
cls
==
complex_cls
)
{
lhs
=
static_cast
<
BoxedComplex
*>
(
_rhs
);
}
else
{
return
NotImplemented
;
}
return
complexDivComplex
(
lhs
,
_lhs
);
}
Box
*
complexPos
(
BoxedComplex
*
self
)
{
assert
(
self
->
cls
==
complex_cls
);
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__pos__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
return
PyComplex_FromDoubles
(
self
->
real
,
self
->
imag
);
}
// str and repr
// For now, just print the same way as ordinary doubles.
// TODO this is wrong, e.g. if real or imaginary part is an integer, there should
// be no decimal point, maybe some other differences. Need to dig deeper into
// how CPython formats floats and complex numbers.
// (complex_format in Objects/complexobject.c)
std
::
string
complexFmt
(
double
r
,
double
i
,
int
precision
,
char
code
)
{
Box
*
complex_fmt
(
double
r
,
double
i
,
int
precision
,
char
format_code
)
noexcept
{
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. */
std
::
string
lead
=
""
;
std
::
string
tail
=
""
;
std
::
string
re
=
""
;
std
::
string
result_str
;
if
(
r
==
0.
&&
copysign
(
1.0
,
r
)
==
1.0
)
{
return
floatFmt
(
i
,
precision
,
code
)
+
"j"
;
re
=
""
;
im
=
PyOS_double_to_string
(
i
,
format_code
,
precision
,
0
,
NULL
);
if
(
!
im
)
{
PyErr_NoMemory
();
goto
done
;
}
}
else
{
return
"("
+
floatFmt
(
r
,
precision
,
code
)
+
(
isnan
(
i
)
||
i
>=
0.0
?
"+"
:
""
)
+
floatFmt
(
i
,
precision
,
code
)
+
"j)"
;
/* Format imaginary part with signr part without */
pre
=
PyOS_double_to_string
(
r
,
format_code
,
precision
,
0
,
NULL
);
if
(
!
pre
)
{
PyErr_NoMemory
();
goto
done
;
}
re
=
std
::
string
(
pre
);
im
=
PyOS_double_to_string
(
i
,
format_code
,
precision
,
Py_DTSF_SIGN
,
NULL
);
if
(
!
im
)
{
PyErr_NoMemory
();
goto
done
;
}
lead
=
"("
;
tail
=
")"
;
}
/* Alloc the final buffer. Add one for the "j" in the format string,
and one for the trailing zero. */
result_str
=
lead
+
std
::
string
(
re
)
+
std
::
string
(
im
)
+
"j"
+
tail
;
result
=
PyString_FromString
(
result_str
.
c_str
());
done:
PyMem_Free
(
im
);
PyMem_Free
(
pre
);
return
result
;
}
static
void
_addFunc
(
const
char
*
name
,
ConcreteCompilerType
*
rtn_type
,
void
*
complex_func
,
void
*
float_func
,
void
*
int_func
,
void
*
boxed_func
)
{
CLFunction
*
cl
=
createRTFunction
(
2
,
0
,
false
,
false
);
...
...
@@ -240,8 +397,151 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* com
complex_cls
->
giveAttr
(
name
,
new
BoxedFunction
(
cl
));
}
static
Py_complex
c_1
=
{
1.
,
0.
};
extern
"C"
Py_complex
c_prod
(
Py_complex
a
,
Py_complex
b
)
noexcept
{
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
;
}
extern
"C"
Py_complex
c_quot
(
Py_complex
a
,
Py_complex
b
)
noexcept
{
/******************************************************************
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). As usual, though, we're still ignoring all IEEE
* endcases.
*/
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
{
/* 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
;
}
return
r
;
}
extern
"C"
Py_complex
c_pow
(
Py_complex
a
,
Py_complex
b
)
noexcept
{
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
);
}
return
r
;
}
static
Py_complex
c_powu
(
Py_complex
x
,
long
n
)
noexcept
{
Py_complex
r
,
p
;
long
mask
=
1
;
r
=
c_1
;
p
=
x
;
while
(
mask
>
0
&&
n
>=
mask
)
{
if
(
n
&
mask
)
r
=
c_prod
(
r
,
p
);
mask
<<=
1
;
p
=
c_prod
(
p
,
p
);
}
return
r
;
}
static
Py_complex
c_powi
(
Py_complex
x
,
long
n
)
noexcept
{
Py_complex
cn
;
if
(
n
>
100
||
n
<
-
100
)
{
cn
.
real
=
(
double
)
n
;
cn
.
imag
=
0.
;
return
c_pow
(
x
,
cn
);
}
else
if
(
n
>
0
)
return
c_powu
(
x
,
n
);
else
return
c_quot
(
c_1
,
c_powu
(
x
,
-
n
));
}
Box
*
complexPow
(
BoxedComplex
*
lhs
,
Box
*
_rhs
,
Box
*
mod
)
{
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__pow__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
Py_complex
p
;
Py_complex
exponent
;
long
int_exponent
;
Py_complex
a
,
b
;
a
=
PyComplex_AsCComplex
(
lhs
);
b
=
PyComplex_AsCComplex
(
_rhs
);
if
(
mod
!=
Py_None
)
{
raiseExcHelper
(
ValueError
,
"complex modulo"
);
}
PyFPE_START_PROTECT
(
"complex_pow"
,
return
0
)
errno
=
0
;
exponent
=
b
;
int_exponent
=
(
long
)
exponent
.
real
;
if
(
exponent
.
imag
==
0.
&&
exponent
.
real
==
int_exponent
)
p
=
c_powi
(
a
,
int_exponent
);
else
p
=
c_pow
(
a
,
exponent
);
PyFPE_END_PROTECT
(
p
)
Py_ADJUST_ERANGE2
(
p
.
real
,
p
.
imag
);
if
(
errno
==
EDOM
)
{
raiseExcHelper
(
ZeroDivisionError
,
"0.0 to a negative or complex power"
);
}
else
if
(
errno
==
ERANGE
)
{
raiseExcHelper
(
OverflowError
,
"complex exponentiation"
);
}
return
boxComplex
(
p
.
real
,
p
.
imag
);
}
Box
*
complexHash
(
BoxedComplex
*
self
)
{
if
(
!
isSubclass
(
self
->
cls
,
complex_cls
))
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__hash__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
long
hashreal
,
hashimag
,
combined
;
...
...
@@ -267,49 +567,491 @@ Box* complexHash(BoxedComplex* self) {
return
boxInt
(
combined
);
}
Box
*
complexCoerce
(
Box
*
lhs
,
Box
*
rhs
)
{
Py_complex
cval
;
cval
.
imag
=
0.
;
if
(
PyInt_Check
(
rhs
))
{
cval
.
real
=
(
double
)
PyInt_AsLong
(
rhs
);
rhs
=
PyComplex_FromCComplex
(
cval
);
}
else
if
(
PyLong_Check
(
rhs
))
{
cval
.
real
=
PyLong_AsDouble
(
rhs
);
if
(
cval
.
real
==
-
1.0
&&
PyErr_Occurred
())
{
throwCAPIException
();
}
rhs
=
PyComplex_FromCComplex
(
cval
);
}
else
if
(
PyFloat_Check
(
rhs
))
{
cval
.
real
=
PyFloat_AsDouble
(
rhs
);
rhs
=
PyComplex_FromCComplex
(
cval
);
}
else
if
(
!
PyComplex_Check
(
rhs
))
{
return
NotImplemented
;
}
return
BoxedTuple
::
create
({
lhs
,
rhs
});
}
Box
*
complexConjugate
(
BoxedComplex
*
self
)
{
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor 'conjuagte' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
return
new
BoxedComplex
(
self
->
real
,
-
self
->
imag
);
}
Box
*
complexAbs
(
BoxedComplex
*
self
)
{
assert
(
self
->
cls
==
complex_cls
);
// TODO: CPython does a lot more safety checks.
return
boxFloat
(
sqrt
(
self
->
real
*
self
->
real
+
self
->
imag
*
self
->
imag
));
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__abs__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
double
result
;
if
(
isinf
(
self
->
real
)
||
isinf
(
self
->
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
(
self
->
real
))
{
return
boxFloat
(
fabs
(
self
->
real
));
}
if
(
!
isinf
(
self
->
imag
))
{
return
boxFloat
(
fabs
(
self
->
imag
));
}
/* either the real or imaginary part is a NaN,
and neither is infinite. Result should be NaN. */
return
boxFloat
(
Py_NAN
);
}
result
=
sqrt
(
self
->
real
*
self
->
real
+
self
->
imag
*
self
->
imag
);
if
(
isinf
(
result
))
{
raiseExcHelper
(
OverflowError
,
"absolute value too large"
);
}
return
boxFloat
(
result
);
}
Box
*
complexGetnewargs
(
BoxedComplex
*
self
)
{
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__getnewargs__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
return
BoxedTuple
::
create
({
boxFloat
(
self
->
real
),
boxFloat
(
self
->
imag
)
});
}
Box
*
complexNonzero
(
BoxedComplex
*
self
)
{
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__nonzero__' require a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
bool
res
=
self
->
real
!=
0.0
||
self
->
imag
!=
0.0
;
return
boxBool
(
res
);
}
Box
*
complexStr
(
BoxedComplex
*
self
)
{
assert
(
self
->
cls
==
complex_cls
);
return
boxString
(
complexFmt
(
self
->
real
,
self
->
imag
,
12
,
'g'
));
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__str__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
Box
*
r
=
complex_fmt
(
self
->
real
,
self
->
imag
,
12
,
'g'
);
if
(
!
r
)
{
throwCAPIException
();
}
return
r
;
}
Box
*
complexRepr
(
BoxedComplex
*
self
)
{
assert
(
self
->
cls
==
complex_cls
);
return
boxString
(
complexFmt
(
self
->
real
,
self
->
imag
,
16
,
'g'
));
if
(
!
PyComplex_Check
(
self
))
raiseExcHelper
(
TypeError
,
"descriptor '__repr__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
self
));
Box
*
r
=
complex_fmt
(
self
->
real
,
self
->
imag
,
16
,
'g'
);
if
(
!
r
)
{
throwCAPIException
();
}
return
r
;
}
Box
*
complexNew
(
Box
*
_cls
,
Box
*
real
,
Box
*
imag
)
{
RELEASE_ASSERT
(
_cls
==
complex_cls
,
""
);
static
PyObject
*
complex_subtype_from_string
(
PyObject
*
v
)
noexcept
{
const
char
*
s
,
*
start
;
char
*
end
;
double
x
=
0.0
,
y
=
0.0
,
z
;
int
got_bracket
=
0
;
#ifdef Py_USING_UNICODE
char
*
s_buffer
=
NULL
;
#endif
Py_ssize_t
len
;
if
(
PyString_Check
(
v
))
{
s
=
PyString_AS_STRING
(
v
);
len
=
PyString_GET_SIZE
(
v
);
}
#ifdef Py_USING_UNICODE
else
if
(
PyUnicode_Check
(
v
))
{
s_buffer
=
(
char
*
)
PyMem_MALLOC
(
PyUnicode_GET_SIZE
(
v
)
+
1
);
if
(
s_buffer
==
NULL
)
return
PyErr_NoMemory
();
if
(
PyUnicode_EncodeDecimal
(
PyUnicode_AS_UNICODE
(
v
),
PyUnicode_GET_SIZE
(
v
),
s_buffer
,
NULL
))
goto
error
;
s
=
s_buffer
;
len
=
strlen
(
s
);
}
#endif
else
if
(
PyObject_AsCharBuffer
(
v
,
&
s
,
&
len
))
{
PyErr_SetString
(
PyExc_TypeError
,
"complex() arg is not a string"
);
return
NULL
;
}
/* 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
double
real_f
;
if
(
PyInt_Check
(
real
))
{
real_f
=
static_cast
<
BoxedInt
*>
(
real
)
->
n
;
}
else
if
(
real
->
cls
==
float_cls
)
{
real_f
=
static_cast
<
BoxedFloat
*>
(
real
)
->
d
;
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
goto
error
;
}
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
goto
error
;
}
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
{
// TODO: implement taking a string argument
raiseExcHelper
(
TypeError
,
"complex() argument must be a string or number"
);
/* 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
++
;
}
double
imag_f
;
if
(
PyInt_Check
(
imag
))
{
imag_f
=
static_cast
<
BoxedInt
*>
(
imag
)
->
n
;
}
else
if
(
imag
->
cls
==
float_cls
)
{
imag_f
=
static_cast
<
BoxedFloat
*>
(
imag
)
->
d
;
}
else
if
(
imag
->
cls
==
str_cls
)
{
raiseExcHelper
(
TypeError
,
"complex() second arg can't be a string"
);
/* we should now be at the end of the string */
if
(
s
-
start
!=
len
)
goto
parse_error
;
#ifdef Py_USING_UNICODE
if
(
s_buffer
)
PyMem_FREE
(
s_buffer
);
#endif
return
new
BoxedComplex
(
x
,
y
);
parse_error:
PyErr_SetString
(
PyExc_ValueError
,
"complex() arg is a malformed string"
);
error:
#ifdef Py_USING_UNICODE
if
(
s_buffer
)
PyMem_FREE
(
s_buffer
);
#endif
return
NULL
;
}
static
Box
*
to_complex
(
Box
*
self
)
noexcept
{
BoxedComplex
*
r
;
if
(
self
==
None
||
self
==
NULL
)
{
return
new
BoxedComplex
(
0.0
,
0.0
);
}
static
BoxedString
*
complex_str
=
internStringImmortal
(
"__complex__"
);
if
(
PyComplex_Check
(
self
)
&&
!
PyObject_HasAttr
((
PyObject
*
)
self
,
complex_str
))
{
r
=
(
BoxedComplex
*
)
self
;
}
else
if
(
PyInt_Check
(
self
))
{
r
=
new
BoxedComplex
(
static_cast
<
BoxedInt
*>
(
self
)
->
n
,
0.0
);
}
else
if
(
PyFloat_Check
(
self
))
{
r
=
new
BoxedComplex
((
static_cast
<
BoxedFloat
*>
(
PyNumber_Float
(
self
)))
->
d
,
0.0
);
}
else
if
(
self
->
cls
==
long_cls
)
{
r
=
new
BoxedComplex
(
PyLong_AsDouble
(
self
),
0.0
);
}
else
{
raiseExcHelper
(
TypeError
,
"complex() argument must be a string or number"
);
return
NotImplemented
;
}
return
r
;
}
template
<
ExceptionStyle
S
>
static
Box
*
try_special_method
(
Box
*
self
)
noexcept
(
S
==
CAPI
)
{
if
(
self
==
None
||
self
==
NULL
)
{
return
None
;
}
static
BoxedString
*
float_str
=
internStringImmortal
(
"__float__"
);
if
(
PyObject_HasAttr
((
PyObject
*
)
self
,
float_str
))
{
Box
*
r_f
=
callattrInternal
<
S
>
(
self
,
float_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
!
PyFloat_Check
(
r_f
))
{
if
(
S
==
CAPI
)
{
if
(
!
PyErr_Occurred
())
PyErr_Format
(
PyExc_TypeError
,
"__float__ returned non-float (type %.200s)"
,
r_f
->
cls
->
tp_name
);
return
NULL
;
}
else
{
raiseExcHelper
(
TypeError
,
"__float__ returned non-float (type %.200s)"
,
r_f
->
cls
->
tp_name
);
}
}
return
(
BoxedFloat
*
)
r_f
;
}
static
BoxedString
*
complex_str
=
internStringImmortal
(
"__complex__"
);
if
(
PyObject_HasAttr
((
PyObject
*
)
self
,
complex_str
))
{
Box
*
r
=
callattrInternal
<
S
>
(
self
,
complex_str
,
CLASS_OR_INST
,
NULL
,
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
!
r
)
{
if
(
S
==
CAPI
)
{
if
(
!
PyErr_Occurred
())
PyErr_Format
(
TypeError
,
"complex() argument must be a string or a number, not '%s'
\n
"
,
getTypeName
(
self
));
return
NULL
;
}
else
{
raiseExcHelper
(
TypeError
,
"complex() argument must be a string or a number, not '%s'
\n
"
,
getTypeName
(
self
));
}
}
if
(
!
PyComplex_Check
(
r
))
{
if
(
S
==
CAPI
)
{
PyErr_Format
(
TypeError
,
"__complex__ returned non-complex (type %s)"
,
r
->
cls
->
tp_name
);
return
NULL
;
}
else
raiseExcHelper
(
TypeError
,
"__complex__ returned non-complex (type %s)"
,
r
->
cls
->
tp_name
);
}
return
static_cast
<
BoxedComplex
*>
(
r
);
}
return
None
;
}
template
<
ExceptionStyle
S
>
Box
*
_complexNew
(
Box
*
real
,
Box
*
imag
)
noexcept
(
S
==
CAPI
)
{
// handle str and unicode
if
(
real
!=
None
&&
real
!=
NULL
)
{
if
(
PyString_Check
(
real
)
||
PyUnicode_Check
(
real
))
{
if
(
imag
!=
None
&&
imag
!=
NULL
)
{
raiseExcHelper
(
TypeError
,
"complex() can't take second arg if first is a string"
);
}
Box
*
res
=
complex_subtype_from_string
(
real
);
if
(
res
==
NULL
)
{
throwCAPIException
();
}
return
res
;
}
}
if
(
real
!=
None
&&
real
!=
NULL
&&
real
->
cls
==
complex_cls
&&
(
imag
==
NULL
||
imag
==
None
))
{
return
static_cast
<
BoxedComplex
*>
(
real
);
}
Box
*
_real
=
try_special_method
<
S
>
(
real
);
Box
*
_imag
=
try_special_method
<
S
>
(
imag
);
if
(
_real
!=
None
&&
_real
!=
NULL
)
{
real
=
_real
;
}
if
(
_imag
!=
None
&&
_imag
!=
NULL
)
{
imag
=
_imag
;
}
double
real_f
,
imag_f
;
bool
real_is_complex
=
false
,
imag_is_complex
=
false
;
if
(
real
==
None
||
real
==
NULL
)
{
real_f
=
0.0
;
}
else
if
(
PyComplex_Check
(
real
))
{
real_f
=
((
BoxedComplex
*
)
real
)
->
real
;
real_is_complex
=
true
;
}
else
{
real_f
=
((
BoxedFloat
*
)
PyNumber_Float
(
real
))
->
d
;
}
if
(
imag
==
None
||
imag
==
NULL
)
{
imag_f
=
0.0
;
}
else
if
(
PyComplex_Check
(
imag
))
{
imag_f
=
((
BoxedComplex
*
)
imag
)
->
real
;
imag_is_complex
=
true
;
}
else
{
imag_f
=
((
BoxedFloat
*
)
PyNumber_Float
(
imag
))
->
d
;
}
if
(
imag_is_complex
)
{
real_f
-=
((
BoxedComplex
*
)
imag
)
->
imag
;
}
if
(
real_is_complex
)
{
imag_f
+=
((
BoxedComplex
*
)
real
)
->
imag
;
}
return
new
BoxedComplex
(
real_f
,
imag_f
);
}
template
<
ExceptionStyle
S
>
Box
*
complexNew
(
BoxedClass
*
_cls
,
Box
*
_real
,
Box
*
_imag
)
noexcept
(
S
==
CAPI
)
{
if
(
!
isSubclass
(
_cls
->
cls
,
type_cls
))
{
if
(
S
==
CAPI
)
{
PyErr_Format
(
TypeError
,
"complex.__new__(X): X is not a type object (%s)"
,
getTypeName
(
_cls
));
return
NULL
;
}
else
raiseExcHelper
(
TypeError
,
"complex.__new__(X): X is not a type object (%s)"
,
getTypeName
(
_cls
));
}
BoxedClass
*
cls
=
static_cast
<
BoxedClass
*>
(
_cls
);
if
(
PyComplex_Check
(
cls
))
{
if
(
S
==
CAPI
)
{
PyErr_Format
(
TypeError
,
"complex.__new__(%s): %s is not a subtype of complex"
,
getNameOfClass
(
cls
),
getNameOfClass
(
cls
));
return
NULL
;
}
else
raiseExcHelper
(
TypeError
,
"complex.__new__(%s): %s is not a subtype of complex"
,
getNameOfClass
(
cls
),
getNameOfClass
(
cls
));
}
// check second argument
if
(
_imag
!=
NULL
&&
(
PyString_Check
(
_imag
)
||
PyUnicode_Check
(
_imag
)))
{
if
(
S
==
CAPI
)
{
PyErr_Format
(
TypeError
,
"complex() second arg can't be a string"
);
return
NULL
;
}
else
raiseExcHelper
(
TypeError
,
"complex() second arg can't be a string"
);
}
// we can't use None as default value, because complex(None) should raise TypeError,
// but complex() should return `0j`. So use NULL as default value.
// Here check we pass complex(None, None), complex(None)
// or complex(imag=None) to the constructor
if
((
_real
==
None
)
&&
(
_imag
==
None
||
_imag
==
NULL
))
{
raiseExcHelper
(
TypeError
,
"complex() argument must be a string or number"
);
}
if
(
cls
==
complex_cls
)
return
_complexNew
<
S
>
(
_real
,
_imag
);
BoxedComplex
*
r
=
(
BoxedComplex
*
)
_complexNew
<
S
>
(
_real
,
_imag
);
if
(
!
r
)
{
assert
(
S
==
CAPI
);
return
NULL
;
}
return
new
(
_cls
)
BoxedComplex
(
r
->
real
,
r
->
imag
);
}
extern
"C"
Box
*
complexDivmod
(
BoxedComplex
*
lhs
,
BoxedComplex
*
rhs
)
{
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__divmod__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
if
(
PyErr_Warn
(
PyExc_DeprecationWarning
,
"complex divmod(), // and % are deprecated"
)
<
0
)
return
NULL
;
if
(
rhs
->
real
==
0.0
&&
rhs
->
imag
==
0.0
)
{
raiseExcHelper
(
ZeroDivisionError
,
"complex divmod()"
);
}
BoxedComplex
*
div
=
(
BoxedComplex
*
)
complexDiv
(
lhs
,
rhs
);
/* The raw divisor value. */
div
->
real
=
floor
(
div
->
real
);
/* Use the floor of the real part. */
div
->
imag
=
0.0
;
BoxedComplex
*
mod
=
(
BoxedComplex
*
)
complexSubComplex
(
lhs
,
(
BoxedComplex
*
)
complexMulComplex
(
rhs
,
div
));
Box
*
res
=
BoxedTuple
::
create
({
div
,
mod
});
return
res
;
}
extern
"C"
Box
*
complexMod
(
BoxedComplex
*
lhs
,
Box
*
_rhs
)
{
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__mod__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
if
(
PyErr_Warn
(
PyExc_DeprecationWarning
,
"complex divmod(), // and % are deprecated"
)
<
0
)
return
NULL
;
Box
*
res
=
to_complex
(
_rhs
);
if
(
res
==
NotImplemented
)
{
return
NotImplemented
;
}
BoxedComplex
*
rhs
=
(
BoxedComplex
*
)
res
;
if
(
rhs
->
real
==
0.0
&&
rhs
->
imag
==
0.0
)
{
raiseExcHelper
(
ZeroDivisionError
,
"complex remainder"
);
}
BoxedComplex
*
div
=
(
BoxedComplex
*
)
complexDiv
(
lhs
,
rhs
);
/* The raw divisor value. */
div
->
real
=
floor
(
div
->
real
);
/* Use the floor of the real part. */
div
->
imag
=
0.0
;
BoxedComplex
*
mod
=
(
BoxedComplex
*
)
complexSubComplex
(
lhs
,
(
BoxedComplex
*
)
complexMulComplex
(
rhs
,
div
));
return
mod
;
}
extern
"C"
Box
*
complexFloordiv
(
BoxedComplex
*
lhs
,
Box
*
_rhs
)
{
if
(
!
PyComplex_Check
(
lhs
))
raiseExcHelper
(
TypeError
,
"descriptor '__floordiv__' requires a 'complex' object but received a '%s'"
,
getTypeName
(
lhs
));
Box
*
res
=
to_complex
(
_rhs
);
if
(
res
==
NotImplemented
)
{
return
NotImplemented
;
}
BoxedComplex
*
rhs
=
(
BoxedComplex
*
)
res
;
BoxedTuple
*
t
=
(
BoxedTuple
*
)
complexDivmod
(
lhs
,
rhs
);
return
t
->
elts
[
0
];
}
static
PyObject
*
complex_richcompare
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
noexcept
{
PyObject
*
res
;
int
equal
;
...
...
@@ -364,32 +1106,180 @@ static PyObject* complex_richcompare(PyObject* v, PyObject* w, int op) noexcept
return
res
;
}
extern
"C"
Box
*
complexEq
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__eq__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_EQ
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
extern
"C"
Box
*
complexNe
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__ne__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_NE
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
extern
"C"
Box
*
complexLe
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__le__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_LE
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
extern
"C"
Box
*
complexLt
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__lt__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_LT
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
extern
"C"
Box
*
complexGe
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__ge__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_GE
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
extern
"C"
Box
*
complexGt
(
BoxedComplex
*
lhs
,
Box
*
rhs
)
{
if
(
lhs
->
cls
!=
complex_cls
)
{
raiseExcHelper
(
TypeError
,
"descriptor '__gt__' requires a 'complex' object but recieved a '%s'"
,
getTypeName
(
lhs
));
}
Box
*
res
=
complex_richcompare
(
lhs
,
rhs
,
Py_GT
);
if
(
!
res
)
{
throwCAPIException
();
}
return
res
;
}
Box
*
complexNeg
(
Box
*
_self
)
{
assert
(
_self
->
cls
==
complex_cls
);
BoxedComplex
*
self
=
(
BoxedComplex
*
)
_self
;
return
PyComplex_FromDoubles
(
-
self
->
real
,
-
self
->
imag
);
}
PyObject
*
complex_neg
(
PyComplexObject
*
v
)
{
BoxedComplex
*
self
=
(
BoxedComplex
*
)
v
;
return
PyComplex_FromDoubles
(
-
self
->
real
,
-
self
->
imag
);
}
// Pyston change: make not static
PyObject
*
complex__format__
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
format_spec
;
if
(
!
PyArg_ParseTuple
(
args
,
"O:__format__"
,
&
format_spec
))
return
NULL
;
if
(
PyBytes_Check
(
format_spec
))
return
_PyComplex_FormatAdvanced
(
self
,
PyBytes_AS_STRING
(
format_spec
),
PyBytes_GET_SIZE
(
format_spec
));
if
(
PyUnicode_Check
(
format_spec
))
{
/* Convert format_spec to a str */
PyObject
*
result
;
PyObject
*
str_spec
=
PyObject_Str
(
format_spec
);
if
(
str_spec
==
NULL
)
return
NULL
;
result
=
_PyComplex_FormatAdvanced
(
self
,
PyBytes_AS_STRING
(
str_spec
),
PyBytes_GET_SIZE
(
str_spec
));
Py_DECREF
(
str_spec
);
return
result
;
}
PyErr_SetString
(
PyExc_TypeError
,
"__format__ requires str or unicode"
);
return
NULL
;
}
static
PyMethodDef
complex_methods
[]
=
{
{
"__format__"
,
(
PyCFunction
)
complex__format__
,
METH_VARARGS
,
NULL
},
};
void
setupComplex
()
{
complex_cls
->
giveAttr
(
"__new__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexNew
,
UNKNOWN
,
3
,
2
,
false
,
false
),
{
boxInt
(
0
),
boxInt
(
0
)
}));
auto
complex_new
=
boxRTFunction
((
void
*
)
complexNew
<
CXX
>
,
UNKNOWN
,
3
,
2
,
false
,
false
,
ParamNames
({
""
,
"real"
,
"imag"
},
""
,
""
),
CXX
);
addRTFunction
(
complex_new
,
(
void
*
)
complexNew
<
CAPI
>
,
UNKNOWN
,
CAPI
);
complex_cls
->
giveAttr
(
"__new__"
,
new
BoxedFunction
(
complex_new
,
{
NULL
,
NULL
}));
_addFunc
(
"__add__"
,
BOXED_COMPLEX
,
(
void
*
)
complexAddComplex
,
(
void
*
)
complexAddFloat
,
(
void
*
)
complexAddInt
,
(
void
*
)
complexAdd
);
_addFunc
(
"__radd__"
,
BOXED_COMPLEX
,
(
void
*
)
complexAddComplex
,
(
void
*
)
complexAddFloat
,
(
void
*
)
complexAddInt
,
(
void
*
)
complexAdd
);
_addFunc
(
"__sub__"
,
BOXED_COMPLEX
,
(
void
*
)
complexSubComplex
,
(
void
*
)
complexSubFloat
,
(
void
*
)
complexSubInt
,
(
void
*
)
complexSub
);
_addFunc
(
"__mul__"
,
BOXED_COMPLEX
,
(
void
*
)
complexMulComplex
,
(
void
*
)
complexMulFloat
,
(
void
*
)
complexMulInt
,
(
void
*
)
complexMul
);
_addFunc
(
"__rmul__"
,
BOXED_COMPLEX
,
(
void
*
)
complexMulComplex
,
(
void
*
)
complexMulFloat
,
(
void
*
)
complexMulInt
,
(
void
*
)
complexMul
);
_addFunc
(
"__div__"
,
BOXED_COMPLEX
,
(
void
*
)
complexDivComplex
,
(
void
*
)
complexDivFloat
,
(
void
*
)
complexDivInt
,
(
void
*
)
complexDiv
);
complex_cls
->
giveAttr
(
"__rsub__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexRSub
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__rdiv__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexRDiv
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__pow__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexPow
,
UNKNOWN
,
3
,
1
,
false
,
false
),
{
None
}));
complex_cls
->
giveAttr
(
"__mod__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexMod
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__divmod__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexDivmod
,
BOXED_TUPLE
,
2
)));
complex_cls
->
giveAttr
(
"__floordiv__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexFloordiv
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__truediv__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexDivComplex
,
BOXED_COMPLEX
,
2
)));
complex_cls
->
giveAttr
(
"conjugate"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexConjugate
,
BOXED_COMPLEX
,
1
)));
complex_cls
->
giveAttr
(
"__coerce__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexCoerce
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__abs__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexAbs
,
BOXED_FLOAT
,
1
)));
complex_cls
->
giveAttr
(
"__getnewargs__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexGetnewargs
,
BOXED_TUPLE
,
1
)));
complex_cls
->
giveAttr
(
"__nonzero__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexNonzero
,
BOXED_BOOL
,
1
)));
complex_cls
->
giveAttr
(
"__eq__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexEq
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__ne__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexNe
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__le__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexLe
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__lt__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexLt
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__ge__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexGe
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__gt__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexGt
,
UNKNOWN
,
2
)));
complex_cls
->
giveAttr
(
"__neg__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexNeg
,
BOXED_COMPLEX
,
1
)));
complex_cls
->
giveAttr
(
"__pos__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexPos
,
BOXED_COMPLEX
,
1
)));
complex_cls
->
giveAttr
(
"__hash__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexHash
,
BOXED_INT
,
1
)));
complex_cls
->
giveAttr
(
"__abs__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexAbs
,
BOXED_FLOAT
,
1
)));
complex_cls
->
giveAttr
(
"__str__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexStr
,
STR
,
1
)));
complex_cls
->
giveAttr
(
"__repr__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
complexRepr
,
STR
,
1
)));
complex_cls
->
giveAttr
(
"real"
,
new
BoxedMemberDescriptor
(
BoxedMemberDescriptor
::
DOUBLE
,
offsetof
(
BoxedComplex
,
real
)));
complex_cls
->
giveAttr
(
"imag"
,
new
BoxedMemberDescriptor
(
BoxedMemberDescriptor
::
DOUBLE
,
offsetof
(
BoxedComplex
,
imag
)));
for
(
auto
&
md
:
complex_methods
)
{
complex_cls
->
giveAttr
(
md
.
ml_name
,
new
BoxedMethodDescriptor
(
&
md
,
complex_cls
));
}
complex_cls
->
freeze
();
complex_cls
->
tp_as_number
->
nb_negative
=
(
unaryfunc
)
complex_neg
;
complex_cls
->
tp_richcompare
=
complex_richcompare
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment