Commit dd37f81e authored by Lisandro Dalcin's avatar Lisandro Dalcin

Seamless C99/C++ complex numbers support (ticket #398)

parent 61e95f53
...@@ -396,7 +396,6 @@ class GlobalState(object): ...@@ -396,7 +396,6 @@ class GlobalState(object):
code_layout = [ code_layout = [
'h_code', 'h_code',
'complex_numbers_utility_code',
'utility_code_proto_before_types', 'utility_code_proto_before_types',
'type_declarations', 'type_declarations',
'utility_code_proto', 'utility_code_proto',
......
...@@ -544,9 +544,8 @@ class ExprNode(Node): ...@@ -544,9 +544,8 @@ class ExprNode(Node):
elif src.type.is_pyobject: elif src.type.is_pyobject:
src = CoerceFromPyTypeNode(dst_type, src, env) src = CoerceFromPyTypeNode(dst_type, src, env)
elif (dst_type.is_complex elif (dst_type.is_complex
and src_type != dst_type and src_type != dst_type
and dst_type.assignable_from(src_type) and dst_type.assignable_from(src_type)):
and not env.directives['c99_complex']):
src = CoerceToComplexNode(src, dst_type, env) src = CoerceToComplexNode(src, dst_type, env)
else: # neither src nor dst are py types else: # neither src nor dst are py types
# Added the string comparison, since for c types that # Added the string comparison, since for c types that
...@@ -1007,8 +1006,6 @@ class ImagNode(AtomicExprNode): ...@@ -1007,8 +1006,6 @@ class ImagNode(AtomicExprNode):
def calculate_result_code(self): def calculate_result_code(self):
if self.type.is_pyobject: if self.type.is_pyobject:
return self.result() return self.result()
elif self.c99_complex:
return "%rj" % float(self.value)
else: else:
return "%s(0, %r)" % (self.type.from_parts, float(self.value)) return "%s(0, %r)" % (self.type.from_parts, float(self.value))
...@@ -1020,8 +1017,6 @@ class ImagNode(AtomicExprNode): ...@@ -1020,8 +1017,6 @@ class ImagNode(AtomicExprNode):
float(self.value), float(self.value),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
else:
self.c99_complex = code.globalstate.directives['c99_complex']
...@@ -3014,7 +3009,7 @@ class AttributeNode(ExprNode): ...@@ -3014,7 +3009,7 @@ class AttributeNode(ExprNode):
else: else:
return self.member return self.member
elif obj.type.is_complex: elif obj.type.is_complex:
return "__Pyx_%s_PART(%s)" % (self.member.upper(), obj_code) return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
else: else:
return "%s%s%s" % (obj_code, self.op, self.member) return "%s%s%s" % (obj_code, self.op, self.member)
...@@ -4071,7 +4066,7 @@ class UnaryMinusNode(UnopNode): ...@@ -4071,7 +4066,7 @@ class UnaryMinusNode(UnopNode):
else: else:
self.type_error() self.type_error()
if self.type.is_complex: if self.type.is_complex:
self.infix = env.directives['c99_complex'] self.infix = False
def py_operation_function(self): def py_operation_function(self):
return "PyNumber_Negative" return "PyNumber_Negative"
...@@ -4498,7 +4493,7 @@ class NumBinopNode(BinopNode): ...@@ -4498,7 +4493,7 @@ class NumBinopNode(BinopNode):
if not self.type: if not self.type:
self.type_error() self.type_error()
return return
if self.type.is_complex and not env.directives['c99_complex']: if self.type.is_complex:
self.infix = False self.infix = False
if not self.infix: if not self.infix:
self.operand1 = self.operand1.coerce_to(self.type, env) self.operand1 = self.operand1.coerce_to(self.type, env)
...@@ -5146,9 +5141,11 @@ class CmpNode(object): ...@@ -5146,9 +5141,11 @@ class CmpNode(object):
richcmp_constants[op], richcmp_constants[op],
code.error_goto_if_null(result_code, self.pos))) code.error_goto_if_null(result_code, self.pos)))
code.put_gotref(result_code) code.put_gotref(result_code)
elif operand1.type.is_complex and not code.globalstate.directives['c99_complex']: elif operand1.type.is_complex:
if op == "!=": negation = "!" if op == "!=":
else: negation = "" negation = "!"
else:
negation = ""
code.putln("%s = %s(%s%s(%s, %s));" % ( code.putln("%s = %s(%s%s(%s, %s));" % (
result_code, result_code,
coerce_result, coerce_result,
...@@ -5684,8 +5681,8 @@ class CoerceToComplexNode(CoercionNode): ...@@ -5684,8 +5681,8 @@ class CoerceToComplexNode(CoercionNode):
def calculate_result_code(self): def calculate_result_code(self):
if self.arg.type.is_complex: if self.arg.type.is_complex:
real_part = "__Pyx_REAL_PART(%s)" % self.arg.result() real_part = "__Pyx_CREAL(%s)" % self.arg.result()
imag_part = "__Pyx_IMAG_PART(%s)" % self.arg.result() imag_part = "__Pyx_CIMAG(%s)" % self.arg.result()
else: else:
real_part = self.arg.result() real_part = self.arg.result()
imag_part = "0" imag_part = "0"
......
...@@ -559,12 +559,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -559,12 +559,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#include <math.h>") code.putln("#include <math.h>")
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env)) code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code) self.generate_includes(env, cimported_modules, code)
if env.directives['c99_complex']: if env.directives['ccomplex']:
code.putln("#ifndef _Complex_I") code.putln("")
code.putln("#include <complex.h>") code.putln("#if !defined(CYTHON_CCOMPLEX)")
code.putln("#define CYTHON_CCOMPLEX 1")
code.putln("#endif") code.putln("#endif")
code.putln("#define __PYX_USE_C99_COMPLEX defined(_Complex_I)") code.putln("")
code.putln('')
code.put(Nodes.utility_function_predeclarations) code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations) code.put(PyrexTypes.type_conversion_predeclarations)
code.put(Nodes.branch_prediction_macros) code.put(Nodes.branch_prediction_macros)
......
...@@ -3134,7 +3134,7 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -3134,7 +3134,7 @@ class InPlaceAssignmentNode(AssignmentNode):
c_op = "/" c_op = "/"
elif c_op == "**": elif c_op == "**":
error(self.pos, "No C inplace power operator") error(self.pos, "No C inplace power operator")
elif self.lhs.type.is_complex and not code.globalstate.directives['c99_complex']: elif self.lhs.type.is_complex:
error(self.pos, "Inplace operators not implemented for complex types.") error(self.pos, "Inplace operators not implemented for complex types.")
# have to do assignment directly to avoid side-effects # have to do assignment directly to avoid side-effects
......
...@@ -65,7 +65,7 @@ option_defaults = { ...@@ -65,7 +65,7 @@ option_defaults = {
'cdivision_warnings': False, 'cdivision_warnings': False,
'always_allow_keywords': False, 'always_allow_keywords': False,
'wraparound' : True, 'wraparound' : True,
'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this... 'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "", 'callspec' : "",
'profile': False, 'profile': False,
'infer_types': False, 'infer_types': False,
......
...@@ -823,7 +823,7 @@ class CFloatType(CNumericType): ...@@ -823,7 +823,7 @@ class CFloatType(CNumericType):
class CComplexType(CNumericType): class CComplexType(CNumericType):
is_complex = 1 is_complex = 1
to_py_function = "__pyx_PyObject_from_complex" to_py_function = "__pyx_PyComplex_FromComplex"
has_attributes = 1 has_attributes = 1
scope = None scope = None
...@@ -859,7 +859,9 @@ class CComplexType(CNumericType): ...@@ -859,7 +859,9 @@ class CComplexType(CNumericType):
return self.base_declaration_code(base, entity_code) return self.base_declaration_code(base, entity_code)
def sign_and_name(self): def sign_and_name(self):
return Naming.type_prefix + self.real_type.specalization_name() + "_complex" real_type_name = self.real_type.specalization_name()
real_type_name = real_type_name.replace('long__double','long_double')
return Naming.type_prefix + real_type_name + "_complex"
def assignable_from_resolved_type(self, src_type): def assignable_from_resolved_type(self, src_type):
return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type) return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type)
...@@ -877,21 +879,34 @@ class CComplexType(CNumericType): ...@@ -877,21 +879,34 @@ class CComplexType(CNumericType):
def create_declaration_utility_code(self, env): def create_declaration_utility_code(self, env):
# This must always be run, because a single CComplexType instance can be shared # This must always be run, because a single CComplexType instance can be shared
# across multiple compilations (the one created in the module scope) # across multiple compilations (the one created in the module scope)
env.use_utility_code(complex_generic_utility_code) env.use_utility_code(complex_header_utility_code)
env.use_utility_code( env.use_utility_code(complex_real_imag_utility_code)
complex_arithmatic_utility_code.specialize(self, for utility_code in (complex_type_utility_code,
math_h_modifier = self.real_type.math_h_modifier, complex_from_parts_utility_code,
real_type = self.real_type.declaration_code(''))) complex_arithmatic_utility_code):
env.use_utility_code(
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.real_type.math_h_modifier))
return True
def create_to_py_utility_code(self, env):
env.use_utility_code(complex_real_imag_utility_code)
env.use_utility_code(complex_to_py_utility_code)
return True return True
def create_from_py_utility_code(self, env): def create_from_py_utility_code(self, env):
self.real_type.create_from_py_utility_code(env) self.real_type.create_from_py_utility_code(env)
env.use_utility_code(
complex_conversion_utility_code.specialize(self, for utility_code in (complex_from_parts_utility_code,
math_h_modifier = self.real_type.math_h_modifier, complex_from_py_utility_code):
real_type = self.real_type.declaration_code(''), env.use_utility_code(
type_convert = self.real_type.from_py_function)) utility_code.specialize(
self.from_py_function = "__pyx_PyObject_As_" + self.specalization_name() self,
real_type = self.real_type.declaration_code(''),
m = self.real_type.math_h_modifier))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specalization_name()
return True return True
def lookup_op(self, nargs, op): def lookup_op(self, nargs, op):
...@@ -901,7 +916,8 @@ class CComplexType(CNumericType): ...@@ -901,7 +916,8 @@ class CComplexType(CNumericType):
pass pass
try: try:
op_name = complex_ops[nargs, op] op_name = complex_ops[nargs, op]
self.binops[nargs, op] = func_name = "%s_%s" % (self.specalization_name(), op_name) modifier = self.real_type.math_h_modifier
self.binops[nargs, op] = func_name = "__Pyx_c_%s%s" % (op_name, modifier)
return func_name return func_name
except KeyError: except KeyError:
return None return None
...@@ -915,114 +931,210 @@ class CComplexType(CNumericType): ...@@ -915,114 +931,210 @@ class CComplexType(CNumericType):
complex_ops = { complex_ops = {
(1, '-'): 'neg', (1, '-'): 'neg',
(1, 'zero'): 'is_zero', (1, 'zero'): 'is_zero',
(2, '+'): 'add', (2, '+'): 'sum',
(2, '-') : 'sub', (2, '-'): 'diff',
(2, '*'): 'mul', (2, '*'): 'prod',
(2, '/'): 'div', (2, '/'): 'quot',
(2, '=='): 'eq', (2, '=='): 'eq',
} }
complex_generic_utility_code = UtilityCode( complex_header_utility_code = UtilityCode(
proto_block='utility_code_proto_before_types',
proto=""" proto="""
#if __PYX_USE_C99_COMPLEX #if !defined(CYTHON_CCOMPLEX)
#define __Pyx_REAL_PART(z) __real__(z) #if defined(__cplusplus)
#define __Pyx_IMAG_PART(z) __imag__(z) #define CYTHON_CCOMPLEX 1
#else #elif defined(_Complex_I)
#define __Pyx_REAL_PART(z) ((z).real) #define CYTHON_CCOMPLEX 1
#define __Pyx_IMAG_PART(z) ((z).imag) #else
#define CYTHON_CCOMPLEX 0
#endif
#endif #endif
#define __pyx_PyObject_from_complex(z) PyComplex_FromDoubles((double)__Pyx_REAL_PART(z), (double)__Pyx_IMAG_PART(z)) #if CYTHON_CCOMPLEX
#ifdef __cplusplus
#include <complex>
#else
#include <complex.h>
#endif
#endif
""") """)
complex_conversion_utility_code = UtilityCode( complex_real_imag_utility_code = UtilityCode(
proto=""" proto="""
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o); /* proto */ #if CYTHON_CCOMPLEX
""", #ifdef __cplusplus
impl=""" #define __Pyx_CREAL(z) ((z).real())
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o) { #define __Pyx_CIMAG(z) ((z).imag())
if (PyComplex_CheckExact(o)) { #else
return %(type_name)s_from_parts( #define __Pyx_CREAL(z) (__real__(z))
(%(real_type)s)((PyComplexObject *)o)->cval.real, #define __Pyx_CIMAG(z) (__imag__(z))
(%(real_type)s)((PyComplexObject *)o)->cval.imag); #endif
} #else
else { #define __Pyx_CREAL(z) ((z).real)
Py_complex cval = PyComplex_AsCComplex(o); #define __Pyx_CIMAG(z) ((z).imag)
return %(type_name)s_from_parts((%(real_type)s)cval.real, (%(real_type)s)cval.imag); #endif
}
}
""") """)
complex_arithmatic_utility_code = UtilityCode( complex_type_utility_code = UtilityCode(
proto_block='utility_code_proto_before_types',
proto=""" proto="""
#if __PYX_USE_C99_COMPLEX #if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< %(real_type)s > %(type_name)s;
#else
typedef %(real_type)s _Complex %(type_name)s; typedef %(real_type)s _Complex %(type_name)s;
#endif
#else
typedef struct { %(real_type)s real, imag; } %(type_name)s;
#endif
""")
complex_from_parts_utility_code = UtilityCode(
proto_block='utility_code_proto_before_types',
proto="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#endif
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#endif
""",
impl="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return ::std::complex< %(real_type)s >(x, y);
}
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) { static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return x + y*(%(type)s)_Complex_I; return x + y*(%(type)s)_Complex_I;
} }
#endif
#define %(type_name)s_is_zero(a) ((a) == 0)
#define %(type_name)s_eq(a, b) ((a) == (b))
#define %(type_name)s_add(a, b) ((a)+(b))
#define %(type_name)s_sub(a, b) ((a)-(b))
#define %(type_name)s_mul(a, b) ((a)*(b))
#define %(type_name)s_div(a, b) ((a)/(b))
#define %(type_name)s_neg(a) (-(a))
#else #else
typedef struct { %(real_type)s real, imag; } %(type_name)s;
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) { static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
%(type)s c; c.real = x; c.imag = y; return c; %(type)s z;
} z.real = x;
z.imag = y;
static INLINE int %(type_name)s_is_zero(%(type)s a) { return z;
return (a.real == 0) & (a.imag == 0);
} }
#endif
""")
static INLINE int %(type_name)s_eq(%(type)s a, %(type)s b) { complex_to_py_utility_code = UtilityCode(
return (a.real == b.real) & (a.imag == b.imag); proto="""
} #define __pyx_PyComplex_FromComplex(z) \\
PyComplex_FromDoubles((double)__Pyx_CREAL(z), \\
(double)__Pyx_CIMAG(z))
""")
complex_from_py_utility_code = UtilityCode(
proto="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject*);
""",
impl="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject* o) {
Py_complex cval;
if (PyComplex_CheckExact(o))
cval = ((PyComplexObject *)o)->cval;
else
cval = PyComplex_AsCComplex(o);
return %(type_name)s_from_parts(
(%(real_type)s)cval.real,
(%(real_type)s)cval.imag);
}
""")
static INLINE %(type)s %(type_name)s_add(%(type)s a, %(type)s b) { complex_arithmatic_utility_code = UtilityCode(
proto="""
#if CYTHON_CCOMPLEX
#define __Pyx_c_eq%(m)s(a, b) ((a)==(b))
#define __Pyx_c_sum%(m)s(a, b) ((a)+(b))
#define __Pyx_c_diff%(m)s(a, b) ((a)-(b))
#define __Pyx_c_prod%(m)s(a, b) ((a)*(b))
#define __Pyx_c_quot%(m)s(a, b) ((a)/(b))
#define __Pyx_c_neg%(m)s(a) (-(a))
#ifdef __cplusplus
#define __Pyx_c_is_zero%(m)s(z) ((z)==0.0)
#define __Pyx_c_conj%(m)s(z) (::std::conj(z))
/*#define __Pyx_c_abs%(m)s(z) (::std::abs(z))*/
#else
#define __Pyx_c_is_zero%(m)s(z) ((z)==0)
#define __Pyx_c_conj%(m)s(z) (conj%(m)s(z))
/*#define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))*/
#endif
#else
static INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s);
static INLINE int __Pyx_c_is_zero%(m)s(%(type)s);
static INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s);
/*static INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);*/
#endif
""",
impl="""
#if CYTHON_CCOMPLEX
#else
static INLINE int __Pyx_c_eq%(m)s(%(type)s a, %(type)s b) {
return (a.real == b.real) && (a.imag == b.imag);
}
static INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s a, %(type)s b) {
%(type)s z; %(type)s z;
z.real = a.real + b.real; z.real = a.real + b.real;
z.imag = a.imag + b.imag; z.imag = a.imag + b.imag;
return z; return z;
} }
static INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s a, %(type)s b) {
static INLINE %(type)s %(type_name)s_sub(%(type)s a, %(type)s b) {
%(type)s z; %(type)s z;
z.real = a.real - b.real; z.real = a.real - b.real;
z.imag = a.imag - b.imag; z.imag = a.imag - b.imag;
return z; return z;
} }
static INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s a, %(type)s b) {
static INLINE %(type)s %(type_name)s_mul(%(type)s a, %(type)s b) {
%(type)s z; %(type)s z;
z.real = a.real * b.real - a.imag * b.imag; z.real = a.real * b.real - a.imag * b.imag;
z.imag = a.real * b.imag + a.imag * b.real; z.imag = a.real * b.imag + a.imag * b.real;
return z; return z;
} }
static INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s a, %(type)s b) {
static INLINE %(type)s %(type_name)s_div(%(type)s a, %(type)s b) {
%(type)s z; %(type)s z;
%(real_type)s denom = b.real*b.real + b.imag*b.imag; %(real_type)s denom = b.real * b.real + b.imag * b.imag;
z.real = (a.real * b.real + a.imag * b.imag) / denom; z.real = (a.real * b.real + a.imag * b.imag) / denom;
z.imag = (a.imag * b.real - a.real * b.imag) / denom; z.imag = (a.imag * b.real - a.real * b.imag) / denom;
return z; return z;
} }
static INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s a) {
static INLINE %(type)s %(type_name)s_neg(%(type)s a) {
%(type)s z; %(type)s z;
z.real = -a.real; z.real = -a.real;
z.imag = -a.imag; z.imag = -a.imag;
return z; return z;
} }
static INLINE int __Pyx_c_is_zero%(m)s(%(type)s a) {
return (a.real == 0) && (a.imag == 0);
}
static INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s a) {
%(type)s z;
z.real = a.real;
z.imag = -a.imag;
return z;
}
/*
static INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
#if HAVE_HYPOT
return hypot%(m)s(z.real, z.imag);
#else
return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
#endif
}
*/
#endif #endif
""", proto_block='complex_numbers_utility_code') """)
class CArrayType(CType): class CArrayType(CType):
......
...@@ -1157,7 +1157,7 @@ class StructOrUnionScope(Scope): ...@@ -1157,7 +1157,7 @@ class StructOrUnionScope(Scope):
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0, cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()): api = 0, in_pxd = 0, modifiers = ()):
self.declare_var(name, type, pos, cname, visibility) return self.declare_var(name, type, pos, cname, visibility)
class ClassScope(Scope): class ClassScope(Scope):
# Abstract base class for namespace of # Abstract base class for namespace of
......
__doc__ = u""" __doc__ = u"""
>>> test_object_conversion(2) >>> test_object_conversion(2)
((2+0j), (2+0j)) ((2+0j), (2+0j), (2+0j))
>>> test_object_conversion(2j - 0.5) >>> test_object_conversion(2j - 0.5)
((-0.5+2j), (-0.5+2j)) ((-0.5+2j), (-0.5+2j), (-0.5+2j))
>>> test_arithmetic(2j, 4j) >>> test_arithmetic(2j, 4j)
(-2j, 6j, -2j, (-8+0j), (0.5+0j)) (2j, -2j, 6j, -2j, (-8+0j), (0.5+0j))
>>> test_arithmetic(6+12j, 3j) >>> test_arithmetic(6+12j, 3j)
((-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j)) ((6+12j), (-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j))
>>> test_arithmetic(5-10j, 3+4j) >>> test_arithmetic(5-10j, 3+4j)
((-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j)) ((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
>>> test_div_by_zero(4j) ## XXX this is not working
-0.25j ## >>> test_div_by_zero(4j)
>>> test_div_by_zero(0) ## -0.25j
Traceback (most recent call last): ## >>> test_div_by_zero(0)
... ## Traceback (most recent call last):
ZeroDivisionError: float division ## ...
## ZeroDivisionError: float division
>>> test_coercion(1, 1.5, 2.5, 4+1j, 10j) >>> test_coercion(1, 1.5, 2.5, 4+1j, 10j)
(1+0j) (1+0j)
...@@ -56,6 +57,10 @@ __doc__ = u""" ...@@ -56,6 +57,10 @@ __doc__ = u"""
(1+2j) (1+2j)
>>> test_real_imag_assignment(1.5, -3.5) >>> test_real_imag_assignment(1.5, -3.5)
(1.5-3.5j) (1.5-3.5j)
## XXX not implemented yet!
## >>> test_conjugate(1+2j)
## (1-2j)
""" """
#cdef extern from "complex.h": #cdef extern from "complex.h":
...@@ -65,15 +70,17 @@ cimport cython ...@@ -65,15 +70,17 @@ cimport cython
def test_object_conversion(o): def test_object_conversion(o):
cdef float complex a = o cdef float complex a = o
cdef double complex z = o cdef double complex b = o
return (a, z) cdef long double complex c = o
return (a, b, c)
def test_arithmetic(double complex z, double complex w): def test_arithmetic(double complex z, double complex w):
return -z, z+w, z-w, z*w, z/w return +z, -z, z+w, z-w, z*w, z/w
@cython.cdivision(False) ## XXX this is not working
def test_div_by_zero(double complex z): ## @cython.cdivision(False)
return 1/z ## def test_div_by_zero(double complex z):
## return 1/z
def test_coercion(int a, float b, double c, float complex d, double complex e): def test_coercion(int a, float b, double c, float complex d, double complex e):
cdef double complex z cdef double complex z
...@@ -102,3 +109,6 @@ def test_real_imag_assignment(object a, double b): ...@@ -102,3 +109,6 @@ def test_real_imag_assignment(object a, double b):
z.imag = b z.imag = b
return z return z
## XXX not implemented yet!
## def test_conjugate(float complex z):
## return z.conjugate()
cdef extern from "complex_numbers_c89_T398.h": pass
include "complex_numbers_T305.pyx"
#if !defined(__cplusplus)
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) \
|| defined(__GNUC__) \
|| defined(__INTEL_COMPILER) \
|| defined(__IBMC__) \
#include <complex.h>
#if !defined(_Complex_I)
#error The "complex.h" header does not define the '_Complex_I' macro.
#error Please report this to Cython developers <cython-dev@codespeak.net>
#endif
#endif
#endif
cdef extern from "complex_numbers_c99_T398.h": pass
include "complex_numbers_T305.pyx"
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
cdef extern from "complex_numbers_cxx_T398.h": pass
include "complex_numbers_T305.pyx"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment