Author: Amaury Forgeot d'Arc <amaur...@gmail.com> Branch: decimal-libmpdec Changeset: r71464:502a9fa6ddd6 Date: 2014-05-10 23:03 +0200 http://bitbucket.org/pypy/pypy/changeset/502a9fa6ddd6/
Log: Add int() conversion, support for trunc(), round()... diff --git a/pypy/module/_decimal/interp_decimal.py b/pypy/module/_decimal/interp_decimal.py --- a/pypy/module/_decimal/interp_decimal.py +++ b/pypy/module/_decimal/interp_decimal.py @@ -94,6 +94,72 @@ w_s = self.descr_str(space) return space.call_function(space.w_float, w_s) + def to_long(self, space, context, round): + if rmpdec.mpd_isspecial(self.mpd): + if rmpdec.mpd_isnan(self.mpd): + raise oefmt(space.w_ValueError, + "cannot convert NaN to integer") + else: + raise oefmt(space.w_OverflowError, + "cannot convert Infinity to integer") + + w_x = W_Decimal.allocate(space) + w_tempctx = context.copy_w(space) + rffi.setintfield(w_tempctx.ctx, 'c_round', round) + with context.catch_status(space) as (ctx, status_ptr): + # We round with the temporary context, but set status and + # raise errors on the global one. + rmpdec.mpd_qround_to_int(w_x.mpd, self.mpd, + w_tempctx.ctx, status_ptr) + + # XXX mpd_qexport_u64 would be faster... + T = rffi.CArrayPtr(rffi.USHORTP).TO + with lltype.scoped_alloc(T, 1, zero=True) as digits_ptr: + n = rmpdec.mpd_qexport_u16( + digits_ptr, 0, 0x10000, + w_x.mpd, status_ptr) + if n == rmpdec.MPD_SIZE_MAX: + raise OperationError(space.w_MemoryError, space.w_None) + try: + char_ptr = rffi.cast(rffi.CCHARP, digits_ptr[0]) + size = rffi.cast(lltype.Signed, n) * 2 + s = rffi.charpsize2str(char_ptr, size) + finally: + rmpdec.mpd_free(digits_ptr[0]) + bigint = rbigint.rbigint.frombytes( + s, byteorder=rbigint.BYTEORDER, signed=False) + if rmpdec.mpd_isnegative(w_x.mpd) and not rmpdec.mpd_iszero(w_x.mpd): + bigint = bigint.neg() + return space.newlong_from_rbigint(bigint) + + def descr_int(self, space): + context = interp_context.getcontext(space) + return self.to_long(space, context, rmpdec.MPD_ROUND_DOWN) + + def descr_floor(self, space): + context = interp_context.getcontext(space) + return self.to_long(space, context, rmpdec.MPD_ROUND_FLOOR) + + def descr_ceil(self, space): + context = interp_context.getcontext(space) + return self.to_long(space, context, rmpdec.MPD_ROUND_CEILING) + + def descr_round(self, space, w_x=None): + context = interp_context.getcontext(space) + if not w_x: + return self.to_long(space, context, rmpdec.MPD_ROUND_HALF_EVEN) + x = space.int_w(w_x) + w_result = W_Decimal.allocate(space) + w_q = decimal_from_ssize(space, None, 1, context, exact=False) + if x == rmpdec.MPD_SSIZE_MIN: + w_q.mpd.c_exp = rmpdec.MPD_SSIZE_MAX + else: + w_q.mpd.c_exp = -x + with context.catch_status(space) as (ctx, status_ptr): + rmpdec.mpd_qquantize(w_result.mpd, self.mpd, w_q.mpd, + ctx, status_ptr) + return w_result + def compare(self, space, w_other, op): if not isinstance(w_other, W_Decimal): # So far return space.w_NotImplemented @@ -388,6 +454,10 @@ __repr__ = interp2app(W_Decimal.descr_repr), __bool__ = interp2app(W_Decimal.descr_bool), __float__ = interp2app(W_Decimal.descr_float), + __int__ = interp2app(W_Decimal.descr_int), + __floor__ = interp2app(W_Decimal.descr_floor), + __ceil__ = interp2app(W_Decimal.descr_ceil), + __round__ = interp2app(W_Decimal.descr_round), __eq__ = interp2app(W_Decimal.descr_eq), # __add__ = interp2app(W_Decimal.descr_add), diff --git a/pypy/module/_decimal/test/test_decimal.py b/pypy/module/_decimal/test/test_decimal.py --- a/pypy/module/_decimal/test/test_decimal.py +++ b/pypy/module/_decimal/test/test_decimal.py @@ -333,17 +333,21 @@ def test_tonum_methods(self): #Test float and int methods. Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + self.decimal.getcontext().traps[InvalidOperation] = False + + import math d1 = Decimal('66') d2 = Decimal('15.32') #int - int(d1) == 66 - int(d2) == 15 + assert int(d1) == 66 + assert int(d2) == 15 #float - float(d1) == 66 - float(d2) == 15.32 + assert float(d1) == 66 + assert float(d2) == 15.32 #floor test_pairs = [ diff --git a/rpython/rlib/rmpdec.py b/rpython/rlib/rmpdec.py --- a/rpython/rlib/rmpdec.py +++ b/rpython/rlib/rmpdec.py @@ -37,6 +37,7 @@ ], export_symbols=[ "mpd_qset_ssize", "mpd_qset_uint", "mpd_qset_string", "mpd_qcopy", "mpd_setspecial", + "mpd_qimport_u32", "mpd_qexport_u32", "mpd_qexport_u16", "mpd_set_sign", "mpd_qfinalize", "mpd_getprec", "mpd_getemin", "mpd_getemax", "mpd_getround", "mpd_getclamp", "mpd_qsetprec", "mpd_qsetemin", "mpd_qsetemax", "mpd_qsetround", "mpd_qsetclamp", @@ -45,7 +46,7 @@ "mpd_to_sci", "mpd_to_sci_size", "mpd_iszero", "mpd_isnegative", "mpd_isinfinite", "mpd_isspecial", "mpd_isnan", "mpd_issnan", "mpd_isqnan", - "mpd_qcmp", + "mpd_qcmp", "mpd_qquantize", "mpd_qpow", "mpd_qadd", "mpd_qsub", "mpd_qmul", "mpd_qdiv", "mpd_qround_to_int", ], @@ -81,6 +82,9 @@ 'MPD_IEEE_CONTEXT_MAX_BITS') MPD_MAX_PREC = platform.ConstantInteger('MPD_MAX_PREC') MPD_MAX_SIGNAL_LIST = platform.ConstantInteger('MPD_MAX_SIGNAL_LIST') + MPD_SIZE_MAX = platform.ConstantInteger('MPD_SIZE_MAX') + MPD_SSIZE_MAX = platform.ConstantInteger('MPD_SSIZE_MAX') + MPD_SSIZE_MIN = platform.ConstantInteger('MPD_SSIZE_MIN') # Flags MPD_POS = platform.ConstantInteger('MPD_POS') @@ -136,8 +140,17 @@ mpd_qset_string = external( 'mpd_qset_string', [MPD_PTR, rffi.CCHARP, MPD_CONTEXT_PTR, rffi.UINTP], lltype.Void) mpd_qimport_u32 = external( - 'mpd_qimport_u32', [MPD_PTR, rffi.UINTP, rffi.SIZE_T, - rffi.UCHAR, rffi.UINT, MPD_CONTEXT_PTR, rffi.UINTP], rffi.SIZE_T) + 'mpd_qimport_u32', [ + MPD_PTR, rffi.UINTP, rffi.SIZE_T, + rffi.UCHAR, rffi.UINT, MPD_CONTEXT_PTR, rffi.UINTP], rffi.SIZE_T) +mpd_qexport_u32 = external( + 'mpd_qexport_u32', [ + rffi.CArrayPtr(rffi.UINTP), rffi.SIZE_T, rffi.UINT, + MPD_PTR, rffi.UINTP], rffi.SIZE_T) +mpd_qexport_u16 = external( + 'mpd_qexport_u16', [ + rffi.CArrayPtr(rffi.USHORTP), rffi.SIZE_T, rffi.UINT, + MPD_PTR, rffi.UINTP], rffi.SIZE_T) mpd_qcopy = external( 'mpd_qcopy', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT) mpd_setspecial = external( @@ -204,6 +217,9 @@ 'mpd_isqnan', [MPD_PTR], rffi.INT) mpd_qcmp = external( 'mpd_qcmp', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT) +mpd_qquantize = external( + 'mpd_qquantize', [MPD_PTR, MPD_PTR, MPD_PTR, MPD_CONTEXT_PTR, rffi.UINTP], + lltype.Void) mpd_qpow = external( 'mpd_qpow', _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit