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):
code_layout = [
'h_code',
'complex_numbers_utility_code',
'utility_code_proto_before_types',
'type_declarations',
'utility_code_proto',
......
......@@ -545,8 +545,7 @@ class ExprNode(Node):
src = CoerceFromPyTypeNode(dst_type, src, env)
elif (dst_type.is_complex
and src_type != dst_type
and dst_type.assignable_from(src_type)
and not env.directives['c99_complex']):
and dst_type.assignable_from(src_type)):
src = CoerceToComplexNode(src, dst_type, env)
else: # neither src nor dst are py types
# Added the string comparison, since for c types that
......@@ -1007,8 +1006,6 @@ class ImagNode(AtomicExprNode):
def calculate_result_code(self):
if self.type.is_pyobject:
return self.result()
elif self.c99_complex:
return "%rj" % float(self.value)
else:
return "%s(0, %r)" % (self.type.from_parts, float(self.value))
......@@ -1020,8 +1017,6 @@ class ImagNode(AtomicExprNode):
float(self.value),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
else:
self.c99_complex = code.globalstate.directives['c99_complex']
......@@ -3014,7 +3009,7 @@ class AttributeNode(ExprNode):
else:
return self.member
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:
return "%s%s%s" % (obj_code, self.op, self.member)
......@@ -4071,7 +4066,7 @@ class UnaryMinusNode(UnopNode):
else:
self.type_error()
if self.type.is_complex:
self.infix = env.directives['c99_complex']
self.infix = False
def py_operation_function(self):
return "PyNumber_Negative"
......@@ -4498,7 +4493,7 @@ class NumBinopNode(BinopNode):
if not self.type:
self.type_error()
return
if self.type.is_complex and not env.directives['c99_complex']:
if self.type.is_complex:
self.infix = False
if not self.infix:
self.operand1 = self.operand1.coerce_to(self.type, env)
......@@ -5146,9 +5141,11 @@ class CmpNode(object):
richcmp_constants[op],
code.error_goto_if_null(result_code, self.pos)))
code.put_gotref(result_code)
elif operand1.type.is_complex and not code.globalstate.directives['c99_complex']:
if op == "!=": negation = "!"
else: negation = ""
elif operand1.type.is_complex:
if op == "!=":
negation = "!"
else:
negation = ""
code.putln("%s = %s(%s%s(%s, %s));" % (
result_code,
coerce_result,
......@@ -5684,8 +5681,8 @@ class CoerceToComplexNode(CoercionNode):
def calculate_result_code(self):
if self.arg.type.is_complex:
real_part = "__Pyx_REAL_PART(%s)" % self.arg.result()
imag_part = "__Pyx_IMAG_PART(%s)" % self.arg.result()
real_part = "__Pyx_CREAL(%s)" % self.arg.result()
imag_part = "__Pyx_CIMAG(%s)" % self.arg.result()
else:
real_part = self.arg.result()
imag_part = "0"
......
......@@ -559,12 +559,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#include <math.h>")
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code)
if env.directives['c99_complex']:
code.putln("#ifndef _Complex_I")
code.putln("#include <complex.h>")
if env.directives['ccomplex']:
code.putln("")
code.putln("#if !defined(CYTHON_CCOMPLEX)")
code.putln("#define CYTHON_CCOMPLEX 1")
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(PyrexTypes.type_conversion_predeclarations)
code.put(Nodes.branch_prediction_macros)
......
......@@ -3134,7 +3134,7 @@ class InPlaceAssignmentNode(AssignmentNode):
c_op = "/"
elif c_op == "**":
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.")
# have to do assignment directly to avoid side-effects
......
......@@ -65,7 +65,7 @@ option_defaults = {
'cdivision_warnings': False,
'always_allow_keywords': False,
'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' : "",
'profile': False,
'infer_types': False,
......
This diff is collapsed.
......@@ -1157,7 +1157,7 @@ class StructOrUnionScope(Scope):
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0,
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):
# Abstract base class for namespace of
......
__doc__ = u"""
>>> test_object_conversion(2)
((2+0j), (2+0j))
((2+0j), (2+0j), (2+0j))
>>> 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)
(-2j, 6j, -2j, (-8+0j), (0.5+0j))
(2j, -2j, 6j, -2j, (-8+0j), (0.5+0j))
>>> 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)
((-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)
-0.25j
>>> test_div_by_zero(0)
Traceback (most recent call last):
...
ZeroDivisionError: float division
## XXX this is not working
## >>> test_div_by_zero(4j)
## -0.25j
## >>> test_div_by_zero(0)
## Traceback (most recent call last):
## ...
## ZeroDivisionError: float division
>>> test_coercion(1, 1.5, 2.5, 4+1j, 10j)
(1+0j)
......@@ -56,6 +57,10 @@ __doc__ = u"""
(1+2j)
>>> test_real_imag_assignment(1.5, -3.5)
(1.5-3.5j)
## XXX not implemented yet!
## >>> test_conjugate(1+2j)
## (1-2j)
"""
#cdef extern from "complex.h":
......@@ -65,15 +70,17 @@ cimport cython
def test_object_conversion(o):
cdef float complex a = o
cdef double complex z = o
return (a, z)
cdef double complex b = o
cdef long double complex c = o
return (a, b, c)
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)
def test_div_by_zero(double complex z):
return 1/z
## XXX this is not working
## @cython.cdivision(False)
## 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):
cdef double complex z
......@@ -102,3 +109,6 @@ def test_real_imag_assignment(object a, double b):
z.imag = b
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