[Python-checkins] r46111 - sandbox/trunk/decimal-c/_decimal.c
georg.brandl
python-checkins at python.org
Tue May 23 16:06:03 CEST 2006
Author: georg.brandl
Date: Tue May 23 16:06:03 2006
New Revision: 46111
Modified:
sandbox/trunk/decimal-c/_decimal.c
Log:
Finish rounding functions.
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c (original)
+++ sandbox/trunk/decimal-c/_decimal.c Tue May 23 16:06:03 2006
@@ -1,6 +1,8 @@
/* C implementation of the decimal module.
*
* Partly written in Iceland by Georg Brandl.
+ *
+ * vim:ts=4:sw=4:et:si
*/
#include "Python.h"
@@ -254,10 +256,53 @@
return 0;
}
+/* add 1eExponent. This is more efficient than add, used in rounding. */
static decimalobject *
-_decimal_increment(decimalobject *self, long prec, contextobject *ctx)
+_decimal_increment(decimalobject *self, int round, contextobject *ctx)
{
- /* XXX */
+ long spot;
+ decimalobject *new;
+
+ if (ISSPECIAL(self)) {
+ decimalobject *nan;
+ int res;
+ res = _check_nans(self, NULL, ctx, &nan);
+ if (res != 0) return nan;
+
+ /* I'm infinite, so incrementing makes no difference. */
+ return decimal_copy(self);
+ }
+
+ 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 */
+ for (spot = 0; spot < self->ob_size; spot++) {
+ if (self->digits[spot] != 9) {
+ spot = -1;
+ break;
+ }
+ }
+ if (spot != -1) {
+ /* no new digit needed */
+ new->ob_size--;
+ for (spot = 0; spot < self->ob_size; spot++)
+ new->digits[spot] = self->digits[spot];
+ } else {
+ for (spot = 0; spot < self->ob_size; spot++)
+ new->digits[spot+1] = self->digits[spot];
+ }
+
+ spot = new->ob_size-1;
+ new->digits[spot]++;
+ while (new->digits[spot] == 10) {
+ new->digits[spot] = 0;
+ spot--;
+ assert(spot >= 0);
+ new->digits[spot]++;
+ }
+ return new;
}
/* Round towards 0, that is, truncate digits. */
@@ -308,6 +353,7 @@
{
decimalobject *new;
long i;
+ assert(expdiff > 0);
if (!tmp) {
tmp = _new_decimalobj(prec, self->sign, self->exp - expdiff);
if (!tmp) return NULL;
@@ -334,6 +380,7 @@
{
long i;
decimalobject *tmp;
+ assert(expdiff > 0);
tmp = _new_decimalobj(prec, self->sign, self->exp - expdiff);
if (!tmp) return NULL;
for (i = 0; i < prec; i++)
@@ -352,6 +399,22 @@
static decimalobject *
_round_half_even(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
+ decimalobject *tmp;
+ long i;
+ 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) {
+ for (i = prec+1; i < self->ob_size; i++) {
+ if (self->digits[i] != 0)
+ return _do_round_half_up(self, prec, expdiff, ctx, tmp);
+ }
+ if ((self->digits[prec-1] & 1) == 0)
+ return tmp;
+ }
+ return _do_round_half_up(self, prec, expdiff, ctx, tmp);
}
/* Round 5 up (away from 0). */
@@ -361,15 +424,26 @@
return _do_round_half_up(self, prec, expdiff, ctx, NULL);
}
+/* Round up (regardless of sign) */
static decimalobject *
_round_floor(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
+ assert(self->sign <= 1);
+ if (self->sign > 0)
+ return _round_down(self, prec, expdiff, ctx);
+ else
+ return _round_up(self, prec, expdiff, ctx);
}
+/* Round down (regardless of sign) */
static decimalobject *
_round_ceiling(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
-
+ assert(self->sign <= 1);
+ if (self->sign > 0)
+ return _round_up(self, prec, expdiff, ctx);
+ else
+ return _round_down(self, prec, expdiff, ctx);
}
typedef decimalobject*(*round_func)(decimalobject *, long, long, contextobject *);
@@ -997,7 +1071,11 @@
static int
decimal_nonzero(decimalobject *self)
{
- /* XXX */
+ long i;
+ if (ISSPECIAL(self))
+ return 1;
+ for (i = 0; i < self->ob_size; i++)
+ if (i != 0) return 1;
return 0;
}
@@ -1080,7 +1158,6 @@
static decimalobject *
_decimal_fromliteralnan(char *str, long len, contextobject *ctx)
{
- /* XXX: what if buffer is longer than LONG_MAX? */
char literalsign = 0, sign = 0;
decimalobject *new;
long size = 0, i;
@@ -1170,11 +1247,11 @@
{
long ipos = 0; /* start of integral digits */
long dpos = -1; /* decimal point location */
- long dend = len; /* end of integral/decimal digits */
+ long dend = len; /* end of integral/decimal digits (last digit+1) */
char *p = str;
char sign = 0;
decimalobject *new;
- long exp = 0, i = 0, ndigits;
+ long exp = 0, i, ndigits;
/* optional sign */
if (*p == '+') {
@@ -1206,7 +1283,7 @@
if (ipos == dpos && dpos == dend-1)
/* no digits at all */
goto err;
- goto finish;
+ goto calculate;
} else if (*p == '-' || *p == '+') {
++p;
}
@@ -1217,20 +1294,31 @@
goto err;
} while (*++p);
-finish:
+calculate:
if (dend < len)
- /* XXX: which function to convert a string to ssize_t? */
exp = atol(str + dend + 1);
if (dpos >= 0)
/* specified fractional digits, reduce exp */
exp -= dend - dpos - 1;
+ /* If it's not a zero, strip leading 0s */
+ for (p = str+ipos; p-str < dend; ++p) {
+ if (*p != '0' && *p != '.') {
+ /* first nonzero digit */
+ ipos = (p-str);
+ goto finish;
+ }
+ }
+ /* it's a zero */
+ dend = (dpos == ipos ? ipos+2 : ipos+1);
+
+finish:
ndigits = dend - ipos - (dpos<0 ? 0 : 1);
new = _new_decimalobj(ndigits, sign, exp);
if (!new)
return NULL;
- /* XXX: leading zeroes are not stripped */
+ i = 0;
for (p = str+ipos; p-str < dend; ++p) {
if (*p == '.') continue;
new->digits[i] = *p - 48;
@@ -1574,7 +1662,7 @@
if (val < 0 || val > 9) {
PyObject_FREE(arr);
PyErr_SetString(PyExc_TypeError, "_int digits must be 0-9");
- return NULL;
+ return -1;
}
arr[i] = val;
}
More information about the Python-checkins
mailing list