Author: Amaury Forgeot d'Arc <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit