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

mateusz.rukowicz python-checkins at python.org
Thu Jun 8 01:48:39 CEST 2006


Author: mateusz.rukowicz
Date: Thu Jun  8 01:48:38 2006
New Revision: 46733

Modified:
   sandbox/trunk/decimal-c/_decimal.c
Log:
Some bugs fixed, draft of new integer representation, from now old will be deleted.


Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Thu Jun  8 01:48:38 2006
@@ -67,6 +67,106 @@
 #include "modsupport.h"
 #include "structmember.h"
 #include "decimal.h"
+#include <stdio.h>
+
+/* integer arithmetic */
+
+/* takes new_digits from self[], starting from start_at digit, *digits* not limbs */
+/* returns digit after that we returned (useful for rounding) */
+static long			
+_limb_first_n_digits(long *self, long ndigits, long start_at, long *new, long new_digits)	
+{
+		long start_pos = ndigits - (start_at + new_digits);	/* where we start counting from left */
+		long pos = 0;					/* we are here */
+		long self_limb = 0;				/* we start at first digit of first limb */
+		long self_mult = 1;
+		long new_limb = 0;
+		long new_mult = 1;
+		long last_digit = 0;				/* digit from start_pos -1 */
+		long i;
+		
+		for(i = 0;i<new_digits;i+= LOG)
+				new[i/LOG] = 0;
+
+		while(pos < start_pos)			/* we need to set pos to 0 */
+		{
+			if(pos == start_pos - 1)		/* that's our last_digit */
+			{
+				long tmp = self[self_limb];
+				tmp %= self_mult * 10;
+				tmp /= self_mult;
+				last_digit = tmp;
+			}
+					
+			self_mult *= 10;
+			if(self_mult == BASE)
+			{
+				self_limb ++;
+				self_mult = 1;
+			}	
+			pos ++;
+		}
+
+		long diff = start_pos;
+		while (diff < 0)		/* put 0s to new */
+		{
+			new[new_limb] = 0;
+			new_mult *= 10;
+			if(new_mult == BASE)
+			{
+					new_limb ++;
+					new_mult = 1;
+			}
+			diff ++;
+		}
+
+		/* now we will just copy from self to digit */
+		long actual_limb = self[self_limb];
+		actual_limb /= self_mult;
+		
+		/* while don't go out of self and new */
+		while(pos < ndigits && pos - start_pos < new_digits)
+		{
+			if(self_mult == 1)
+					actual_limb = self[self_limb];
+				
+			long x = actual_limb % 10;
+			new[new_limb] += x * new_mult;
+			new_mult *= 10;
+			if(new_mult == BASE)
+			{
+					new_limb ++;
+					new_mult = 1;
+			}
+			actual_limb /= 10;
+			self_mult *= 10;
+
+			if(self_mult == BASE)
+			{
+					self_mult = 1;
+					self_limb ++;
+			}
+			pos ++;
+		}
+
+		/* rest is 0 */
+
+		return last_digit;
+}
+
+static void
+_limb_cut_one_digit(long *self, long ndigits)
+{
+	long limb_count = ndigits/LOG + ((ndigits%LOG) != 0);
+	long i;
+
+	self[0] /= 10;
+	for(i = 1;i<limb_count;i++)
+	{
+			self[i-1] += (self[i]%10) * (BASE/10);
+			self[i] /= 10;
+	}
+}
 
 /* helpful macros ************************************************************/
 
@@ -421,6 +521,9 @@
 {
     decimalobject *new;
     char *arr = NULL;
+	long *arr2 = NULL;
+	long limb_c = ndigits / LOG;
+	limb_c += (ndigits % LOG) > 0;	
     
     if (ndigits > LONG_MAX) {
         PyErr_NoMemory();
@@ -432,6 +535,13 @@
         PyErr_NoMemory();
         goto err;
     }
+
+	arr2 = PyObject_MALLOC(limb_c * sizeof(long));
+
+	if(!arr2){
+		PyErr_NoMemory();
+		goto err;
+	}
     new = (decimalobject *)type->tp_alloc(type, 0);
     if (new == NULL)
         goto err;
@@ -439,10 +549,13 @@
     new->exp = exp;
     new->ob_size = ndigits;
     new->digits = arr;
+	new->limb_count = limb_c;
+	new->limbs = arr2;
     return new;
         
   err:
     if (arr) PyObject_FREE(arr);
+	if (arr2) PyObject_FREE(arr2);
     return NULL;
 }
 
@@ -499,7 +612,7 @@
 static decimalobject *
 _decimal_increment(decimalobject *self, int round, contextobject *ctx)
 {
-    long spot;
+    long spot, i;
     decimalobject *new;
 
     if (ISSPECIAL(self)) {
@@ -514,6 +627,7 @@
 
     new = _NEW_decimalobj(self->ob_size + 1,  /* we possibly need a new digit */
                           self->sign, self->exp);
+
     if (!new) return NULL;
     
     /* determine if we need a new digit */
@@ -523,7 +637,7 @@
             break;
         }
     }
-    if (spot != -1) {
+    if (spot == -1) {
         /* no new digit needed */
         new->ob_size--;
         for (spot = 0; spot < self->ob_size; spot++)
@@ -531,6 +645,7 @@
     } else {
         for (spot = 0; spot < self->ob_size; spot++)
             new->digits[spot+1] = self->digits[spot];
+		new->digits[0] = 0;
     }
 
     spot = new->ob_size-1;
@@ -541,6 +656,21 @@
         assert(spot >= 0);
         new->digits[spot]++;
     }
+
+	for(i=0;i<self->limb_count;i++)
+			new->limbs[i] = self->limbs[i];
+	if(self->limb_count != new->limb_count)
+		new->limbs[new->limb_count - 1] = 0;	/* we have new limb */
+
+	new->limbs[0] ++;
+	i = 0;
+	while(new->limbs[i] >= BASE)
+	{
+			new->limbs[i] -= BASE;
+			new->limbs[i+1] ++;
+			i++;
+			assert(i+1 < new->limb_count);
+	}
     return new;
 }
 
@@ -553,19 +683,23 @@
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
         new->digits[i] = self->digits[i];
+
+	_limb_first_n_digits(self->limbs, self->ob_size, 0, new->limbs, prec);
     return new;
 }
 
 /* Round away from 0. */
 static decimalobject *
