[Python-checkins] r46163 - sandbox/trunk/decimal-c/_decimal.c

georg.brandl python-checkins at python.org
Wed May 24 13:42:02 CEST 2006


Author: georg.brandl
Date: Wed May 24 13:42:02 2006
New Revision: 46163

Modified:
   sandbox/trunk/decimal-c/_decimal.c
Log:
Adding some nb_ methods.



Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Wed May 24 13:42:02 2006
@@ -624,10 +624,10 @@
         if (!new) return NULL;
     }
 
-    expdiff = prec - new->ob_size;
+    expdiff = new->ob_size - prec;
     if (expdiff == 0)
         return new;
-    else if (expdiff > 0) {
+    else if (expdiff < 0) {
         /* we need to extend precision */
         new2 = _NEW_decimalobj(prec, new->sign, new->exp - expdiff);
         if (!new2) {
@@ -901,20 +901,20 @@
    returns NotImplemented or raises an exception, depending
    on the raise argument.
 */
-static decimalobject *
+static PyObject *
 _convert_to_decimal(PyTypeObject *type, PyObject *thing,
                     contextobject *ctx, int raise)
 {
     if (PyDecimal_Check(thing)) {
         Py_INCREF(thing);
-        return (decimalobject *)thing;
+        return thing;
     } else if (PyInt_Check(thing)) {
         long val = PyInt_AsLong(thing);
         if (val == -1 && PyErr_Occurred())
             return NULL;
-        return (decimalobject *)decimal_from_long(type, val);
+        return decimal_from_long(type, val);
     } else if (PyLong_Check(thing)) {
-        return _decimal_from_pylong(type, thing, ctx);
+        return (PyObject *)_decimal_from_pylong(type, thing, ctx);
     }
     /* failed to convert */
     if (raise) {
@@ -1248,24 +1248,36 @@
 PyDoc_STR("Floating point class for decimal arithmetic.");
 
 
-#define DECIMAL_SPECIAL_FUNC(func)                          \
-    static PyObject *                                       \
-    func (decimalobject *self, decimalobject *other) {      \
-        contextobject *ctx = getcontext();                  \
-        if (!ctx) return NULL;                              \
-        return (PyObject *)_do_##func(self, other, ctx);    \
+#define DECIMAL_SPECIAL_2FUNC(func)                                     \
+    static PyObject *                                                   \
+    func (PyObject *self, PyObject *other) {                            \
+        decimalobject *res;                                             \
+        contextobject *ctx = getcontext();                              \
+        if (!ctx) return NULL;                                          \
+        other = _convert_to_decimal(self->ob_type, other, ctx, 0);      \
+        if (other == NULL || other == Py_NotImplemented) return other;  \
+        res = _do_##func((decimalobject *)self,                         \
+                         (decimalobject *)other, ctx);                  \
+        Py_DECREF(other);                                               \
+    }
+
+#define DECIMAL_SPECIAL_1FUNC(func)                                 \
+    static PyObject *                                               \
+    func (PyObject *self) {                                         \
+        contextobject *ctx = getcontext();                          \
+        if (!ctx) return NULL;                                      \
+        return (PyObject *)_do_##func((decimalobject *)self, ctx);  \
     }
 
-static PyObject *
+
+
+static decimalobject *
 _do_decimal_add(decimalobject *self, decimalobject *other,
                 contextobject *ctx)
 {
-    other = _convert_to_decimal(self->ob_type, other, ctx, 0);
-    if (other == Py_NotImplemented) return other;
-
     /* XXX */
 }
-DECIMAL_SPECIAL_FUNC(decimal_add)
+DECIMAL_SPECIAL_2FUNC(decimal_add)
 
 static decimalobject *
 _do_decimal_subtract(decimalobject *self, decimalobject *other,
@@ -1273,19 +1285,13 @@
 {
     decimalobject *copy, *res;
     
-    other = _convert_to_decimal(self->ob_type, other, ctx, 0);
-    if (other == Py_NotImplemented) return other;
-
     if (ISSPECIAL(self) || ISSPECIAL(other)) {
         decimalobject *nan;
-        if (_check_nans(self, other, ctx, &nan) != 0) {
-            Py_DECREF(other);
+        if (_check_nans(self, other, ctx, &nan) != 0)
             return nan;
-        }
     }
 
     copy = _decimal_get_copy(other);
-    Py_DECREF(other);
     if (!copy)
         return NULL;
     /* flip sign */
@@ -1298,52 +1304,180 @@
     Py_DECREF(copy);
     return res;        
 }
-DECIMAL_SPECIAL_FUNC(decimal_subtract)
+DECIMAL_SPECIAL_2FUNC(decimal_subtract)
 
 STUB(multiply)
 STUB(divide)
 STUB(remainder)
 STUB(divmod)
 STUB(power)
-STUB1(negative)
-STUB1(positive)
-STUB1(absolute)
-STUB1(invert)
 
+static decimalobject *
+_do_decimal_negative(decimalobject *self, contextobject *ctx)
+{
+    int sign = 0;
+    decimalobject *tmp, *res;
+    
+    if (ISSPECIAL(self)) {
+        decimalobject *nan;
+        if (_check_nans(self, NULL, ctx, &nan) != 0)
+            return nan;
+    }
+    if (! decimal_nonzero(self))
+        /* - '0' => '0', not '-0' */
+        sign = 0;
+    else if (self->sign & 1)
+        sign--;
+    else
+        sign++;
+
+    res = _decimal_get_copy(self);
+    if (!res) return NULL;
+    res->sign = sign;
+    if (ctx->rounding_dec == ALWAYS_ROUND) {
+        tmp = _decimal_fix(res, ctx);
+        Py_DECREF(res);
+        if (!tmp)
+            return NULL;
+        return tmp;
+    } else {
+        return res;
+    }    
+}
+DECIMAL_SPECIAL_1FUNC(decimal_negative)
+
+
+static decimalobject *
+_do_decimal_positive(decimalobject *self, contextobject *ctx)
+{
+    decimalobject *res, *tmp;
+    char sign = self->sign;
+
+    if (ISSPECIAL(self)) {
+        decimalobject *nan;
+        if (_check_nans(self, NULL, ctx, &nan) != 0)
+            return nan;
+    }
+    
+    if (! decimal_nonzero(self))
+        /* + '-0' => '0' */
+        sign = 0;
+
+    res = _decimal_get_copy(self);
+    if (!res) return NULL;
+    res->sign = sign;
+    if (ctx->rounding_dec == ALWAYS_ROUND) {
+        tmp = _decimal_fix(res, ctx);
+        Py_DECREF(res);
+        if (!tmp)
+            return NULL;
+        return tmp;
+    } else {
+        return res;
+    }
+}
+DECIMAL_SPECIAL_1FUNC(decimal_positive)
+
+
+static decimalobject *
+_do_decimal_absolute(decimalobject *self, contextobject *ctx, int round)
+{
+    contextobject *ctx2 = NULL;
+    decimalobject *ans;
+    
+    if (ISSPECIAL(self)) {
+        decimalobject *nan;
+        if (_check_nans(self, NULL, ctx, &nan) != 0)
+            return nan;
+    }
+
+    if (!round) {
+        ctx2 = context_copy(ctx);
+        if (!ctx2) return NULL;
+        ctx2->rounding_dec = NEVER_ROUND;
+    }
+
+    if (self->sign & 1)
+        ans = _do_decimal_negative(self, ctx2);
+    else
+        ans = _do_decimal_positive(self, ctx2);
+    Py_XDECREF(ctx2);
+    return ans;
+}
 
 static PyObject *
+decimal_absolute(PyObject *self)
+{
+    contextobject *ctx = getcontext();
+    if (!ctx) return NULL;
+    return (PyObject *)_do_decimal_absolute((decimalobject *)self, ctx, 1);
+}    
+
+
+static PyObject *
+decimal_long(decimalobject *self)
+{
+    long i, max;
+    char *buf;
+    PyObject *res;
+
+    max = self->ob_size + self->exp;
+    
+    buf = PyMem_MALLOC(max + 2); /* with sign */
+    if (!buf) return NULL;
+    buf[0] = (self->sign & 1 ? '-' : '+');
+    for (i = 0; i < max; i++) {
+        if (i < self->ob_size)
+            buf[i+1] = self->digits[i] + 48;
+        else
+            buf[i+1] = '0';
+    }
+    buf[max+1] = 0;
+    res = PyLong_FromString(buf, NULL, 10);
+    PyMem_FREE(buf);
+    return res;
+}
+
+/* Convert to int, truncating. */
+static PyObject *
 decimal_int(decimalobject *self)
 {
-    if (ISSPECIAL(self))
+    long res = 0;
+    long i, max;
+    
+    if (ISSPECIAL(self)) {
         if (GETNAN(self)) {
             contextobject *ctx;
             ctx = getcontext();
             if (!ctx) return NULL;
-            return handle_InvalidContext(self->ob_type, ctx, NULL);
+            return (PyObject *)handle_InvalidContext(self->ob_type, ctx, NULL);
         } else if (ISINF(self)) {
             PyErr_SetString(PyExc_OverflowError, "Cannot convert infinity to long");
             return NULL;
         }
+    }
 
-}
-            
+    /* try converting to int, if it's too big, convert to long  */
+    max = self->ob_size + self->exp;
 
-static PyObject *
-decimal_long(decimalobject *self)
-{
-    PyObject *tmp, *res;
-    tmp = decimal_int(self);
-    if (PyInt_Check(tmp)) {
-        res = PyLong_FromLong(PyInt_AsLong(tmp));
-        Py_DECREF(tmp);
-        return res;
-    } else {
-        /* it's already a long */
-        assert(PyLong_Check(tmp));
-        return tmp;
+#if SIZEOF_LONG == 4
+    if (max > 9) return decimal_long(self);
+#elif SIZEOF_LONG == 8
+    if (max > 18) return decimal_long(self);
+#else
+#error "Decimal currently assumes that SIZEOF_LONG is 4 or 8, please adapt this"
+#endif
+
+    for (i = 0; i < max; i++) {
+        if (i < self->ob_size)
+            res = res * 10 + self->digits[i];
+        else
+            res *= 10;
     }
+    if (self->sign & 1) res = -res;
+    return PyInt_FromLong(res);
 }
-
+            
 static PyObject *
 decimal_float(decimalobject *self)
 {
@@ -1366,7 +1500,7 @@
     if (ISSPECIAL(self))
         return 1;
     for (i = 0; i < self->ob_size; i++)
-        if (i != 0) return 1;
+        if (self->digits[i] != 0) return 1;
     return 0;
 }
 
@@ -1381,17 +1515,17 @@
     decimal_negative,    /* nb_negative */
     decimal_positive,    /* nb_positive */
     decimal_absolute,    /* nb_absolute */
-    decimal_nonzero,     /* nb_nonzero */
-    decimal_invert,      /* nb_invert */
+    (inquiry)decimal_nonzero,     /* nb_nonzero */
+    0,                   /* nb_invert */
     0,                   /* nb_lshift */
     0,                   /* nb_rshift */
     0,                   /* nb_and */
     0,                   /* nb_xor */
     0,                   /* nb_or */
     0,                   /* nb_coerce */
-    decimal_int,         /* nb_int */
-    decimal_long,        /* nb_long */
-    decimal_float,       /* nb_float */
+    (unaryfunc)decimal_int,         /* nb_int */
+    (unaryfunc)decimal_long,        /* nb_long */
+    (unaryfunc)decimal_float,       /* nb_float */
     0,                   /* nb_oct */
     0,                   /* nb_hex */
     0,                   /* nb_inplace_add */
@@ -2195,8 +2329,8 @@
 {
     static char *kwlist[] = {"num", 0};
     PyObject *thing = NULL;
-    PyObject *nargs, *nkwds;
-    PyObject *res, *fixed;
+    PyObject *nargs, *nkwds, *res;
+    decimalobject *fixed;
 
     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &thing))
         return NULL;
@@ -2224,7 +2358,7 @@
         Py_DECREF(nargs);
     }
 
-    fixed = _decimal_fix(res, self);
+    fixed = _decimal_fix((decimalobject *)res, self);
     Py_DECREF(res);
     return fixed;
 }
@@ -2794,20 +2928,20 @@
     ctx = getcontext();
     if (!ctx) return;
 
-    PyDecimal_NaN = PyDecimal_FromString("nan", 3, ctx);
+    PyDecimal_NaN = (decimalobject *)PyDecimal_FromString("nan", 3, ctx);
     if (!PyDecimal_NaN)
         return;
-    if (PyModule_AddObject(m, "NaN", PyDecimal_NaN) < 0)
+    if (PyModule_AddObject(m, "NaN", (PyObject *)PyDecimal_NaN) < 0)
         return;
-    PyDecimal_Inf = PyDecimal_FromString("inf", 3, ctx);
+    PyDecimal_Inf = (decimalobject *)PyDecimal_FromString("inf", 3, ctx);
     if (!PyDecimal_Inf)
         return;
-    if (PyModule_AddObject(m, "Inf", PyDecimal_Inf) < 0)
+    if (PyModule_AddObject(m, "Inf", (PyObject *)PyDecimal_Inf) < 0)
         return;
-    PyDecimal_NegInf = PyDecimal_FromString("-inf", 4, ctx);
+    PyDecimal_NegInf = (decimalobject *)PyDecimal_FromString("-inf", 4, ctx);
     if (!PyDecimal_NegInf)
         return;
-    if (PyModule_AddObject(m, "negInf", PyDecimal_NegInf) < 0)
+    if (PyModule_AddObject(m, "negInf", (PyObject *)PyDecimal_NegInf) < 0)
         return;
 
     ADD_CONST(m, ROUND_DOWN);


More information about the Python-checkins mailing list