[Python-checkins] r68608 - in sandbox/trunk/decimal/decimal_in_c: README deccoeff.c

mark.dickinson python-checkins at python.org
Wed Jan 14 12:44:26 CET 2009


Author: mark.dickinson
Date: Wed Jan 14 12:44:26 2009
New Revision: 68608

Log:
Reorganize Decimal coefficient code slightly, expand comments, add docstring
for Deccoeff.digit_length, and call limbs_as_unicode from deccoeff_str
to remove duplication of code.


Modified:
   sandbox/trunk/decimal/decimal_in_c/README
   sandbox/trunk/decimal/decimal_in_c/deccoeff.c

Modified: sandbox/trunk/decimal/decimal_in_c/README
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/README	(original)
+++ sandbox/trunk/decimal/decimal_in_c/README	Wed Jan 14 12:44:26 2009
@@ -129,3 +129,17 @@
 
 >>> LIMB_DIGITS
 9
+
+Notes
+-----
+The aim is to slowly move all Decimal methods to _Decimal.  However,
+there's a minor problem with inheritance and subclasses of Decimal.
+For example, suppose MyDecimal is a subclass of Decimal.  Then if x
+and y are instances of MyDecimal, x + y should produce a Decimal
+instance, not a MyDecimal instance.
+
+However, if we move the __add__ code from Decimal to _Decimal,
+we'll end up with a _Decimal instance instead.
+
+So all the _Decimal operations will still need to be wrapped
+at the Decimal level, during the Python -> C migration period.

Modified: sandbox/trunk/decimal/decimal_in_c/deccoeff.c
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/deccoeff.c	(original)
+++ sandbox/trunk/decimal/decimal_in_c/deccoeff.c	Wed Jan 14 12:44:26 2009
@@ -245,7 +245,7 @@
 
 static long
 limb_hash(limb_t x) {
-    return (long)x;
+    return (long)(x % LONG_MAX);
 }
 
 /* smallest nonnegative i such that x < 10**i; undefined if x == 0 */
@@ -332,6 +332,8 @@
 limb_lshift(limb_t *res, limb_t a, Py_ssize_t n, limb_t b) {
     if (!(0 <= n && n <= LIMB_DIGITS))
         limb_error("limb_lshift: invalid shift index");
+    if (b != limb_mask(b, n))
+        limb_error("limb_lshift: b out of range");
     if (LIMB_DIGITS == n) {
         *res = b;
         return a;
@@ -346,7 +348,9 @@
 limb_rshift(limb_t *res, limb_t a, Py_ssize_t n, limb_t b) {
     limb_t rem;
     if (!(0 <= n && n <= LIMB_DIGITS))
-        limb_error("limb_lshift: invalid shift index");
+        limb_error("limb_rshift: invalid shift index");
+    if (b != limb_mask(b, n))
+        limb_error("limb_rshift: b out of range");
     if (LIMB_DIGITS == n) {
         *res = b;
         return a;
@@ -412,8 +416,8 @@
 #error "unrecognised value for LIMB_DIGITS"
 #endif
 
-/* res[0:a_size+b_size] := a*b, assuming b_size <= MIN(MAX_PARTIALS, a_size).
-   This is a dropin replacement for limbs_mul. */
+/* res[0:a_size+b_size] := a*b, assuming b_size <= MIN(MAX_PARTIALS,
+   a_size). */
 
 static void
 limbs_fastmultiply_init(limb_t *res, const limb_t *a, Py_ssize_t a_size,
@@ -447,7 +451,7 @@
 
      res[0:a_size+b_size] := a*b + res[0:a_size],
 
-   assuming b_size <= MIN(MAX_PARTIALS, a_size) */
+   still assuming b_size <= MIN(MAX_PARTIALS, a_size) */
 
 static void
 limbs_fastmultiply_add(limb_t *res, const limb_t *a, Py_ssize_t a_size,
@@ -479,7 +483,8 @@
     assert(acc == 0);
 }
 
-/* res[0:a_size+b_size] := a * b */
+/* res[0:a_size+b_size] := a * b.  This is a dropin replacement for
+   limbs_mul. */
 
 static void
 limbs_fastmultiply(limb_t *res, const limb_t *a, Py_ssize_t a_size,
@@ -497,6 +502,8 @@
     if (b_size < MAX_PARTIALS)
         limbs_fastmultiply_init(res, a, a_size, b, b_size);
     else {
+        /* break b up into chunks of size <= MAX_PARTIALS,
+           and do a separate multiply for each chunk */
         limbs_fastmultiply_init(res, a, a_size, b, MAX_PARTIALS);
         b_size -= MAX_PARTIALS;
         b += MAX_PARTIALS;
@@ -511,9 +518,6 @@
     }
 }
 
-#undef LIMB_BASE
-
-
 /*********************************
  * Arithmetic on arrays of limbs *
  *********************************/
@@ -522,22 +526,6 @@
    don't take care of memory allocation; they all assume that sufficient space
    is provided for their results. */
 
-/* Rational approximations to log(10)/log(2), used for base conversion:
-   485/146  = 3.321917808219...
-   log2(10) = 3.321928094887...
-   2136/643 = 3.321928460342...
-
-   Note that for correctness of scale_Py_ssize_t, it's required that LOG2_10UP
-   * LOG2_10UQ * LIMB_DIGITS * PyLong_SHIFT and LOG2_10LP * LOG2_10LQ *
-   LIMB_DIGITS * PyLong_SHIFT both fit into a Py_ssize_t.  The values below
-   are okay even if LIMB_DIGITS = 19 and PyLong_SHIFT = 64.
-*/
-
-#define LOG2_10LP 485
-#define LOG2_10LQ 146
-#define LOG2_10UP 2136
-#define LOG2_10UQ 643
-
 /* add n-limb numbers a and b, producing an n-limb result res and a carry */
 
 static bool
@@ -672,7 +660,7 @@
    instead.  This code left in for testing and debugging purposes. */
 
 static void
-limbs_mul(limb_t *res, const limb_t *a, Py_ssize_t a_size,
+limbs_multiply(limb_t *res, const limb_t *a, Py_ssize_t a_size,
           const limb_t *b, Py_ssize_t b_size)
 {
     Py_ssize_t i, j;
@@ -687,9 +675,9 @@
     }
 }
 
-/* divide a_size-limb number a by single limb x, giving a_size-limb quotient
-   res and returning the (single limb) remainder.  If the input high is
-   nonzero, it's treated as digit a_size of a. */
+/* divide a_size-limb number a by single nonzero limb x, giving a_size-limb
+   quotient res and returning the (single limb) remainder.  If the input high
+   is nonzero, it's treated as digit a_size of a. */
 
 static limb_t
 limbs_div1(limb_t *res, const limb_t *a, Py_ssize_t a_size,
@@ -707,7 +695,7 @@
    standard: see Knuth, TAOCP, Volume 4. */
 
 static void
-limbs_div(limb_t *quot, limb_t *rem, const limb_t *a, Py_ssize_t a_size,
+limbs_divmod(limb_t *quot, limb_t *rem, const limb_t *a, Py_ssize_t a_size,
           const limb_t *b, Py_ssize_t b_size, limb_t *w)
 {
     limb_t scale, top, a_top, b_top, q, dummy;
@@ -949,18 +937,14 @@
     assert(digits_in_limb == LIMB_DIGITS);
 }
 
-/* Base conversion, from base 2**15 to base LIMB_BASE.
+/* Base conversion, from base PyLong_BASE to base LIMB_BASE.
 
-   Convert an array of (base 2**15) digits for a Python long to an
-   array of limbs representing the same number.  Returns the number of
-   limbs of a filled.  The result is normalized, in the sense that if
-   the returned size a_size is nonzero then a[a_size-1] is nonzero.
+   Convert an array of digits for a Python long to an array of limbs
+   representing the same number.  Returns the number of limbs of a filled.
+   The result is normalized, in the sense that if the returned size a_size is
+   nonzero then a[a_size-1] is nonzero.
 
-   a should have at least:
-
-   ceiling(b_size * log(2**15)/log(LIMB_BASE))
-
-   limbs available.
+   a should have sufficient space to store the converted result.
 */
 
 static Py_ssize_t
@@ -979,7 +963,8 @@
     return a_size;
 }
 
-/* base conversion, from base LIMB_BASE to base 2**30. */
+/* base conversion, from base LIMB_BASE to base PyLong_BASE.
+   b should have sufficient space to store the converted result. */
 
 static Py_ssize_t
 limbs_to_longdigits(digit *b, const limb_t *a, Py_ssize_t a_size)
@@ -1017,23 +1002,17 @@
  * Karatsuba multiplication *
  ****************************/
 
-/* Note that for a balanced multiplication, where you don't want to
-   keep the original multiplicands, one can do the multiplication
-   without any additional workspace necessary:
-
-   to multiply a0 a1 * b0 b1, with result in z0 z1 z2 z3
-   (1) a0 - a1 -> z2
-   (2) b0 - b1 -> z3
-   (3) a0 * b0 -> z0 z1
-   (4) b1 -> a0
-   (5) z2 * z3 -> b0 b1
-   (6) a0 * a1 -> z2 z3
-   (7)
-*/
-
+/* Karatsuba multiplication algorithm.  There are two functions here: the
+   first, limbs_kmul, does Karatsuba multiplication in the more-or-less
+   balanced case, where the multiplier and multiplicand have roughly the same
+   number of limbs.
+
+   The second function, limbs_mul_dispatch, performs multiplication for
+   arbitrary sizes, splitting one or other of the arguments if necessary
+   before calling the balanced Karatsuba function. */
 
-/* Unbalanced karatsuba multiplication: multiply a and b, putting result (of
-   size a_size + b_size) in res.  w provides workspace.
+/* Basic karatsuba multiplication: multiply a and b, putting result (of size
+   a_size + b_size) in res.  w provides workspace.
 
    Preconditions: 1 <= k < a_size <= b_size <= 2*k, and k is a
    power of 2.
@@ -1066,45 +1045,22 @@
    +-----+-+-----+
    0   n-k k     n
 
-   Sizes:
-   a0    k
-   a1    m-k
-   b0    n-k
-   b1    k
-   c     k
-   d     k
-   a0*b0 n
-   a1*b1 m
-   c*d   2*k
 */
 
-
-/* notes:
-
-   (1) there's no real need to pass w_size around, but it helps guard
-   against errors
-   (2) slice notation in the comments below is as in Python:
-   res[2n:4n] means the number represented by res[2*n] through
-   res[4*n-1], inclusive.
-*/
-
-/* decide how to handle a particular size of multiplication, and
-   dispatch to the appropriate function to do the computation */
-
-/* strategy: wlog suppose 1 <= m <= n.
+/* strategy for limbs_mul_dispatch: wlog suppose 1 <= m <= n.
 
    (1) if m == 1, do a basecase multiplication.
 
    Otherwise, let k be the largest power of 2 strictly less than m
    (so k < m <= 2*k).  Then:
 
-   (2) If n <= 2*k, do a Karatsuba multiplication.  Else
+   (2) If n <= 2*k, do a Karatsuba multiplication.
 
    (3) Otherwise, split n as n[:2k] and n[2k:], and do an m*(2k) Karatsuba
    multiplication and a m * (n-2k) multiplication (via a recursive call to
    limbs_mul_dispatch).  Add the results.
 
-   Question: how much workspace do we need for this?
+   How much workspace do we need for this?
 
    Write W(m, n) for the amount of workspace needed; assume 1 <= m <= n.
 
@@ -1138,6 +1094,9 @@
 
 #define KARATSUBA_CUTOFF 72
 
+/* we don't absolutely have to pass w_size around, but doing so
+   helps guard against errors */
+
 /* limbs_kmul and limbs_mul_dispatch call each other recursively,
    so we need a forward declaration */
 
@@ -1280,12 +1239,22 @@
 
 static PyTypeObject deccoeff_DeccoeffType;
 
+/* output contents of a deccoeff, for debugging */
+
+static void
+deccoeff_printf(const char *name, deccoeff *v)
+{
+    limbs_printf(name, v->ob_limbs, Py_SIZE(v));
+    printf("Number of limbs: %ld\n", Py_SIZE(v));
+}
+
 /* allocate a new decimal integer with 'size' limbs */
 
 static deccoeff *
 _deccoeff_new(Py_ssize_t size)
 {
     /* XXX check for overflow */
+    assert(size >= 0);
     return PyObject_NEW_VAR(deccoeff, &deccoeff_DeccoeffType, size);
 }
 
@@ -1302,9 +1271,10 @@
     return v;
 }
 
-/* returns its argument (with reference count unaffected) if the argument has
-   MAX_DIGITS or fewer digits.  Otherwise it decrements the reference count
-   for its argument, sets OverflowError, and returns NULL. */
+/* deccoeff_checksize returns its argument (with reference count unaffected)
+   if the argument has MAX_DIGITS or fewer digits.  Otherwise it decrements
+   the reference count for its argument, sets OverflowError, and returns
+   NULL. */
 
 static deccoeff *
 deccoeff_checksize(deccoeff *v)
@@ -1333,6 +1303,8 @@
     return NULL;
 }
 
+/* Make a copy of a deccoeff */
+
 static deccoeff *
 _deccoeff_copy(deccoeff *a)
 {
@@ -1367,6 +1339,10 @@
     return z;
 }
 
+/* convert an array of unicode characters into a Deccoeff instance.
+   May raise OverflowError if the character array is too long, or
+   ValueError if the array is invalid. */
+
 static deccoeff *
 _deccoeff_from_unicode_and_size(const Py_UNICODE *s, Py_ssize_t s_len) {
     Py_ssize_t z_size;
@@ -1391,9 +1367,15 @@
                         "nondigit character in input");
         return NULL;
     }
+
     return deccoeff_normalize(z);
 }
 
+/* Variant of the above that converts an array of unicode digits containing a
+   decimal point at position int_len (but no sign).  The decimal point is
+   simply ignored.  This is used to parse the coefficient of a Decimal
+   instance. */
+
 static deccoeff *
 _deccoeff_from_pointed_unicode_and_size(const Py_UNICODE *s, Py_ssize_t s_len,
                                       Py_ssize_t int_len) {
@@ -1416,17 +1398,109 @@
 }
 
 
+/***********************************
+ * Deccoeff <-> PyLong conversions *
+ ***********************************/
+
+/* Rational approximations to log2(10):
+
+   LOG2_10LP/LOG2_10LQ is a lower bound for log2(10);
+   LOG2_10UP/LOG2_10UQ is an upper bound.
+
+      485/146  = 3.321917808219...
+      log2(10) = 3.321928094887...
+      2136/643 = 3.321928460342...
+
+   For correctness of scale_Py_ssize_t, it's required that LOG2_10UP *
+   LOG2_10UQ * LIMB_DIGITS * PyLong_SHIFT and LOG2_10LP * LOG2_10LQ *
+   LIMB_DIGITS * PyLong_SHIFT both fit into a Py_ssize_t.  The values below
+   are okay even if we're using 64-bit types to hold limbs and digits: in that
+   case, LIMB_DIGITS <= 19 and PyLong_SHIFT <= 64.
+*/
+
+#define LOG2_10LP 485
+#define LOG2_10LQ 146
+#define LOG2_10UP 2136
+#define LOG2_10UQ 643
+
+/* Compute ceiling(n*p/q) without intermediate overflow.  If the result
+   would be larger than PY_SSIZE_T_MAX, return -1.  Assumes that
+   n is nonnegative, and that (q-1)*(p+1) <= PY_SSIZE_T_MAX. */
+
+static Py_ssize_t
+scale_Py_ssize_t(Py_ssize_t n, int p, int q) {
+    Py_ssize_t hi, low;
+    assert (n >= 0);
+    hi = n/q;
+    if (hi > PY_SSIZE_T_MAX/p)
+        return -1;
+    hi *= p;
+    low = (n%q*p+q-1)/q;
+    if (hi > PY_SSIZE_T_MAX-low)
+        return -1;
+    return hi+low;
+}
+
+/* Create a Deccoeff from a Python integer. */
+
+static deccoeff *
+deccoeff_from_PyLong(PyLongObject *a)
+{
+    Py_ssize_t a_size, z_size;
+    deccoeff *z;
+
+    a_size = Py_SIZE(a);
+    if (a_size < 0) {
+        PyErr_SetString(PyExc_OverflowError,
+                        "Can't convert negative integer to " CLASS_NAME);
+        return NULL;
+    }
+    z_size = scale_Py_ssize_t(a_size,
+                              LOG2_10LQ * PyLong_SHIFT,
+                              LOG2_10LP * LIMB_DIGITS);
+    if (z_size == -1)
+        PyErr_SetString(PyExc_OverflowError,
+                        "Overflow in int to " CLASS_NAME " conversion\n");
+    z = _deccoeff_new(z_size);
+    if (z==NULL)
+        return NULL;
+    Py_SIZE(z) = limbs_from_longdigits(z->ob_limbs, a->ob_digit, a_size);
+    return deccoeff_checksize(z);
+}
+
+/* Convert a Python integer to a Deccoeff */
+
+static PyLongObject *
+deccoeff_long(deccoeff *a)
+{
+    Py_ssize_t a_size, z_size;
+    PyLongObject *z;
+
+    a_size = Py_SIZE(a);
+    z_size = scale_Py_ssize_t(a_size,
+                              LOG2_10UP * LIMB_DIGITS,
+                              LOG2_10UQ * PyLong_SHIFT);
+    if (z_size == -1)
+        PyErr_SetString(PyExc_OverflowError,
+                        "Overflow in " CLASS_NAME " to int conversion\n");
+    z = _PyLong_New(z_size);
+    if (z == NULL)
+        return NULL;
+    Py_SIZE(z) = limbs_to_longdigits(z->ob_digit, a->ob_limbs, a_size);
+    return z;
+}
+
 
 /***************************
  * Arithmetic on deccoeffs *
  ***************************/
 
-/* General rules: if the result of any arithmetic operation falls
-   outside the range [0, 10**MAX_DIGITS) then OverflowError is raised.
-   Results are always normalized. */
+/* General rules: if the result of any arithmetic operation falls outside the
+   range [0, 10**MAX_DIGITS) then OverflowError is raised.  Results are always
+   normalized. */
 
-/* determine whether another Python object is compatible with deccoeff, in the
-   sense that it can be used in mixed-type arithmetic with deccoeff */
+/* determine whether another Python object can be used in mixed-type arithmetic
+   with deccoeff */
 
 static bool
 compatible_with_deccoeff(PyObject *v)
@@ -1434,11 +1508,7 @@
     return (v->ob_type == &deccoeff_DeccoeffType || PyIndex_Check(v));
 }
 
-/* convert an arbitrary PyObject to a deccoeff.  If conversion is implemented
-   for this type, return false and put the result of the attempted conversion
-   (which may be NULL on failure) in *z.   Otherwise, return true. */
-
-static deccoeff *deccoeff_from_PyLong(PyLongObject *a);
+/* convert an arbitrary PyObject to a Deccoeff.  Returns a new reference. */
 
 static deccoeff *
 convert_to_deccoeff(PyObject *v)
@@ -1465,28 +1535,31 @@
     }
 }
 
+/* wrap a binary operation on deccoeffs to give a binary
+   operation on PyObjects */
+
 #define DECCOEFF_WRAP_BINOP(PO_func, DC_func)                        \
     static PyObject *                                                \
     PO_func(PyObject *v, PyObject *w)                                \
     {                                                                \
-        deccoeff *a, *b;                                        \
-        PyObject *z = NULL;                                        \
-        if (!compatible_with_deccoeff(v)) {                        \
-            Py_INCREF(Py_NotImplemented);                        \
-            z = Py_NotImplemented;                                \
-        }                                                        \
-        else if ((a = convert_to_deccoeff(v)) != NULL) {        \
-            if (!compatible_with_deccoeff(w)) {                 \
-                Py_INCREF(Py_NotImplemented);                   \
-                z = Py_NotImplemented;                          \
-            }                                                   \
-            else if ((b = convert_to_deccoeff(w)) != NULL) {        \
-                z = (PyObject *)(DC_func(a, b));                \
-                Py_DECREF(b);                                   \
-            }                                                   \
-            Py_DECREF(a);                                        \
-        }                                                        \
-        return z;                                                \
+        deccoeff *a, *b;                                             \
+        PyObject *z = NULL;                                          \
+        if (!compatible_with_deccoeff(v)) {                          \
+            Py_INCREF(Py_NotImplemented);                            \
+            z = Py_NotImplemented;                                   \
+        }                                                            \
+        else if ((a = convert_to_deccoeff(v)) != NULL) {             \
+            if (!compatible_with_deccoeff(w)) {                      \
+                Py_INCREF(Py_NotImplemented);                        \
+                z = Py_NotImplemented;                               \
+            }                                                        \
+            else if ((b = convert_to_deccoeff(w)) != NULL) {         \
+                z = (PyObject *)(DC_func(a, b));                     \
+                Py_DECREF(b);                                        \
+            }                                                        \
+            Py_DECREF(a);                                            \
+        }                                                            \
+        return z;                                                    \
     }
 
 /* addition */
