[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