[pypy-commit] pypy decimal-libmpdec: Add Decimal.as_tuple()
amauryfa
noreply at buildbot.pypy.org
Sat May 17 11:56:48 CEST 2014
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: decimal-libmpdec
Changeset: r71551:b6fe176810c7
Date: 2014-05-11 20:31 +0200
http://bitbucket.org/pypy/pypy/changeset/b6fe176810c7/
Log: Add Decimal.as_tuple()
diff --git a/pypy/module/_decimal/interp_context.py b/pypy/module/_decimal/interp_context.py
--- a/pypy/module/_decimal/interp_context.py
+++ b/pypy/module/_decimal/interp_context.py
@@ -61,6 +61,10 @@
w_MutableMapping]),
space.newdict())
+ self.W_DecimalTuple = space.call_method(
+ w_collections, "namedtuple",
+ space.wrap("DecimalTuple"), space.wrap("sign digits exponent"))
+
def state_get(space):
return space.fromcache(State)
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
@@ -315,6 +315,53 @@
def is_infinite_w(self, space):
return space.wrap(bool(rmpdec.mpd_isinfinite(self.mpd)))
+ def as_tuple_w(self, space):
+ "Return the DecimalTuple representation of a Decimal"
+ w_sign = space.wrap(rmpdec.mpd_sign(self.mpd))
+ if rmpdec.mpd_isinfinite(self.mpd):
+ w_expt = space.wrap("F")
+ # decimal.py has non-compliant infinity payloads.
+ w_coeff = space.newtuple([space.wrap(0)])
+ else:
+ if rmpdec.mpd_isnan(self.mpd):
+ if rmpdec.mpd_issnan(self.mpd):
+ w_expt = space.wrap("N")
+ else:
+ w_expt = space.wrap("n")
+ else:
+ w_expt = space.wrap(self.mpd.c_exp)
+
+ if self.mpd.c_len > 0:
+ # coefficient is defined
+
+ # make an integer
+ # XXX this should be done in C...
+ x = rmpdec.mpd_qncopy(self.mpd)
+ if not x:
+ raise OperationError(space.w_MemoryError, space.w_None)
+ try:
+ x.c_exp = 0
+ # clear NaN and sign
+ rmpdec.mpd_clear_flags(x)
+ intstring = rmpdec.mpd_to_sci(x, 1)
+ finally:
+ rmpdec.mpd_del(x)
+ if not intstring:
+ raise OperationError(space.w_MemoryError, space.w_None)
+ try:
+ digits = rffi.charp2str(intstring)
+ finally:
+ rmpdec.mpd_free(intstring)
+ w_coeff = space.newtuple([
+ space.wrap(ord(d) - ord('0'))
+ for d in digits])
+ else:
+ w_coeff = space.newtuple([])
+
+ return space.call_function(
+ interp_context.state_get(space).W_DecimalTuple,
+ w_sign, w_coeff, w_expt)
+
# Helper functions for arithmetic conversions
def convert_op(space, context, w_value):
@@ -643,4 +690,6 @@
copy_sign = interp2app(W_Decimal.copy_sign_w),
is_qnan = interp2app(W_Decimal.is_qnan_w),
is_infinite = interp2app(W_Decimal.is_infinite_w),
+ #
+ as_tuple = interp2app(W_Decimal.as_tuple_w),
)
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
@@ -712,3 +712,49 @@
d = Decimal(1).copy_sign(Decimal(-2))
assert Decimal(1).copy_sign(-2) == d
raises(TypeError, Decimal(1).copy_sign, '-2')
+
+ def test_as_tuple(self):
+ Decimal = self.decimal.Decimal
+
+ #with zero
+ d = Decimal(0)
+ assert d.as_tuple() == (0, (0,), 0)
+
+ #int
+ d = Decimal(-45)
+ assert d.as_tuple() == (1, (4, 5), 0)
+
+ #complicated string
+ d = Decimal("-4.34913534E-17")
+ assert d.as_tuple() == (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25)
+
+ # The '0' coefficient is implementation specific to decimal.py.
+ # It has no meaning in the C-version and is ignored there.
+ d = Decimal("Infinity")
+ assert d.as_tuple() == (0, (0,), 'F')
+
+ #leading zeros in coefficient should be stripped
+ d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), -2) )
+ assert d.as_tuple() == (0, (4, 0, 5, 3, 4), -2)
+ d = Decimal( (1, (0, 0, 0), 37) )
+ assert d.as_tuple() == (1, (0,), 37)
+ d = Decimal( (1, (), 37) )
+ assert d.as_tuple() == (1, (0,), 37)
+
+ #leading zeros in NaN diagnostic info should be stripped
+ d = Decimal( (0, (0, 0, 4, 0, 5, 3, 4), 'n') )
+ assert d.as_tuple() == (0, (4, 0, 5, 3, 4), 'n')
+ d = Decimal( (1, (0, 0, 0), 'N') )
+ assert d.as_tuple() == (1, (), 'N')
+ d = Decimal( (1, (), 'n') )
+ assert d.as_tuple() == (1, (), 'n')
+
+ # For infinities, decimal.py has always silently accepted any
+ # coefficient tuple.
+ d = Decimal( (0, (0,), 'F') )
+ assert d.as_tuple() == (0, (0,), 'F')
+ d = Decimal( (0, (4, 5, 3, 4), 'F') )
+ assert d.as_tuple() == (0, (0,), 'F')
+ d = Decimal( (1, (0, 2, 7, 1), 'F') )
+ assert d.as_tuple() == (1, (0,), 'F')
+
diff --git a/rpython/rlib/rmpdec.py b/rpython/rlib/rmpdec.py
--- a/rpython/rlib/rmpdec.py
+++ b/rpython/rlib/rmpdec.py
@@ -36,13 +36,14 @@
libdir.join('memory.c'),
],
export_symbols=[
- "mpd_qset_ssize", "mpd_qset_uint", "mpd_qset_string", "mpd_qcopy", "mpd_setspecial",
+ "mpd_qset_ssize", "mpd_qset_uint", "mpd_qset_string",
+ "mpd_qcopy", "mpd_qncopy", "mpd_setspecial", "mpd_clear_flags",
"mpd_qimport_u32", "mpd_qexport_u32", "mpd_qexport_u16",
- "mpd_set_sign", "mpd_qfinalize",
+ "mpd_set_sign", "mpd_sign", "mpd_qfinalize",
"mpd_getprec", "mpd_getemin", "mpd_getemax", "mpd_getround", "mpd_getclamp",
"mpd_qsetprec", "mpd_qsetemin", "mpd_qsetemax", "mpd_qsetround", "mpd_qsetclamp",
"mpd_maxcontext",
- "mpd_qnew",
+ "mpd_qnew", "mpd_del",
"mpd_to_sci", "mpd_to_sci_size",
"mpd_iszero", "mpd_isnegative", "mpd_isinfinite", "mpd_isspecial",
"mpd_isnan", "mpd_issnan", "mpd_isqnan",
@@ -156,10 +157,16 @@
MPD_PTR, rffi.UINTP], rffi.SIZE_T)
mpd_qcopy = external(
'mpd_qcopy', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT)
+mpd_qncopy = external(
+ 'mpd_qncopy', [MPD_PTR], MPD_PTR)
mpd_setspecial = external(
'mpd_setspecial', [MPD_PTR, rffi.UCHAR, rffi.UCHAR], lltype.Void)
mpd_set_sign = external(
'mpd_set_sign', [MPD_PTR, rffi.UCHAR], lltype.Void)
+mpd_clear_flags = external(
+ 'mpd_clear_flags', [MPD_PTR], lltype.Void)
+mpd_sign = external(
+ 'mpd_sign', [MPD_PTR], rffi.UCHAR)
mpd_qfinalize = external(
'mpd_qfinalize', [MPD_PTR, MPD_CONTEXT_PTR, rffi.UINTP], lltype.Void)
@@ -191,6 +198,8 @@
mpd_qnew = external(
'mpd_qnew', [], MPD_PTR)
+mpd_del = external(
+ 'mpd_del', [MPD_PTR], lltype.Void)
mpd_free = external(
'mpd_free', [rffi.VOIDP], lltype.Void, macro=True)
More information about the pypy-commit
mailing list