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

mateusz.rukowicz python-checkins at python.org
Tue Jun 27 04:48:31 CEST 2006


Author: mateusz.rukowicz
Date: Tue Jun 27 04:48:30 2006
New Revision: 47112
Modified:
 sandbox/trunk/decimal-c/_decimal.c
Log:
remainder_near implemented, some minor bugs fixed.
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Tue Jun 27 04:48:30 2006
@@ -694,6 +694,7 @@
 static decimalobject *_decimal_fromliteral(PyTypeObject *, char *str, long, contextobject *);
 static decimalobject *_do_decimal_multiply(decimalobject *, decimalobject *, contextobject *);
 static decimalobject *_do_decimal_subtract(decimalobject *, decimalobject *, contextobject *);
+static PyObject *context_ignore_flags(contextobject *self, PyObject *args);
 
 /* Exception handlers *********************************************************/
 
@@ -777,8 +778,9 @@
 {
 HANDLE_ERROR(ctx, C_DIV_IMPOSSIBLE, expl, NULL);
 
- Py_INCREF(PyDecimal_NaN);
- return PyDecimal_NaN;
+/* Py_INCREF(PyDecimal_NaN); */
+ 
+ return Py_BuildValue("(OO)", PyDecimal_NaN, PyDecimal_NaN);
 }
 
 static decimalobject *
@@ -787,8 +789,15 @@
 {
 HANDLE_ERROR(ctx, C_DIV_UNDEFINED, expl, NULL);
 
- Py_INCREF(PyDecimal_NaN);
- return PyDecimal_NaN;
+ if (!two) {
+ Py_INCREF(PyDecimal_NaN);
+ return PyDecimal_NaN;
+ }
+ 
+ else {
+ return Py_BuildValue("(OO)", PyDecimal_NaN, PyDecimal_NaN);
+ }
+ 
 }
 
 static int
@@ -1399,6 +1408,7 @@
 for (i = 0; i < tmp->ob_size-1; i++)
 tmp->digits[i] = tmp->digits[i+1]; /* TODO make last digit 0 */
 tmp->ob_size--;
+ tmp->limb_count = (tmp->ob_size + LOG -1)/LOG;
 }
 tmp->exp = exp;
 
@@ -1784,9 +1794,10 @@
 
 res = _do_real_decimal_compare(self, other, ctx);
 Py_DECREF(other);
- if (PyErr_Occurred()) 
+ /* we will return 0 anyway */
+/* if (PyErr_Occurred()) 
 return NULL;
-
+*/
 return res;
 
 }
@@ -2049,12 +2060,277 @@
 }
 
 
+/* it is rewritten from python implementation */
 static decimalobject *
 _do_decimal_remainder_near(decimalobject *self, decimalobject *other,
 contextobject *ctx)
 {
- /* XXX */
- Py_RETURN_NONE;
+ contextobject *ctx2;
+ decimalobject *side, *r;
+ decimalobject *comparison = 0;
+ int rounding_dec;
+ int decrease;
+ PyObject *ignored_flags;
+ PyObject *flags = 0;
+ int s1, s2;
+ if (ISSPECIAL(self) || ISSPECIAL(other)) {
+ decimalobject *nan;
+ if (_check_nans(self, other, ctx, &nan))
+ return nan;
+ }
+
+ if (decimal_nonzero(self) && !decimal_nonzero(other))
+ return handle_InvalidOperation(self->ob_type, ctx, "x % 0", NULL);
+
+ ctx2 = context_shallow_copy(ctx);
+
+ if (!ctx2)
+ return NULL;
+
+ ignored_flags = PyTuple_New(2);
+
+ if (!ignored_flags)
+ goto err;
+
+ Py_INCREF(errors[S_ROUNDED]);
+ Py_INCREF(errors[S_INEXACT]);
+ PyTuple_SET_ITEM(ignored_flags, 0, errors[S_ROUNDED]);
+ PyTuple_SET_ITEM(ignored_flags, 1, errors[S_INEXACT]);
+
+ flags = context_ignore_flags(ctx2, ignored_flags);
+ Py_DECREF(ignored_flags);
+
+ if (!flags)
+ goto err;
+
+ {
+ PyObject *divmod = _do_decimal__divide(self, other, 1, ctx2);
+ if (!divmod) {
+ PyObject *r = context_regard_flags(ctx2, flags);
+ Py_XDECREF(r);
+ goto err;
+ }
+
+ side = PySequence_GetItem(divmod, 0);
+ r = PySequence_GetItem(divmod, 1);
+
+ Py_DECREF(divmod);
+ }
+
+ if (GETNAN(r)) {
+ PyObject *ret;
+ ret = context_regard_flags(ctx2, flags);
+ if (!ret)
+ goto err;
+
+ Py_DECREF(ret);
+ Py_DECREF(flags);
+ Py_DECREF(ctx2);
+ Py_DECREF(side);
+
+ return r;
+ 
+ }
+
+ rounding_dec = ctx2->rounding_dec;
+ ctx2->rounding_dec = NEVER_ROUND;
+
+
+ {
+ decimalobject *two = _NEW_decimalobj(1, 0, 0);
+ if (!two) {
+ PyObject *r = context_regard_flags(ctx2, flags);
+ Py_XDECREF(r);
+ goto err;
+ }
+
+ two->limbs[0] = 2;
+ two->sign = other->sign&1;
+
+ comparison = _do_decimal__divide(other, two, 0, ctx2);
+ Py_DECREF(two);
+
+ if (!comparison)
+ goto err;
+ }
+
+ ctx2->rounding_dec = rounding_dec;
+ {
+ PyObject *ret;
+ ret = context_regard_flags(ctx2, flags);
+ if (!ret)
+ goto err;
+ Py_DECREF(ret);
+ }
+ s1 = r->sign;
+ s2 = comparison->sign;
+ /* we don't want to loose info about infinity */
+ r->sign &= 254;
+ comparison->sign &= 254;
+
+ {
+ int cmp = _do_real_decimal_compare(r, comparison, ctx2);
+ if (PyErr_Occurred())
+ goto err;
+
+ if (cmp == -1) {
+ PyObject *ret;
+ decimalobject *fixed;
+ r->sign = s1;
+ comparison->sign = s2;
+ 
+ ret = _do_decimal__divide(self, other, 1, ctx2);
+
+ if (!ret)
+ goto err;
+ Py_DECREF(ret);
+ fixed = _decimal_fix(r, ctx2);
+ Py_DECREF(r);
+ Py_DECREF(ctx2);
+ Py_DECREF(flags);
+ Py_DECREF(side);
+ Py_DECREF(comparison);
+ 
+ return fixed;
+ }
+ }
+
+ r->sign = s1;
+ comparison->sign = s2;
+
+ rounding_dec = ctx2->rounding_dec;
+ ctx2->rounding_dec = NEVER_ROUND;
+ 
+ {
+ PyObject *divmod = _do_decimal__divide(self, other, 1, ctx2);
+ 
+ if (!divmod)
+ goto err;
+
+ Py_DECREF(side);
+ Py_DECREF(r);
+ 
+ side = PySequence_GetItem(divmod, 0);
+ r = PySequence_GetItem(divmod, 1);
+ Py_DECREF(divmod);
+ }
+
+ ctx2->rounding_dec = rounding_dec;
+
+ if (GETNAN(r)) {
+ Py_DECREF(ctx2);
+ Py_DECREF(flags);
+ Py_DECREF(side);
+ Py_DECREF(comparison);
+ return r;
+ }
+
+ decrease = side->limbs[0] &1;
+ side->sign &= 254;
+
+ s1 = r->sign;
+ s2 = comparison->sign;
+ r->sign &= 254;
+ comparison->sign &= 254;
+
+ {
+ int cmp = _do_real_decimal_compare(r, comparison, ctx2);
+
+ if (PyErr_Occurred())
+ goto err;
+
+ if (cmp == 1 || decrease && cmp == 0) {
+ r->sign = s1;
+ comparison->sign = s2;
+ ctx2->prec += 1;
+
+ {
+ decimalobject *one;
+ decimalobject *tmp;
+ one = _NEW_decimalobj(1,0,0);
+ if (!one)
+ goto err;
+
+ one->limbs[0] = 1;
+ tmp = _do_decimal_add(side, one, ctx2);
+ Py_DECREF(one);
+
+ if (!tmp) 
+ goto err;
+
+ if (tmp->ob_size >= ctx2->prec) {
+ PyObject *ret;
+ PyObject *tup;
+ Py_DECREF(tmp);
+ ctx2->prec -= 1;
+ 
+ tup = handle_DivisionImpossible(self->ob_type, ctx2, NULL);
+
+ if (!tup)
+ goto err;
+ 
+ ret = PySequence_GetItem(tup, 1);
+ 
+ Py_DECREF(tup);
+ Py_DECREF(ctx2);
+ Py_XDECREF(flags);
+ Py_DECREF(side);
+ Py_DECREF(r);
+ Py_DECREF(comparison);
+
+ return ret;
+ }
+ Py_DECREF(tmp);
+ 
+ }
+ ctx2->prec -= 1;
+
+ if (self->sign == other->sign) {
+ decimalobject *tmp = _do_decimal_subtract(r, other, ctx2);
+ if (!tmp)
+ goto err;
+
+ Py_DECREF(r);
+ r = tmp;
+ tmp = 0;
+ }
+ else {
+ decimalobject *tmp = _do_decimal_add(r, other, ctx2);
+ if (!tmp)
+ goto err;
+ Py_DECREF(r);
+ r = tmp;
+ }
+ }
+ else {
+ r->sign = s1;
+ comparison->sign = s2;
+ }
+ }
+ 
+ Py_DECREF(comparison);
+ Py_DECREF(side);
+ Py_DECREF(flags);
+ Py_DECREF(ctx2);
+
+ {
+ decimalobject *fixed = _decimal_fix(r, ctx);
+ if (!fixed) {
+ Py_DECREF(r);
+ return NULL;
+ }
+ Py_DECREF(r);
+ return fixed;
+ } 
+ 
+err:
+ Py_DECREF(ctx2);
+ Py_XDECREF(flags);
+ Py_XDECREF(side);
+ Py_XDECREF(r);
+ Py_XDECREF(comparison);
+ 
+ return NULL;
 }
 DECIMAL_BINARY_FUNC(remainder_near)
 
@@ -3187,10 +3463,13 @@
 op2->limb_count + 1 : op1->limb_count;
 
 
+ /* if !shouldround, then we need log2(divider.int) + log10(op1.int)
+ * + some constant, to make sure, division is possible */
 if (!shouldround && !divmod)
- Py_RETURN_NONE; /* TODO */
-
- prec_needed = ctx->prec+1;
+ prec_needed = op2->ob_size * 4 + op1->ob_size + 5;
+ /* we need only ctx->prec + 1 and remainder */
+ else
+ prec_needed = ctx->prec+1;
 /* we need (prec_needed + LOG -1)/ LOG rounded up limbs, because
 * it may happen, that first limb is between 1 and 9, so we'll
 * get (significant_limbs-1) * LOG + 1 digits */
@@ -3271,6 +3550,7 @@
 else
 remainder_ret->exp = op1->exp;
 remainder_ret->ob_size = _limb_size_s(remainder_ret->limbs, remainder_ret->ob_size);
+ remainder_ret->limb_count = (remainder_ret->ob_size + LOG -1)/LOG;
 }
 
 old_size = result->ob_size;
@@ -5829,9 +6109,14 @@
 return NULL;
 }
 /* regard_flags allows a list of flags as the first arg */
- flags = PyTuple_GET_ITEM(args, 0);
- if (PyTuple_GET_SIZE(args) != 1 && !PySequence_Check(flags))
+ flags = PySequence_GetItem(args, 0);
+/* if (PyTuple_GET_SIZE(args) != 1 && !PySequence_Check(flags))*/
+/* flags = args; */
+ if (!PyTuple_Check(flags) && !PyList_Check(flags))
+ {
+ Py_DECREF(flags);
 flags = args;
+ }
 
 for (i = 0; i < PySequence_Size(flags); i++) {
 flag = PySequence_GetItem(flags, i);


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /