[Python-checkins] r46105 - sandbox/trunk/decimal-c/_decimal.c sandbox/trunk/decimal-c/decimal.h sandbox/trunk/decimal-c/decimal.py
georg.brandl
python-checkins at python.org
Tue May 23 14:07:27 CEST 2006
Author: georg.brandl
Date: Tue May 23 14:07:26 2006
New Revision: 46105
Modified:
sandbox/trunk/decimal-c/_decimal.c
sandbox/trunk/decimal-c/decimal.h
sandbox/trunk/decimal-c/decimal.py
Log:
Don't use the PyObject_VAR machinery any longer.
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c (original)
+++ sandbox/trunk/decimal-c/_decimal.c Tue May 23 14:07:26 2006
@@ -181,18 +181,26 @@
static decimalobject *
-_new_decimalobj(Py_ssize_t ndigits, char sign, long exp)
+_new_decimalobj(long ndigits, char sign, long exp)
{
decimalobject *new;
- if (ndigits > PY_SSIZE_T_MAX) {
+ char *arr;
+ if (ndigits > LONG_MAX) {
PyErr_NoMemory();
return NULL;
}
- new = (decimalobject *)PyObject_NEW_VAR(decimalobject, &PyDecimal_DecimalType, ndigits);
+ arr = PyObject_MALLOC(ndigits);
+ if (!arr) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ new = (decimalobject *)PyObject_NEW(decimalobject, &PyDecimal_DecimalType);
if (new == NULL)
return NULL;
new->sign = sign;
new->exp = exp;
+ new->ob_size = ndigits;
+ new->digits = arr;
return new;
}
@@ -249,13 +257,14 @@
static decimalobject *
_decimal_increment(decimalobject *self, long prec, contextobject *ctx)
{
+ /* XXX */
}
/* Round towards 0, that is, truncate digits. */
static decimalobject *
_round_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
- Py_ssize_t i;
+ long i;
decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
if (!new) return NULL;
for (i = 0; i < prec; i++)
@@ -267,9 +276,9 @@
static decimalobject *
_round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
- Py_ssize_t i;
+ long i;
decimalobject *new = _new_decimalobj(prec, self->sign, self->exp - expdiff);
- decimalobject *new2;
+ decimalobject *new2 = NULL;
if (!new) return NULL;
for (i = 0; i < prec; i++)
new->digits[i] = self->digits[i];
@@ -290,27 +299,54 @@
}
/* Actually round half up. Returns a new reference, either on tmp
- * or a new decimalobject. */
+ * or a new decimalobject, and steals one reference on tmp in turn,
+ * if it was passed in so that you can just do
+ * return _do_round_half_up(...) */
static decimalobject *
_do_round_half_up(decimalobject *self, long prec, long expdiff,
contextobject *ctx, decimalobject *tmp)
{
- Py_ssize_t i;
+ decimalobject *new;
+ long i;
if (!tmp) {
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->ob_size > prec && self->digits[prec] >= 5) {*/
-
+ if (self->ob_size > prec && self->digits[prec] >= 5) {
+ new = _decimal_increment(tmp, 1, ctx);
+ Py_DECREF(tmp);
+ if (!new) return NULL;
+ if (new->ob_size > prec) {
+ new->ob_size--;
+ new->exp++;
+ }
+ return new;
+ } else {
+ return tmp;
+ }
}
/* Round 5 down. */
static decimalobject *
_round_half_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
{
-
+ long i;
+ decimalobject *tmp;
+ 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);
+ }
+ /* self ends in 5000...., so tmp is okay */
+ return tmp;
+ }
+ return _do_round_half_up(self, prec, expdiff, ctx, tmp);
}
static decimalobject *
@@ -348,7 +384,7 @@
{
decimalobject *new, *new2 = NULL, *errres;
contextobject *ctx2 = NULL;
- Py_ssize_t i, expdiff;
+ long i, expdiff;
round_func rnd_func;
if (ISSPECIAL(self)) {
@@ -482,10 +518,10 @@
_decimal_rescale(decimalobject *self, long exp, contextobject *ctx,
int rounding, int watchexp)
{
- decimalobject *ans = NULL, *tmp, *tmp2;
+ decimalobject *ans = NULL, *tmp;
int ret;
long diff, adj;
- Py_ssize_t digits, i;
+ long digits, i;
if (ISSPECIAL(self)) {
if (ISINF(self))
@@ -833,7 +869,7 @@
decimal_copy(decimalobject *self)
{
decimalobject *new;
- Py_ssize_t size = self->ob_size;
+ long size = self->ob_size;
new = _new_decimalobj(size, self->sign, self->exp);
if (!new)
@@ -857,7 +893,7 @@
decimal_as_tuple(decimalobject *self)
{
PyObject *digits, *res, *d;
- Py_ssize_t i;
+ long i;
digits = PyTuple_New(self->ob_size);
if (!digits)
@@ -1019,7 +1055,7 @@
int
_decimal_isint(decimalobject *d)
{
- Py_ssize_t i;
+ long i;
if (d->exp >= 0)
/* if the exponent is positive, there's no
@@ -1035,17 +1071,19 @@
}
static void
-decimal_dealloc(PyObject *d)
+decimal_dealloc(decimalobject *d)
{
+ PyObject_FREE(d->digits);
d->ob_type->tp_free(d);
}
static decimalobject *
-_decimal_fromliteralnan(char *str, Py_ssize_t len, contextobject *ctx)
+_decimal_fromliteralnan(char *str, long len, contextobject *ctx)
{
+ /* XXX: what if buffer is longer than LONG_MAX? */
char literalsign = 0, sign = 0;
decimalobject *new;
- Py_ssize_t size = 0, i;
+ long size = 0, i;
char *start = NULL, *p;
if (len < 3)
@@ -1128,16 +1166,15 @@
}
static decimalobject *
-_decimal_fromliteral(char *str, Py_ssize_t len, contextobject *ctx)
+_decimal_fromliteral(char *str, long len, contextobject *ctx)
{
- Py_ssize_t ipos = 0; /* start of integral digits */
- Py_ssize_t dpos = -1; /* decimal point location */
- Py_ssize_t dend = len; /* end of integral/decimal digits */
+ long ipos = 0; /* start of integral digits */
+ long dpos = -1; /* decimal point location */
+ long dend = len; /* end of integral/decimal digits */
char *p = str;
char sign = 0;
decimalobject *new;
- long exp = 0;
- Py_ssize_t i = 0, ndigits;
+ long exp = 0, i = 0, ndigits;
/* optional sign */
if (*p == '+') {
@@ -1207,7 +1244,7 @@
}
PyObject *
-PyDecimal_FromString(char *buffer, Py_ssize_t buf_len, contextobject *ctx)
+PyDecimal_FromString(char *buffer, long buf_len, contextobject *ctx)
{
decimalobject *new;
@@ -1262,8 +1299,7 @@
decimalobject *new = NULL;
PyObject *tup, *digits, *digtup = NULL, *item;
int sign;
- long exp;
- Py_ssize_t i;
+ long i, exp;
if (PyTuple_Check(seq)) {
tup = seq;
@@ -1387,6 +1423,11 @@
/* try buffer interface (e.g. strings and unicode) */
if (PyObject_AsCharBuffer(value, (const char **)&buffer, &buf_len) == 0) {
+ if (buf_len > LONG_MAX) {
+ PyErr_NoMemory();
+ if (decref_value) { Py_DECREF(value); }
+ return NULL;
+ }
PyObject *res = (PyObject *)PyDecimal_FromString(buffer, buf_len, ctx);
if (decref_value) {
Py_DECREF(value);
@@ -1417,7 +1458,7 @@
/* XXX: quick hack */
char buf[1000];
char dig[2];
- Py_ssize_t i;
+ long i;
dig[1] = 0;
PyOS_snprintf(buf, 1000, "sign=%i, exp=%ld, digits=", d->sign, d->exp);
@@ -1487,6 +1528,40 @@
return hash;
}
+/* XXX: just for debugging? */
+static PyMemberDef _decimal_members[] = {
+ {"_sign", T_INT, offsetof(decimalobject, sign), 0},
+ {"_exp", T_LONG, offsetof(decimalobject, exp), 0},
+ {NULL}
+};
+
+static PyObject *
+_decimal_get_int(decimalobject *self)
+{
+ PyObject *tup;
+ long i;
+ tup = PyTuple_New(self->ob_size);
+ if (!tup) return NULL;
+ for (i = 0; i < self->ob_size; i++)
+ PyTuple_SET_ITEM(tup, i, PyInt_FromLong(self->digits[i]));
+ return tup;
+}
+
+static PyObject *
+_decimal_is_special(decimalobject *self)
+{
+ if (ISSPECIAL(self))
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyGetSetDef _decimal_getset[] = {
+ {"_int", (getter)_decimal_get_int, 0},
+ {"_is_special", (getter)_decimal_is_special, 0},
+ {NULL}
+};
+
static PyTypeObject PyDecimal_DecimalType = {
PyObject_HEAD_INIT(NULL)
@@ -1519,8 +1594,8 @@
0, /* tp_iter */
0, /* tp_iternext */
decimal_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
+ _decimal_members, /* tp_members */
+ _decimal_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
Modified: sandbox/trunk/decimal-c/decimal.h
==============================================================================
--- sandbox/trunk/decimal-c/decimal.h (original)
+++ sandbox/trunk/decimal-c/decimal.h Tue May 23 14:07:26 2006
@@ -10,10 +10,11 @@
/* decimalobject struct ******************************************************/
typedef struct {
- PyObject_VAR_HEAD
+ PyObject_HEAD
+ long ob_size; /* number of digits */
unsigned int sign; /* see sign contstants above */
long exp;
- signed char digits[1]; /* digits are stored as the actual numbers 0-9 */
+ signed char *digits; /* digits are stored as the actual numbers 0-9 */
} PyDecimalObject;
static PyTypeObject PyDecimal_DecimalType;
Modified: sandbox/trunk/decimal-c/decimal.py
==============================================================================
--- sandbox/trunk/decimal-c/decimal.py (original)
+++ sandbox/trunk/decimal-c/decimal.py Tue May 23 14:07:26 2006
@@ -466,114 +466,117 @@
class Decimal(_decimal.Decimal):
"""Floating point class for decimal arithmetic."""
- __slots__ = ('_exp','_int','_sign', '_is_special')
# Generally, the value of the Decimal instance is given by
# (-1)**_sign * _int * 10**_exp
# Special values are signified by _is_special == True
- # We're immutable, so use __new__ not __init__
- def __new__(cls, value="0", context=None):
- """Create a decimal point instance.
-
- >>> Decimal('3.14') # string input
- Decimal("3.14")
- >>> Decimal((0, (3, 1, 4), -2)) # tuple input (sign, digit_tuple, exponent)
- Decimal("3.14")
- >>> Decimal(314) # int or long
- Decimal("314")
- >>> Decimal(Decimal(314)) # another decimal instance
- Decimal("314")
- """
-
- self = object.__new__(cls)
- self._is_special = False
-
- # From an internal working value
- if isinstance(value, _WorkRep):
- self._sign = value.sign
- self._int = tuple(map(int, str(value.int)))
- self._exp = int(value.exp)
- return self
-
- # From another decimal
- if isinstance(value, Decimal):
- self._exp = value._exp
- self._sign = value._sign
- self._int = value._int
- self._is_special = value._is_special
- return self
-
- # From an integer
- if isinstance(value, (int,long)):
- if value >= 0:
- self._sign = 0
- else:
- self._sign = 1
- self._exp = 0
- self._int = tuple(map(int, str(abs(value))))
- return self
-
- # tuple/list conversion (possibly from as_tuple())
- if isinstance(value, (list,tuple)):
- if len(value) != 3:
- raise ValueError, 'Invalid arguments'
- if value[0] not in (0,1):
- raise ValueError, 'Invalid sign'
- for digit in value[1]:
- if not isinstance(digit, (int,long)) or digit < 0:
- raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
-
- self._sign = value[0]
- self._int = tuple(value[1])
- if value[2] in ('F','n','N'):
- self._exp = value[2]
- self._is_special = True
- else:
- self._exp = int(value[2])
- return self
-
- if isinstance(value, float):
- raise TypeError("Cannot convert float to Decimal. " +
- "First convert the float to a string")
-
- # Other argument types may require the context during interpretation
- if context is None:
- context = getcontext()
-
- # From a string
- # REs insist on real strings, so we can too.
- if isinstance(value, basestring):
- if _isinfinity(value):
- self._exp = 'F'
- self._int = (0,)
- self._is_special = True
- if _isinfinity(value) == 1:
- self._sign = 0
- else:
- self._sign = 1
- return self
- if _isnan(value):
- sig, sign, diag = _isnan(value)
- self._is_special = True
- if len(diag) > context.prec: #Diagnostic info too long
- self._sign, self._int, self._exp = \
- context._raise_error(ConversionSyntax)
- return self
- if sig == 1:
- self._exp = 'n' #qNaN
- else: #sig == 2
- self._exp = 'N' #sNaN
- self._sign = sign
- self._int = tuple(map(int, diag)) #Diagnostic info
- return self
- try:
- self._sign, self._int, self._exp = _string2exact(value)
- except ValueError:
- self._is_special = True
- self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
- return self
-
- raise TypeError("Cannot convert %r to Decimal" % value)
+ @property
+ def _is_special(self):
+ return (self._sign > 1)
+
+# # We're immutable, so use __new__ not __init__
+# def __new__(cls, value="0", context=None):
+# """Create a decimal point instance.
+#
+# >>> Decimal('3.14') # string input
+# Decimal("3.14")
+# >>> Decimal((0, (3, 1, 4), -2)) # tuple input (sign, digit_tuple, exponent)
+# Decimal("3.14")
+# >>> Decimal(314) # int or long
+# Decimal("314")
+# >>> Decimal(Decimal(314)) # another decimal instance
+# Decimal("314")
+# """
+#
+# self = _decimal.Decimal.__new__(cls)
+# self._is_special = False
+#
+# # From an internal working value
+# if isinstance(value, _WorkRep):
+# self._sign = value.sign
+# self._int = tuple(map(int, str(value.int)))
+# self._exp = int(value.exp)
+# return self
+#
+# # From another decimal
+# if isinstance(value, Decimal):
+# self._exp = value._exp
+# self._sign = value._sign
+# self._int = value._int
+# self._is_special = value._is_special
+# return self
+#
+# # From an integer
+# if isinstance(value, (int,long)):
+# if value >= 0:
+# self._sign = 0
+# else:
+# self._sign = 1
+# self._exp = 0
+# self._int = tuple(map(int, str(abs(value))))
+# return self
+#
+# # tuple/list conversion (possibly from as_tuple())
+# if isinstance(value, (list,tuple)):
+# if len(value) != 3:
+# raise ValueError, 'Invalid arguments'
+# if value[0] not in (0,1):
+# raise ValueError, 'Invalid sign'
+# for digit in value[1]:
+# if not isinstance(digit, (int,long)) or digit < 0:
+# raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
+#
+# self._sign = value[0]
+# self._int = tuple(value[1])
+# if value[2] in ('F','n','N'):
+# self._exp = value[2]
+# self._is_special = True
+# else:
+# self._exp = int(value[2])
+# return self
+#
+# if isinstance(value, float):
+# raise TypeError("Cannot convert float to Decimal. " +
+# "First convert the float to a string")
+#
+# # Other argument types may require the context during interpretation
+# if context is None:
+# context = getcontext()
+#
+# # From a string
+# # REs insist on real strings, so we can too.
+# if isinstance(value, basestring):
+# if _isinfinity(value):
+# self._exp = 'F'
+# self._int = (0,)
+# self._is_special = True
+# if _isinfinity(value) == 1:
+# self._sign = 0
+# else:
+# self._sign = 1
+# return self
+# if _isnan(value):
+# sig, sign, diag = _isnan(value)
+# self._is_special = True
+# if len(diag) > context.prec: #Diagnostic info too long
+# self._sign, self._int, self._exp = \
+# context._raise_error(ConversionSyntax)
+# return self
+# if sig == 1:
+# self._exp = 'n' #qNaN
+# else: #sig == 2
+# self._exp = 'N' #sNaN
+# self._sign = sign
+# self._int = tuple(map(int, diag)) #Diagnostic info
+# return self
+# try:
+# self._sign, self._int, self._exp = _string2exact(value)
+# except ValueError:
+# self._is_special = True
+# self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
+# return self
+#
+# raise TypeError("Cannot convert %r to Decimal" % value)
def _isnan(self):
"""Returns whether the number is not actually one.
More information about the Python-checkins
mailing list