@@ -1635,7 +1708,7 @@
             *r = NULL;
             return NULL;
         }
-        limbs_div(quot->ob_limbs, rem->ob_limbs, a->ob_limbs, a_size,
+        limbs_divmod(quot->ob_limbs, rem->ob_limbs, a->ob_limbs, a_size,
                   b->ob_limbs, b_size, w->ob_limbs);
         Py_DECREF(w);
     }
@@ -2066,71 +2139,6 @@
     return z;
 }
 
-/* Compute ceiling(n*p/q) without intermediate overflow.  If the result
-   would be larger than PY_SSIZE_T_MAX, return -1.  Assumes that
-   n is nonnegative, and that (q-1)*(p+1) <= PY_SSIZE_T_MAX. */
-
-static Py_ssize_t
-scale_Py_ssize_t(Py_ssize_t n, int p, int q) {
-    Py_ssize_t hi, low;
-    assert (n >= 0);
-    hi = n/q;
-    if (hi > PY_SSIZE_T_MAX/p)
-        return -1;
-    hi *= p;
-    low = (n%q*p+q-1)/q;
-    if (hi > PY_SSIZE_T_MAX-low)
-        return -1;
-    return hi+low;
-}
-
-/* Create a deccoeff from a Python integer. */
-
-static deccoeff *
-deccoeff_from_PyLong(PyLongObject *a)
-{
-    Py_ssize_t a_size, z_size;
-    deccoeff *z;
-
-    a_size = Py_SIZE(a);
-    if (a_size < 0) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "Can't convert negative integer to " CLASS_NAME);
-        return NULL;
-    }
-    z_size = scale_Py_ssize_t(a_size,
-                              LOG2_10LQ * PyLong_SHIFT,
-                              LOG2_10LP * LIMB_DIGITS);
-    if (z_size == -1)
-        PyErr_SetString(PyExc_OverflowError,
-                        "Overflow in int to " CLASS_NAME " conversion\n");
-    z = _deccoeff_new(z_size);
-    if (z==NULL)
-        return NULL;
-    Py_SIZE(z) = limbs_from_longdigits(z->ob_limbs, a->ob_digit, a_size);
-    return deccoeff_checksize(z);
-}
-
-static PyLongObject *
-deccoeff_long(deccoeff *a)
-{
-    Py_ssize_t a_size, z_size;
-    PyLongObject *z;
-
-    a_size = Py_SIZE(a);
-    z_size = scale_Py_ssize_t(a_size,
-                              LOG2_10UP * LIMB_DIGITS,
-                              LOG2_10UQ * PyLong_SHIFT);
-    if (z_size == -1)
-        PyErr_SetString(PyExc_OverflowError,
-                        "Overflow in " CLASS_NAME " to int conversion\n");
-    z = _PyLong_New(z_size);
-    if (z == NULL)
-        return NULL;
-    Py_SIZE(z) = limbs_to_longdigits(z->ob_digit, a->ob_limbs, a_size);
-    return z;
-}
-
 static PyObject *
 deccoeff_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -2193,6 +2201,16 @@
     return PyLong_FromSsize_t(_deccoeff_length(v));
 }
 
+PyDoc_STRVAR(deccoeff_digit_length_doc,
+"\
+Deccoeff.digit_length(self) -> integer\n\
+\n\
+Number of decimal digits required to represent self.\n\
+\n\
+If self is positive, return the least nonnegative integer\n\
+k such that self < 10**k.  If self is zero, return 0.\n\
+");
+
 static void
 deccoeff_dealloc(PyObject *v)
 {
@@ -2248,7 +2266,7 @@
 
 static PyMethodDef deccoeff_methods[] = {
     {"digit_length", (PyCFunction)deccoeff_digit_length, METH_NOARGS,
-     "Number of digits."},
+     deccoeff_digit_length_doc},
     {NULL, NULL}
 };
 
@@ -2276,7 +2294,7 @@
     0, /*nb_xor*/
     0, /*nb_or*/
     (unaryfunc) deccoeff_long,              /*nb_int*/
-    (unaryfunc) deccoeff_long,              /*nb_long*/
+    0, /*nb_long*/
     0, /*nb_float*/
     0, /*nb_inplace_add*/
     0, /*nb_inplace_subtract*/
@@ -2295,18 +2313,17 @@
     (unaryfunc) deccoeff_long,              /*nb_index*/
 };
 
+/* str(deccoeff) */
+
 static PyObject *
 deccoeff_str(deccoeff *v)
 {
-    Py_ssize_t sz, nlimbs;
-    limb_t *limb_pointer, *last_limb, limb_value;
+    Py_ssize_t size, nlimbs;
     PyObject *str;
-    int i;
     Py_UNICODE *p;
 
     nlimbs = Py_SIZE(v);
     if (nlimbs == 0) {
-        /* return empty string */
         str = PyUnicode_FromUnicode(NULL, 1);
         if (str == NULL)
             return NULL;
@@ -2315,35 +2332,21 @@
         *--p = '0';
         return str;
     }
+    size = _deccoeff_length(v);
 
-    sz = _deccoeff_length(v);
-
-    str = PyUnicode_FromUnicode(NULL, sz);
+    assert(size >= 0);
+    str = PyUnicode_FromUnicode(NULL, size);
     if (str == NULL)
         return NULL;
-    p = PyUnicode_AS_UNICODE(str) + sz;
-    *p = '\0';
+    p = PyUnicode_AS_UNICODE(str);
 
-    /* fill in digits from right to left;  start with the least
-       significant limb_t */
-    limb_pointer = v -> ob_limbs;
-    last_limb = limb_pointer + nlimbs - 1;
-    while (limb_pointer < last_limb) {
-        limb_value = *limb_pointer++;
-        for (i=0; i < LIMB_DIGITS; i++)
-            *--p = limb_to_wdigit(
-                limb_rshift(&limb_value,
-                            limb_value, 1, LIMB_ZERO));
-    }
-    /* most significant limb_t */
-    limb_value = *limb_pointer;
-    assert(limb_bool(limb_value));
-    while (limb_bool(limb_value))
-        *--p = limb_to_wdigit(
-            limb_rshift(&limb_value, limb_value, 1, LIMB_ZERO));
+    limbs_as_unicode(p, size, v->ob_limbs);
+    *(p+size) = '\0';
     return str;
 }
 
+/* repr(Deccoeff_instance) looks like "Deccoeff('123')" */
+
 static PyObject *
 deccoeff_repr(deccoeff *v)
 {
@@ -2410,10 +2413,10 @@
 /* A finite decimal object needs a sign, a coefficient and an exponent.  An
    infinity has a sign and nothing more; the coefficient and exponent are
    ignored.  A (quiet or signalling) nan has a sign, and may carry additional
-   information in the coefficient.  The exponent is not used. */
+   information (the payload) in the coefficient.  The exponent is not used. */
 
 #define DEC_FLAGS_NEG (1<<0)
-#define DEC_FLAGS_NONZERO (1<<1) /* currently unused, but may want this later */
+#define DEC_FLAGS_NONZERO (1<<1) /* currently unused; may want this later */
 #define DEC_FLAGS_SPECIAL (1<<2)
 #define DEC_FLAGS_INF  (1<<3)
 #define DEC_FLAGS_NAN (1<<4)
@@ -2505,10 +2508,14 @@
 
 /* Macros to create finite, infinite, qnan, and snan _Decimal instances */
 
-#define FINITE_DECIMAL(type, sign, coeff, exp) (__Decimal_new(type, sign, coeff, exp))
-#define INF_DECIMAL(type, sign) (__Decimal_new(type, sign | INF_FLAGS, NULL, NULL))
-#define QNAN_DECIMAL(type, sign, payload) (__Decimal_new(type, sign | QNAN_FLAGS, payload, NULL))
-#define SNAN_DECIMAL(type, sign, payload) (__Decimal_new(type, sign | SNAN_FLAGS, payload, NULL))
+#define FINITE_DECIMAL(type, sign, coeff, exp) \
+    (__Decimal_new(type, sign, coeff, exp))
+#define INF_DECIMAL(type, sign) \
+    (__Decimal_new(type, sign | INF_FLAGS, NULL, NULL))
+#define QNAN_DECIMAL(type, sign, payload) \
+    (__Decimal_new(type, sign | QNAN_FLAGS, payload, NULL))
+#define SNAN_DECIMAL(type, sign, payload) \
+    (__Decimal_new(type, sign | SNAN_FLAGS, payload, NULL))
 
 /* create a new finite _Decimal instance */
 
@@ -2819,7 +2826,8 @@
     if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
         return NULL;
     if (opayload->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError, "payload should have type " CLASS_NAME);
+        PyErr_SetString(PyExc_TypeError,
+                        "payload should have type " CLASS_NAME);
         return NULL;
     }
     payload = (deccoeff *)opayload;
@@ -2841,7 +2849,8 @@
     if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
         return NULL;
     if (opayload->ob_type != &deccoeff_DeccoeffType) {
-        PyErr_SetString(PyExc_TypeError, "payload should have type " CLASS_NAME);
+        PyErr_SetString(PyExc_TypeError,
+                        "payload should have type " CLASS_NAME);
         return NULL;
     }
     payload = (deccoeff *)opayload;
@@ -3053,35 +3062,35 @@
 
 static PyTypeObject deccoeff__DecimalType = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    MODULE_NAME "." DECIMAL_NAME,             /* tp_name */
-    sizeof(_Decimal),                       /* tp_basicsize */
-    0,                          /* tp_itemsize */
-    _Decimal_dealloc,                       /* tp_dealloc */
+    MODULE_NAME "." DECIMAL_NAME,               /* tp_name */
+    sizeof(_Decimal),                           /* tp_basicsize */
+    0, /* tp_itemsize */
+    _Decimal_dealloc,                           /* tp_dealloc */
     0, /* tp_print */
     0, /* tp_getattr */
     0, /* tp_setattr */
     0, /* tp_compare */
-    0,                /* tp_repr */
-    0,                    /* tp_as_number */
+    0, /* tp_repr */
+    0, /* tp_as_number */
     0, /* tp_as_sequence */
-    0,                   /* tp_as_mapping */
-    0,                /* tp_hash */
+    0, /* tp_as_mapping */
+    0, /* tp_hash */
     0, /* tp_call */
-    0,                 /* tp_str */
+    0, /* tp_str */
     0, /* tp_getattro */
     0, /* tp_setattro */
     0, /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                     /* tp_flags */
-    "support for Decimal type",                     /* tp_doc */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
+    "support for Decimal type",                 /* tp_doc */
     0, /* tp_traverse */
     0, /* tp_clear */
-    0,      /* tp_richcompare */
+    0, /* tp_richcompare */
     0, /* tp_weaklistoffset */
     0, /* tp_iter */
     0, /* tp_iternext */
-    _Decimal_methods,                       /* tp_methods */
+    _Decimal_methods,                           /* tp_methods */
     0, /* tp_members */
-    _Decimal_getsetters, /* tp_getset */
+    _Decimal_getsetters,                        /* tp_getset */
     0, /* tp_base */
     0, /* tp_dict */
     0, /* tp_descr_get */
@@ -3089,8 +3098,8 @@
     0, /* tp_dictoffset */
     0, /* tp_init */
     0, /* tp_alloc */
-    _Decimal_new,                           /* tp_new */
-    PyObject_Del,                           /* tp_free */
+    _Decimal_new,                               /* tp_new */
+    PyObject_Del,                               /* tp_free */
 };
 
 static PyMethodDef deccoeff_module_methods[] = {


More information about the Python-checkins mailing list