-_round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
-{
+_round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)			
+{			/* XXX temporary solution with limbs */
     long i;
     decimalobject *new = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     decimalobject *new2 = NULL;
     if (!new) return NULL;
     for (i = 0; i < prec; i++)
         new->digits[i] = self->digits[i];
+	_limb_first_n_digits(self->limbs, self->ob_size, 0, new->limbs, prec);
+	
     if (!new) return NULL;
     for (i = prec; i < self->ob_size; i++)
         if (self->digits[i] > 0) {
@@ -574,12 +708,13 @@
             if (!new2)
                 return NULL;
             if (new2->ob_size > prec) {
+				_limb_cut_one_digit(new2->limbs,new2->ob_size);				
                 new2->ob_size--;
                 new2->exp++;
             }
             return new2;
         }
-    return new2;
+    return new;	
 }
 
 /* Actually round half up. Returns a new reference, either on tmp
@@ -598,6 +733,7 @@
         Py_DECREF(tmp);
         if (!new) return NULL;
         if (new->ob_size > prec) {
+			_limb_cut_one_digit(new->limbs,new->ob_size);
             new->ob_size--;
             new->exp++;
         }
@@ -611,14 +747,18 @@
 static decimalobject *
 _round_half_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
-    long i;
+    long i, last;
     decimalobject *tmp;
     assert(expdiff > 0);
     tmp = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!tmp) return NULL;
     for (i = 0; i < prec; i++)
         tmp->digits[i] = self->digits[i];
-    if (self->digits[prec] == 5) {
+
+	last = _limb_first_n_digits(self->limbs, self->ob_size, 0, tmp->limbs, prec);
+	last = self->digits[prec];
+	assert(self->digits[prec] == last);
+    if (last == 5) {
         for (i = prec+1; i < self->ob_size; i++) {
             if (self->digits[i] != 0)
                 return _do_round_half_up(self, prec, expdiff, ctx, tmp);
@@ -634,13 +774,16 @@
 _round_half_even(decimalobject *self, long prec, long expdiff, contextobject *ctx)
 {
     decimalobject *tmp;
-    long i;
+    long i, last;
     assert(expdiff > 0);
     tmp = _NEW_decimalobj(prec, self->sign, self->exp - expdiff);
     if (!tmp) return NULL;
     for (i = 0; i < prec; i++)
         tmp->digits[i] = self->digits[i];
-    if (self->digits[prec] == 5) {
+	last = _limb_first_n_digits(self->limbs, self->ob_size, 0, tmp->limbs, prec);
+	last = self->digits[prec];
+	assert(last == self->digits[prec]);
+    if (last == 5) {
         for (i = prec+1; i < self->ob_size; i++) {
             if (self->digits[i] != 0)
                 return _do_round_half_up(self, prec, expdiff, ctx, tmp);
@@ -661,6 +804,7 @@
     if (!tmp) return NULL;
     for (i = 0; i < prec; i++)
         tmp->digits[i] = self->digits[i];
+	_limb_first_n_digits(self->limbs, self->ob_size, 0, tmp->limbs, prec);
     return _do_round_half_up(self, prec, expdiff, ctx, tmp);
 }
 
@@ -1517,6 +1661,8 @@
         return NULL;
     for (i = 0; i < self->ob_size; i++)
         new->digits[i] = self->digits[i];
+	for (i = 0;i < new->limb_count;i++)
+		new->limbs[i] = self->limbs[i];
     return new;
 }
 
@@ -2382,6 +2528,7 @@
 decimal_dealloc(decimalobject *d)
 {
     PyObject_FREE(d->digits);
+	PyObject_FREE(d->limbs);
     d->ob_type->tp_free(d);
 }
 
@@ -2471,6 +2618,7 @@
         if (!new)
             return NULL;
         new->digits[0] = 0;
+		new->limbs[0] = 0;
         return new;
     }
     return NULL;
@@ -2558,6 +2706,26 @@
         new->digits[i] = *p - 48;
         i++;
     }
+	
+	long mult = 1;
+	long limb = 0;
+	for(i=0;i<new -> limb_count; i++)
+			new->limbs[i] = 0;
+	
+	for(i = dend - 1; i>= ipos; i--)
+	{
+			if(str[i] == '.') continue;
+			assert(limb < new->limb_count);
+			new->limbs[limb] += mult * (str[i] - '0');
+
+			mult *= 10;
+			if(mult == BASE)
+			{
+					mult = 1;
+					limb ++;
+			}
+	}
+	
     return new;
 
   err:
@@ -2600,7 +2768,8 @@
     if (value == 0) {
         new = _new_decimalobj(type, 1, 0, 0);
         if (!new) return NULL;
-        new->digits[0] = 0;
+        new->digits[0] = 0;	
+		new->limbs[0] = 0;
         return (PyObject *)new;
     } else if (value < 0) {
         value = -value;
@@ -2613,6 +2782,8 @@
         v /= 10;
     }
     
+	v = value;
+	
     new = _new_decimalobj(type, ndigits, (neg ? SIGN_NEG : SIGN_POS), 0);
     if (!new) return NULL;
     while (value) {
@@ -2620,6 +2791,13 @@
         value /= 10;
         i++;
     }
+
+	for(i=0; i < new->limb_count; i++)
+	{
+			new->limbs[i] = v % BASE;
+			v /= BASE;
+	}
+	
     return (PyObject *)new;
 }
 
@@ -2667,28 +2845,67 @@
     new = _new_decimalobj(type, PyTuple_GET_SIZE(digtup), sign, exp);
     for (i = 0; i < new->ob_size; i++) {
         item = PyTuple_GET_ITEM(digtup, i);
+		long x;
         if (PyInt_Check(item)) {
-            long x = PyInt_AsLong(item);
-            if (x < 0 || x > 9) {
-                PyErr_Format(PyExc_ValueError, "Invalid digit: %ld", x);
-                goto err;
-            }
-            new->digits[i] = (signed char)x;
+            x = PyInt_AsLong(item);
         } else if (PyLong_Check(item)) {
-            long x = PyLong_AsLong(item);
+            x = PyLong_AsLong(item);
             if (x == -1 && PyErr_Occurred())
                 goto err;
-            if (x < 0 || x > 9) {
-                PyErr_Format(PyExc_ValueError, "Invalid digit: %ld", x);
-                return err;
-            }
-            new->digits[i] = (signed char)x;
         } else {
             PyErr_SetString(PyExc_ValueError, "The second value in the tuple "
                             "must be composed of non  negative integer elements.");
-            return err;
+            goto err;
         }
-    }
+		
+		if(x < 0 || x > 9)
+		{
+				PyErr_Format(PyExc_ValueError, "Invalid digit: %ld", x);
+				goto err;
+		}
+
+		new->digits[i] = x;
+    }			//this loop will go out soon XXX
+	
+	for(i = 0;i < new->limb_count;i++)
+			new->limbs[i] = 0;
+	
+	long mult = 1;
+	long limb = 0;
+	new->limbs[0] = 0;
+	for(i = new->ob_size-1; i>=0; i--)	//limb[0] keeps least significant limb
+	{
+		item = PyTuple_GET_ITEM(digtup, i);
+		long x;
+		if(PyInt_AsLong(item))
+			x = PyInt_AsLong(item);
+		else if (PyLong_Check(item)) {
+			x = PyLong_AsLong(item);
+			if(x == -1 && PyErr_Occurred())
+					goto err;
+		}
+		else {
+			PyErr_SetString(PyExc_ValueError, "The second value in the tuple "
+							"must be composed of non negative integer elements.");
+			goto err;
+		}
+
+		if(x < 0 || x > 9)
+		{
+				PyErr_Format(PyExc_ValueError, "Invalid digit: %ld", x);
+				goto err;
+		}
+		
+		assert(limb < new->limb_count);
+		new->limbs[limb] += mult * x;
+		mult *= 10;
+		
+		if(mult == BASE)	/* we already used LOG digits of one limb */
+		{
+				mult = 1;
+				limb ++;
+		}
+	}
 
     Py_DECREF(digtup);
     Py_DECREF(tup);
@@ -2753,6 +2970,7 @@
         decimalobject *new = _new_decimalobj(type, 1, 0, 0);
         if (!new) return NULL;
         new->digits[0] = 0;
+		new->limbs[0] = 0;
         return (PyObject *)new;
     }
 
@@ -2931,6 +3149,17 @@
     return 0;
 }
 
+static PyObject *
+_decimal_get_limbs(decimalobject *self)
+{
+	PyObject *tup;
+	long i;
+	tup = PyTuple_New(self->limb_count);
+	if(!tup) return NULL;
+	for(i = 0; i< self->limb_count; i++)
+		PyTuple_SET_ITEM(tup, i, PyInt_FromLong(self->limbs[i]));
+	return tup;
+}
 
 static PyObject *
 _decimal_is_special(decimalobject *self)
@@ -2943,6 +3172,7 @@
 
 
 static PyGetSetDef _decimal_getset[] = {
+	{"_limbs", (getter)_decimal_get_limbs, 0},
     {"_int", (getter)_decimal_get_int, (setter)_decimal_set_int},
     {"_is_special", (getter)_decimal_is_special, 0},
     {NULL}


More information about the Python-checkins mailing list