Author: Jasper Schulz <jasper.sch...@student.hpi.uni-potsdam.de> Branch: numpypy-complex2 Changeset: r55863:7623c78dccba Date: 2012-06-27 16:34 +0200 http://bitbucket.org/pypy/pypy/changeset/7623c78dccba/
Log: some work on complex numbers diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -79,7 +79,9 @@ 'unicode_': 'interp_boxes.W_UnicodeBox', 'void': 'interp_boxes.W_VoidBox', 'complexfloating': 'interp_boxes.W_ComplexFloatingBox', - 'complex128': 'interp_boxes.W_Complex128Box' + 'complex_': 'interp_boxes.W_Complex128Box', + 'complex128': 'interp_boxes.W_Complex128Box', + 'complex64': 'interp_boxes.W_Complex64Box', } # ufuncs @@ -94,6 +96,8 @@ ("arccosh", "arccosh"), ("arcsinh", "arcsinh"), ("arctanh", "arctanh"), + ("conj", "conjugate"), + ("conjugate", "conjugate"), ("copysign", "copysign"), ("cos", "cos"), ("cosh", "cosh"), diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -34,6 +34,22 @@ def convert_to(self, dtype): return dtype.box(self.value) +class ComplexBox(object): + _mixin_ = True + + def __init__(self, real, imag): + self.real = real + self.imag = imag + + def descr_get_real(self, space): + return space.wrap(self._COMPONENTS_BOX(self.real)) + + def descr_get_imag(self, space): + return space.wrap(self._COMPONENTS_BOX(self.imag)) + + def convert_to(self, dtype): + return dtype.box_complex(self.real, self.imag) + class W_GenericBox(Wrappable): _attrs_ = () @@ -274,19 +290,15 @@ class W_ComplexFloatingBox(W_InexactBox): _attrs_ = () -class W_Complex128Box(W_ComplexFloatingBox): +class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): + descr__new__, _get_dtype = new_dtype_getter("complex64") + _COMPONENTS_BOX = W_Float32Box + +class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): descr__new__, _get_dtype = new_dtype_getter("complex128") + _COMPONENTS_BOX = W_Float64Box - def __init__(self, real, imag): - self.real = real - self.imag = imag - - def descr_get_real(self, space): - return space.wrap(self.real) - - def descr_get_imag(self, space): - return space.wrap(self.imag) - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", @@ -474,9 +486,17 @@ __module__ = "numpypy", ) + W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), real = GetSetProperty(W_Complex128Box.descr_get_real), imag = GetSetProperty(W_Complex128Box.descr_get_imag), +) + +W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), + __module__ = "numpypy", + __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + real = GetSetProperty(W_Complex64Box.descr_get_real), + imag = GetSetProperty(W_Complex64Box.descr_get_imag), ) \ No newline at end of file diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -40,6 +40,11 @@ def box(self, value): return self.itemtype.box(value) + @specialize.argtype(1, 2) + def box_complex(self, real, imag): + return self.itemtype.box_complex(real, imag) + + def coerce(self, space, w_item): return self.itemtype.coerce(space, self, w_item) @@ -387,12 +392,27 @@ alternate_constructors=[space.w_float], aliases=["float"], ) + # self.w_float128dtype = W_Dtype( + # types.Float128(), + # num=13, + # kind=FLOATINGLTR, + # name="float128", + # ... + # ) + self.w_complex64dtype = W_Dtype( + types.Complex64(), + num=14, + kind=FLOATINGLTR, + name="complex64", + char="F", + w_box_type = space.gettypefor(interp_boxes.W_Complex64Box), + ) self.w_complex128dtype = W_Dtype( types.Complex128(), num=15, kind=FLOATINGLTR, name="complex128", - char="c", + char="D", w_box_type = space.gettypefor(interp_boxes.W_Complex128Box), alternate_constructors=[space.w_complex], aliases=["complex"], @@ -430,7 +450,8 @@ self.w_int16dtype, self.w_uint16dtype, self.w_int32dtype, self.w_uint32dtype, self.w_longdtype, self.w_ulongdtype, self.w_int64dtype, self.w_uint64dtype, - self.w_float32dtype, self.w_float64dtype, self.w_complex128dtype, + self.w_float32dtype, self.w_float64dtype, self.w_complex64dtype, + self.w_complex128dtype, self.w_stringdtype, self.w_unicodedtype, self.w_voiddtype, ] diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -443,6 +443,7 @@ bool_dtype = interp_dtype.get_dtype_cache(space).w_booldtype long_dtype = interp_dtype.get_dtype_cache(space).w_longdtype int64_dtype = interp_dtype.get_dtype_cache(space).w_int64dtype + complex_type = interp_dtype.get_dtype_cache(space).w_complex128dtype if isinstance(w_obj, interp_boxes.W_GenericBox): dtype = w_obj.get_dtype(space) @@ -464,6 +465,13 @@ current_guess is long_dtype or current_guess is int64_dtype): return int64_dtype return current_guess + elif space.isinstance_w(w_obj, space.w_complex): + if (current_guess is None or current_guess is bool_dtype or + current_guess is long_dtype or current_guess is int64_dtype or + current_guess is complex_type): + return complex_type + return current_guess + return interp_dtype.get_dtype_cache(space).w_float64dtype @@ -535,6 +543,7 @@ ("sign", "sign", 1, {"promote_bools": True}), ("signbit", "signbit", 1, {"bool_result": True}), ("reciprocal", "reciprocal", 1), + ("conjugate", "conj", 1), ("fabs", "fabs", 1, {"promote_to_float": True}), ("fmax", "fmax", 2, {"promote_to_float": True}), diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -427,29 +427,56 @@ assert numpy.complexfloating.__mro__ == (numpy.complexfloating, numpy.inexact, numpy.number, numpy.generic, object) + def test_complex_format(self): + import _numpypy as numpy + + for complex_ in (numpy.complex128, numpy.complex64,): + for real, imag, should in [ + (1, 2, '(1+2j)'), + (0, 1, '1j'), + (1, 0, '(1+0j)'), + (-1, -2, '(-1-2j)'), + (0.5, -0.75, '(0.5-0.75j)'), + #xxx + #(numpy.inf, numpy.inf, '(inf+inf*j)'), + ]: + + c = complex_(complex(real, imag)) + assert c == complex(real, imag) + assert c.real == real + assert c.imag == imag + assert repr(c) == should + + real, imag, should = (1e100, 3e66, '(1e+100+3e+66j)') + c128 = numpy.complex128(complex(real, imag)) + assert type(c128.real) is type(c128.imag) is numpy.float64 + assert c128.real == real + assert c128.imag == imag + assert repr(c128) == should + + c64 = numpy.complex64(complex(real, imag)) + assert repr(c64.real) == 'inf' + assert type(c64.real) is type(c64.imag) is numpy.float32 + assert repr(c64.imag).startswith('inf') + assert repr(c64) in ('(inf+inf*j)', '(inf+infj)') + + + assert numpy.complex128(1.2) == numpy.complex128(complex(1.2, 0)) + assert numpy.complex64(1.2) == numpy.complex64(complex(1.2, 0)) + def test_complex(self): import _numpypy as numpy + assert numpy.complex_ is numpy.complex128 + assert numpy.complex64.__mro__ == (numpy.complex64, + numpy.complexfloating, numpy.inexact, numpy.number, numpy.generic, + object) assert numpy.complex128.__mro__ == (numpy.complex128, numpy.complexfloating, numpy.inexact, numpy.number, numpy.generic, complex, object) - for real, imag, should in [ - (1, 2, '(1+2j)'), - (0, 1, '1j'), - (1, 0, '(1+0j)'), - (-1, -2, '(-1-2j)') - ]: - - c = numpy.complex128(complex(real, imag)) - assert c.real == real - assert c.imag == imag - assert repr(c) == should - - def test_complex_dtype(self): - import _numpypy as numpy - - assert numpy.dtype(complex) is numpy.dtype("complex") + assert numpy.dtype(complex).type is numpy.complex128 + assert numpy.dtype("complex").type is numpy.complex128 def test_subclass_type(self): import _numpypy as numpy diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -823,3 +823,88 @@ assert logaddexp2(float('-inf'), float('inf')) == float('inf') assert logaddexp2(float('inf'), float('-inf')) == float('inf') assert logaddexp2(float('inf'), float('inf')) == float('inf') + + def test_conjugate(self): + from _numpypy import conj, conjugate, complex128, complex64 + import _numpypy as np + + c0 = complex128(complex(2.5, 0)) + c1 = complex64(complex(1, 2)) + + assert conj is conjugate + assert conj(c0) == c0 + assert conj(c1) == complex(1, -2) + assert conj(1) == 1 + assert conj(-3) == -3 + assert conj(float('-inf')) == float('-inf') + + + assert np.conjugate(1+2j) == 1-2j + + x = np.eye(2) + 1j * np.eye(2) + for a, b in zip(np.conjugate(x), np.array([[ 1.-1.j, 0.-0.j], [ 0.-0.j, 1.-1.j]])): + assert a[0] == b[0] + assert a[1] == b[1] + + + def test_complex(self): + from _numpypy import (array, complex128, complex64, add, subtract as sub, multiply, + divide, negative, conjugate, conj, abs) + from _numpypy import equal, not_equal, greater, greater_equal, less, less_equal + + for complex_ in complex128, complex64: + + O = complex(0, 0) + c0 = complex_(complex(2.5, 0)) + c1 = complex_(complex(1, 2)) + c2 = complex_(complex(3, 4)) + c3 = complex_(complex(-3, -3)) + + assert equal(c0, 2.5) + assert equal(c1, complex_(complex(1, 2))) + assert equal(c1, complex(1, 2)) + assert equal(c1, c1) + assert not_equal(c1, c2) + assert not equal(c1, c2) + + assert less(c1, c2) + assert less_equal(c1, c2) + assert less_equal(c1, c1) + assert not less(c1, c1) + + assert greater(c2, c1) + assert greater_equal(c2, c1) + assert not greater(c1, c2) + + assert add(c1, c2) == complex_(complex(4, 6)) + assert add(c1, c2) == complex(4, 6) + + assert sub(c0, c0) == sub(c1, c1) == 0 + assert sub(c1, c2) == complex(-2, -2) + assert negative(complex(1,1)) == complex(-1, -1) + assert negative(complex(0, 0)) == 0 + + + assert multiply(1, c1) == c1 + assert multiply(2, c2) == complex(6, 8) + assert multiply(c1, c2) == complex(-5, 10) + + assert divide(c0, 1) == c0 + assert divide(c2, -1) == negative(c2) + assert divide(c1, complex(0, 1)) == complex(2, -1) + n = divide(c1, O) + assert repr(n.real) == 'nan' + assert repr(n.imag).startswith('nan') #can be nan*j or nanj + assert divide(c0, c0) == 1 + res = divide(c2, c1) + assert abs(res.real-2.2) < 0.001 + assert abs(res.imag+0.4) < 0.001 + + assert abs(c0) == 2.5 + assert abs(c2) == 5 + + + + def test_complex_math(self): + # from _numpypy import + pass \ No newline at end of file diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -6,13 +6,14 @@ from pypy.module.micronumpy import interp_boxes from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import W_ComplexObject, str_format -from pypy.rlib import rfloat, libffi, clibffi +from pypy.rlib import rfloat, libffi, clibffi, rcomplex from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.rlib.rarithmetic import widen, byteswap from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rstruct.runpack import runpack from pypy.tool.sourcetools import func_with_new_name from pypy.rlib import jit +from pypy.module import cmath VOID_STORAGE = lltype.Array(lltype.Char, hints={'nolength': True, @@ -34,6 +35,18 @@ ) return dispatcher +def complex_unary_op(func): + specialize.argtype(1)(func) + @functools.wraps(func) + def dispatcher(self, v): + return self.box_complex( + *func( + self, + self.for_computation(self.unbox(v)) + ) + ) + return dispatcher + def raw_unary_op(func): specialize.argtype(1)(func) @functools.wraps(func) @@ -57,6 +70,19 @@ ) return dispatcher +def complex_binary_op(func): + specialize.argtype(1, 2)(func) + @functools.wraps(func) + def dispatcher(self, v1, v2): + return self.box_complex( + *func( + self, + self.for_computation(self.unbox(v1)), + self.for_computation(self.unbox(v2)), + ) + ) + return dispatcher + def raw_binary_op(func): specialize.argtype(1, 2)(func) @functools.wraps(func) @@ -173,6 +199,10 @@ return -v @simple_unary_op + def conj(self, v): + return v + + @simple_unary_op def abs(self, v): return abs(v) @@ -919,33 +949,464 @@ BoxType = interp_boxes.W_Float64Box format_code = "d" -class Complex128(BaseType): +class ComplexFloating(object): + _mixin_ = True + _attrs_ = () + + def _coerce(self, space, w_item): + w_item = space.call_function(space.w_complex, w_item) + real, imag = space.unpackcomplex(w_item) + return self.box_complex(real, imag) + + def coerce(self, space, dtype, w_item): + if isinstance(w_item, self.BoxType): + return w_item + return self.coerce_subtype(space, space.gettypefor(self.BoxType), w_item) + + def coerce_subtype(self, space, w_subtype, w_item): + w_tmpobj = self._coerce(space, w_item) + w_obj = space.allocate_instance(self.BoxType, w_subtype) + assert isinstance(w_obj, self.BoxType) + w_obj.__init__(w_tmpobj.real, w_tmpobj.imag) + return w_obj + + def str_format(self, box): + real, imag = self.for_computation(self.unbox(box)) + imag_str = str_format(imag) + 'j' + + # (0+2j) => 2j + if real == 0: + return imag_str + + real_str = str_format(real) + op = '+' if imag >= 0 else '' + return ''.join(['(', real_str, op, imag_str, ')']) + + def for_computation(self, v): + return float(v[0]), float(v[1]) + + def get_element_size(self): + return 2 * rffi.sizeof(self._COMPONENTS_T) + + @specialize.argtype(1) + def box(self, value): + return self.BoxType( + rffi.cast(self._COMPONENTS_T, value), + rffi.cast(self._COMPONENTS_T, 0.0)) + + @specialize.argtype(1, 2) + def box_complex(self, real, imag): + return self.BoxType( + rffi.cast(self._COMPONENTS_T, real), + rffi.cast(self._COMPONENTS_T, imag)) + + def unbox(self, box): + assert isinstance(box, self.BoxType) + return box.real, box.imag + + @complex_binary_op + def add(self, v1, v2): + return rcomplex.c_add(v1, v2) + + @complex_binary_op + def sub(self, v1, v2): + return rcomplex.c_sub(v1, v2) + + @complex_binary_op + def mul(self, v1, v2): + return rcomplex.c_mul(v1, v2) + + @complex_binary_op + def div(self, v1, v2): + try: + return rcomplex.c_div(v1, v2) + except ZeroDivisionError: + return rfloat.NAN, rfloat.NAN + + + + @complex_unary_op + def pos(self, v): + return v + + @complex_unary_op + def neg(self, v): + return -v[0], -v[1] + + @complex_unary_op + def conj(self, v): + return v[0], -v[1] + + @raw_unary_op + def abs(self, v): + return rcomplex.c_abs(v[0], v[1]) + + @raw_unary_op + def isnan(self, v): + '''a complex number is nan if one of the parts is nan''' + return rfloat.isnan(v[0]) or rfloat.isnan(v[1]) + + @raw_unary_op + def isinf(self, v): + '''a complex number is inf if one of the parts is inf''' + return rfloat.isinf(v[0]) or rfloat.isinf(v[1]) + + def _eq(self, v1, v2): + return v1[0] == v2[0] and v1[1] == v2[1] + + @raw_binary_op + def eq(self, v1, v2): + #compare the parts, so nan == nan is False + return self._eq(v1, v2) + + @raw_binary_op + def ne(self, v1, v2): + return not self._eq(v1, v2) + + def _lt(self, v1, v2): + (r1, i1), (r2, i2) = v1, v2 + if r1 < r2: + return True + elif not r1 <= r2: + return False + return i1 < i2 + + @raw_binary_op + def lt(self, v1, v2): + return self._lt(v1, v2) + + @raw_binary_op + def le(self, v1, v2): + return self._lt(v1, v2) or self._eq(v1, v2) + + @raw_binary_op + def gt(self, v1, v2): + return self._lt(v2, v1) + + @raw_binary_op + def ge(self, v1, v2): + return self._lt(v2, v1) or self._eq(v2, v1) + + @raw_binary_op + def logical_and(self, v1, v2): + return bool(v1) and bool(v2) + + @raw_binary_op + def logical_or(self, v1, v2): + return bool(v1) or bool(v2) + + @raw_unary_op + def logical_not(self, v): + return not bool(v) + + @raw_binary_op + def logical_xor(self, v1, v2): + return bool(v1) ^ bool(v2) + + def bool(self, v): + return bool(self.for_computation(self.unbox(v))) + + @simple_binary_op + def max(self, v1, v2): + return max(v1, v2) + + @simple_binary_op + def min(self, v1, v2): + return min(v1, v2) + + + @simple_binary_op + def floordiv(self, v1, v2): + try: + r, i = rcomplex.c_div(v1, v2) + return math.floor(r), 0 + except ZeroDivisionError: + return rfloat.NAN, 0 + + @simple_binary_op + def mod(self, v1, v2): + return math.fmod(v1, v2) + + @simple_binary_op + def pow(self, v1, v2): + try: + return math.pow(v1, v2) + except ValueError: + return rfloat.NAN + except OverflowError: + if math.modf(v2)[0] == 0 and math.modf(v2 / 2)[0] != 0: + # Odd integer powers result in the same sign as the base + return rfloat.copysign(rfloat.INFINITY, v1) + return rfloat.INFINITY + + @simple_binary_op + def copysign(self, v1, v2): + return math.copysign(v1, v2) + + @simple_unary_op + def sign(self, v): + if v == 0.0: + return 0.0 + return rfloat.copysign(1.0, v) + + @raw_unary_op + def signbit(self, v): + return rfloat.copysign(1.0, v) < 0.0 + + @simple_unary_op + def fabs(self, v): + return math.fabs(v) + + @simple_binary_op + def fmax(self, v1, v2): + if math.isnan(v1): + return v1 + elif math.isnan(v2): + return v2 + return max(v1, v2) + + @simple_binary_op + def fmin(self, v1, v2): + if math.isnan(v1): + return v1 + elif math.isnan(v2): + return v2 + return min(v1, v2) + + @simple_binary_op + def fmod(self, v1, v2): + try: + return math.fmod(v1, v2) + except ValueError: + return rfloat.NAN + + @simple_unary_op + def reciprocal(self, v): + if v == 0.0: + return rfloat.copysign(rfloat.INFINITY, v) + return 1.0 / v + + @simple_unary_op + def floor(self, v): + return math.floor(v) + + @simple_unary_op + def ceil(self, v): + return math.ceil(v) + + @simple_unary_op + def trunc(self, v): + if v < 0: + return math.ceil(v) + else: + return math.floor(v) + + @simple_unary_op + def exp(self, v): + try: + return math.exp(v) + except OverflowError: + return rfloat.INFINITY + + @simple_unary_op + def exp2(self, v): + try: + return math.pow(2, v) + except OverflowError: + return rfloat.INFINITY + + @simple_unary_op + def expm1(self, v): + try: + return rfloat.expm1(v) + except OverflowError: + return rfloat.INFINITY + + @simple_unary_op + def sin(self, v): + return math.sin(v) + + @simple_unary_op + def cos(self, v): + return math.cos(v) + + @simple_unary_op + def tan(self, v): + return math.tan(v) + + @simple_unary_op + def arcsin(self, v): + if not -1.0 <= v <= 1.0: + return rfloat.NAN + return math.asin(v) + + @simple_unary_op + def arccos(self, v): + if not -1.0 <= v <= 1.0: + return rfloat.NAN + return math.acos(v) + + @simple_unary_op + def arctan(self, v): + return math.atan(v) + + @simple_binary_op + def arctan2(self, v1, v2): + return math.atan2(v1, v2) + + @simple_unary_op + def sinh(self, v): + return math.sinh(v) + + @simple_unary_op + def cosh(self, v): + return math.cosh(v) + + @simple_unary_op + def tanh(self, v): + return math.tanh(v) + + @simple_unary_op + def arcsinh(self, v): + return math.asinh(v) + + @simple_unary_op + def arccosh(self, v): + if v < 1.0: + return rfloat.NAN + return math.acosh(v) + + @simple_unary_op + def arctanh(self, v): + if v == 1.0 or v == -1.0: + return math.copysign(rfloat.INFINITY, v) + if not -1.0 < v < 1.0: + return rfloat.NAN + return math.atanh(v) + + @simple_unary_op + def sqrt(self, v): + try: + return math.sqrt(v) + except ValueError: + return rfloat.NAN + + @simple_unary_op + def square(self, v): + return v*v + + @raw_unary_op + def isnan(self, v): + return rfloat.isnan(v) + + @raw_unary_op + def isinf(self, v): + return rfloat.isinf(v) + + @raw_unary_op + def isneginf(self, v): + return rfloat.isinf(v) and v < 0 + + @raw_unary_op + def isposinf(self, v): + return rfloat.isinf(v) and v > 0 + + @raw_unary_op + def isfinite(self, v): + return not (rfloat.isinf(v) or rfloat.isnan(v)) + + @simple_unary_op + def radians(self, v): + return v * degToRad + deg2rad = radians + + @simple_unary_op + def degrees(self, v): + return v / degToRad + + @simple_unary_op + def log(self, v): + try: + return math.log(v) + except ValueError: + if v == 0.0: + # CPython raises ValueError here, so we have to check + # the value to find the correct numpy return value + return -rfloat.INFINITY + return rfloat.NAN + + @simple_unary_op + def log2(self, v): + try: + return math.log(v) / log2 + except ValueError: + if v == 0.0: + # CPython raises ValueError here, so we have to check + # the value to find the correct numpy return value + return -rfloat.INFINITY + return rfloat.NAN + + @simple_unary_op + def log10(self, v): + try: + return math.log10(v) + except ValueError: + if v == 0.0: + # CPython raises ValueError here, so we have to check + # the value to find the correct numpy return value + return -rfloat.INFINITY + return rfloat.NAN + + @simple_unary_op + def log1p(self, v): + try: + return rfloat.log1p(v) + except OverflowError: + return -rfloat.INFINITY + except ValueError: + return rfloat.NAN + + @simple_binary_op + def logaddexp(self, v1, v2): + tmp = v1 - v2 + if tmp > 0: + return v1 + rfloat.log1p(math.exp(-tmp)) + elif tmp <= 0: + return v2 + rfloat.log1p(math.exp(tmp)) + else: + return v1 + v2 + + def npy_log2_1p(self, v): + return log2e * rfloat.log1p(v) + + @simple_binary_op + def logaddexp2(self, v1, v2): + tmp = v1 - v2 + if tmp > 0: + return v1 + self.npy_log2_1p(math.pow(2, -tmp)) + if tmp <= 0: + return v2 + self.npy_log2_1p(math.pow(2, tmp)) + else: + return v1 + v2 + +class Complex64(ComplexFloating, BaseType): _attrs_ = () T = rffi.CHAR + _COMPONENTS_T = rffi.FLOAT + BoxType = interp_boxes.W_Complex64Box + + + +NonNativeComplex64 = Complex64 + +class Complex128(ComplexFloating, BaseType): + _attrs_ = () + + T = rffi.CHAR + _COMPONENTS_T = rffi.DOUBLE BoxType = interp_boxes.W_Complex128Box - def get_element_size(self): - return 2 * rffi.sizeof(rffi.DOUBLE) - - def coerce_subtype(self, space, w_subtype, w_item): - real, imag = space.unpackcomplex(w_item) - w_obj = space.allocate_instance(self.BoxType, w_subtype) - assert isinstance(w_obj, self.BoxType) - w_obj.__init__(real, imag) - return w_obj - - def str_format(self, box): - imag_str = str_format(box.imag) + 'j' - - # (0+2j) => 2j - if box.real == 0: - return imag_str - - real_str = str_format(box.real) - op = '+' if box.imag >= 0 else '' - return ''.join(['(', real_str, op, imag_str, ')']) - NonNativeComplex128 = Complex128 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit