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

mateusz.rukowicz python-checkins at python.org
Sun Jun 11 01:33:54 CEST 2006


Author: mateusz.rukowicz
Date: Sun Jun 11 01:33:53 2006
New Revision: 46842

Modified:
   sandbox/trunk/decimal-c/_decimal.c
Log:
Multiplying and min works.


Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Sun Jun 11 01:33:53 2006
@@ -301,6 +301,59 @@
 	
 	return left_digits;
 }
+/* temporary solution, will be speeded up */
+static long
+_limb_multiply_core(long *first, long flimbs, long *second, long slimbs, long *out)
+{
+	long max_limbs = flimbs + slimbs;
+	long i,j;
+	
+	for(i = 0;i<max_limbs;i++)
+		out[i] = 0;
+
+	for(i = 0;i<flimbs;i++)
+		for(j = 0;j<slimbs;j++)
+		{
+			out[i+j] += first[i] * second[j];
+			if(out[i+j] >= BASE)
+			{
+				out[i+j+1] += out[i+j]/BASE;
+				out[i+j] %= BASE;
+			}
+		}
+
+	for(i = 0;i<max_limbs;i++)
+	{
+		if(out[i] >= BASE)
+		{
+			assert(i+1 < max_limbs);
+			out[i+1] += out[i] / BASE;
+			out[i] %= BASE;
+		}
+	}
+
+	while(!out[max_limbs -1] && max_limbs > 1) max_limbs --;
+	return max_limbs;
+}
+
+static long
+_limb_multiply(long *first, long fsize, long *second, long ssize, long *out)
+{
+	long used_limbs;
+	long flimbs, slimbs;
+	long digits_at_most;
+	flimbs = (fsize + LOG - 1)/LOG;
+	slimbs = (ssize + LOG - 1)/LOG;
+	used_limbs = _limb_multiply_core(first, flimbs, second, slimbs, out);
+	
+	digits_at_most = used_limbs * LOG;
+	if(!digits_at_most)
+		return 1;
+
+	while(_limb_get_digit(out, digits_at_most, 0) == 0 && digits_at_most >1) digits_at_most --;
+
+	return digits_at_most;
+}
 
 
 /* helpful macros ************************************************************/
@@ -1540,6 +1593,8 @@
     if (context_ignore_all_flags(ctx2) == NULL)
         return 0; /* error */
 
+	Py_XDECREF(ctx2);
+
     /* XXX: WTF? */
     ans = _do_decimal_subtract(self, other, ctx2);
     if (!ans) return 0;
@@ -1671,8 +1726,71 @@
 _do_decimal_min(decimalobject *self, decimalobject *other,
                 contextobject *ctx)
 {
-    /* XXX */
-    Py_RETURN_NONE;
+	decimalobject *ans;
+	long cmp;
+	decimalobject *ctx2;
+
+	if(ISSPECIAL(self) || ISSPECIAL(other))
+	{
+		decimalobject *nan;
+		int sn = GETNAN(self);
+		int so = GETNAN(other);
+
+		if(sn || so)
+		{
+			if(so == 1 && sn != 2)
+			{
+				Py_INCREF(self);
+				return self;
+			}
+			else if (sn == 1 && so != 2)
+			{
+				Py_INCREF(other);
+				return other;
+			}
+		}
+
+		if(_check_nans(self, other, ctx, &nan) != 0)
+				return nan;
+	}
+
+	ans = self;
+	if(!ctx)
+		ctx = getcontext();
+	if(!ctx)
+		return NULL;
+
+	ctx2 = getcontext();
+	if(!ctx2)
+		return NULL;
+	cmp = _do_real_decimal_compare(self,other,ctx2);
+
+	if(PyErr_Occurred())
+		return NULL;
+
+	if(!cmp)
+	{
+		if(self->sign != other->sign)
+		{
+			if(!self->sign)
+				ans = other;
+		}
+		else{	
+		if(self->exp > other->exp && !self->sign)
+			ans = other;
+		else if (self->exp < other->exp && self->sign)
+			ans = other;
+		}
+	}
+	else if(cmp == 1)
+		ans = other;
+
+	if(ctx->rounding_dec == ALWAYS_ROUND)
+		return _decimal_fix(ans, ctx);
+	
+	Py_INCREF(ans);
+	return ans;
+
 }
 DECIMAL_BINARY_FUNC(min)
 
@@ -1697,14 +1815,16 @@
         new = _NEW_decimalobj(1, dup->sign, 0);
         Py_DECREF(dup);
         if (!new) return NULL;
-        new->digits[0] = 0;
+		new->limbs[0] = 0;
         return new;
     }
     
     /* strip trailing 0s from dup */
-    while (dup->digits[dup->ob_size - 1] == 0) {
-        dup->ob_size--;
-        dup->exp++;
+//    while (dup->digits[dup->ob_size - 1] == 0) {
+	while(_limb_get_digit(dup->limbs, dup->ob_size, dup->ob_size -1) == 0){
+		_limb_cut_one_digit(dup->limbs,dup->ob_size);
+		dup->ob_size --;
+		dup->exp ++;
     }
     return dup;
 }
@@ -1776,7 +1896,7 @@
 static PyObject *
 _do_decimal_same_quantum(decimalobject *self, decimalobject *other)
 {
-    if (ISSPECIAL(self) && ISSPECIAL(other)) {
+    if (ISSPECIAL(self) || ISSPECIAL(other)) {
         if (GETNAN(self) || GETNAN(other)) {
             if (GETNAN(self) && GETNAN(other))
                 Py_RETURN_TRUE;
@@ -1870,6 +1990,8 @@
                                      &rounding, &ctx))
         return NULL;
     ENSURE_CONTEXT("to_integral", ctx);
+	if(rounding == -1)
+		rounding = ctx->rounding;
     if (!VALID_ROUND(rounding)) {
         PyErr_SetString(PyExc_ValueError, "invalid rounding value");
         return NULL;
@@ -2673,12 +2795,103 @@
 DECIMAL_SPECIAL_2FUNC(decimal_subtract)
 
 
+/* it's just so straightforward, wish adding was the same ;P */
 static decimalobject *
 _do_decimal_multiply(decimalobject *self, decimalobject *other,
                      contextobject *ctx)
 {
-    /* XXX */
-    Py_RETURN_NONE;
+	long resultsign;
+	long resultexp;
+	long shouldround;
+	long i;
+	long max_limbs;
+	long size;
+	decimalobject *ans;
+
+	resultsign = (self->sign&1) ^ (other->sign&1);
+	
+	if(ISSPECIAL(self) || ISSPECIAL(other))
+	{
+		decimalobject *nan;
+		if(_check_nans(self, other, ctx, &nan))
+			return nan;
+
+		if(ISINF(self))
+		{
+			if(decimal_nonzero(other))
+			{
+				ans = _NEW_decimalobj(1, resultsign ? SIGN_NEGINF : SIGN_POSINF, 0);
+				return ans;
+			}
+			return handle_InvalidOperation(self->ob_type, ctx, "(+-)INF * 0", NULL);
+		}
+
+		if(ISINF(other))
+		{
+			if(decimal_nonzero(self))
+			{
+				ans = _NEW_decimalobj(1, resultsign ? SIGN_NEGINF : SIGN_POSINF, 0);
+				return ans;
+			}
+			return handle_InvalidOperation(self->ob_type, ctx, "0 * (+-)INF", NULL);
+		}
+	}
+
+	resultexp = self->exp + other->exp;
+	shouldround = ctx->rounding_dec == ALWAYS_ROUND;
+
+	if(!decimal_nonzero(self) || !decimal_nonzero(other))
+	{
+		decimalobject *ret;
+		ans = _NEW_decimalobj(1, resultsign, resultexp);
+		if(!ans)
+			return NULL;
+
+		ans->limbs[0] = 0;
+		goto done;
+	}
+
+	if(self->ob_size == 1 && self->limbs[0] == 1)
+	{
+		ans = _NEW_decimalobj(other->ob_size, resultsign, resultexp);
+		if(!ans)
+			return NULL;
+		
+		for(i = 0; i<ans->limb_count;i++)
+			ans->limbs[i] = other->limbs[i];
+		goto done;
+	}
+
+	if(other->ob_size == 1 && other->limbs[0] == 1)
+	{
+		ans = _NEW_decimalobj(self->ob_size, resultsign, resultexp);
+		if(!ans)
+			return NULL;
+
+		for(i = 0; i<ans->limb_count; i++)
+			ans->limbs[i] = self->limbs[i];
+
+		goto done;
+	}
+
+	max_limbs = (self->ob_size + LOG -1)/ LOG + (other->ob_size + LOG -1)/LOG;
+	ans = _NEW_decimalobj(max_limbs * LOG, resultsign, resultexp);
+	if(!ans)
+		return NULL;
+
+	size = _limb_multiply(self->limbs, self->ob_size, other->limbs, other->ob_size, ans->limbs);
+
+	ans->ob_size = size;
+	
+
+done:
+	if(shouldround)
+	{
+		decimalobject *fixed = _decimal_fix(ans, ctx);
+		Py_DECREF(ans);
+		return fixed;
+	}
+	return ans;
 }
 DECIMAL_SPECIAL_2FUNC(decimal_multiply)
 
@@ -4333,12 +4546,13 @@
 
 
 static PyObject *
-context_to_integral(contextobject *self, PyObject *args)
+context_to_integral(contextobject *self, PyObject *args, PyObject *kwds)
 {
+	static char *kwlist[] = {"a", 0};
     PyObject *a, *res;
     decimalobject *dec_a = NULL;
 
-    if (!PyArg_ParseTuple(args, "O:to_integral", &a))
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:to_integral", kwlist, &a))
         return NULL;
 
     dec_a = (decimalobject *)_convert_to_decimal(
@@ -4714,7 +4928,7 @@
     {"to_eng_string",   (PyCFunction)context_to_eng_string,
      METH_O},
     {"to_integral",     (PyCFunction)context_to_integral,
-     METH_O},
+     METH_VARARGS | METH_KEYWORDS},
     {"to_sci_string",   (PyCFunction)context_to_sci_string,
      METH_VARARGS | METH_KEYWORDS},
     {"_ignore_all_flags", (PyCFunction)context_ignore_all_flags,


More information about the Python-checkins mailing list