[Python-checkins] r75559 - in sandbox/trunk/decimal/decimal_in_c: deccoeff.c decimal.py
mark.dickinson
python-checkins at python.org
Tue Oct 20 13:33:42 CEST 2009
Author: mark.dickinson
Date: Tue Oct 20 13:33:41 2009
New Revision: 75559
Log:
Remove _Decimal type from deccoeff extension
Modified:
sandbox/trunk/decimal/decimal_in_c/deccoeff.c
sandbox/trunk/decimal/decimal_in_c/decimal.py
Modified: sandbox/trunk/decimal/decimal_in_c/deccoeff.c
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/deccoeff.c (original)
+++ sandbox/trunk/decimal/decimal_in_c/deccoeff.c Tue Oct 20 13:33:41 2009
@@ -1,17 +1,12 @@
/*
- * 'deccoeff' is a Python extension module that exports two classes:
- * _Decimal and Deccoeff.
- *
- * deccoeff._Decimal is a skeletal base class for the decimal.Decimal class.
- * As time goes on, the aim is to move more and more code from the Python
- * decimal.py file to the _Decimal class, and eventually rename _Decimal
- * to Decimal.
+ * 'deccoeff' is a Python extension module that exports two a single class,
+ * 'Deccoeff'.
*
* deccoeff.Deccoeff is a class implementing arbitrary-precision unsigned
* integer arithmetic in a decimal base. In addition to the usual arithmetic
* operations, Deccoeff instances support slicing and element access, for
* retrieving individual digits or sequences of digits. As the name suggests,
- * Deccoeff instances are intended to be used as the coefficients for _Decimal
+ * Deccoeff instances are intended to be used as the coefficients for Decimal
* instances.
*
* Author: Mark Dickinson (dickinsm at gmail.com).
@@ -897,46 +892,6 @@
return false;
}
-/*
- variant of limbs_from_string that accepts a string where all but one of the
- characters is a decimal digit, and ignores the specified character.
- (Typically, the character to be ignored is a decimal point.)
-
- On entry, s is a pointer to a character array of length s_len + 1, 0 <=
- int_len <= s_len, s[0] through s[int_len-1] and s[int_len+1] through
- s[s_len] contain decimal digits. The result is then identical to
- limbs_from_string applied to the concatenation of s[:int_len] and
- s[int_len+1:]. No checking is performed, and there is no return value.
-
- This function is used when parsing _Decimal instances.
- */
-
-static void
-limbs_from_pointed_unicode(limb_t *a, const Py_UNICODE *s, Py_ssize_t s_len,
- Py_ssize_t int_len)
-{
- Py_ssize_t i, k, digits_in_limb;
- limb_t acc;
- Py_UNICODE c;
-
-#define GET_DIGIT(i) ((i) < int_len ? s[(i)] : s[(i)+1])
-
- k = (s_len+LIMB_DIGITS-1) / LIMB_DIGITS;
- digits_in_limb = (s_len+LIMB_DIGITS-1) % LIMB_DIGITS + 1;
- acc = LIMB_ZERO;
- for (i = 0; i < s_len; i++) {
- c = GET_DIGIT(i);
- limb_lshift(&acc, acc, 1, wdigit_to_limb(c));
- digits_in_limb--;
- if (digits_in_limb == 0) {
- digits_in_limb = LIMB_DIGITS;
- a[--k] = acc;
- acc = LIMB_ZERO;
- }
- }
- assert(digits_in_limb == LIMB_DIGITS);
-}
-
/* Base conversion, from base PyLong_BASE to base LIMB_BASE.
Convert an array of digits for a Python long to an array of limbs
@@ -1371,33 +1326,6 @@
return deccoeff_normalize(z);
}
-/* Variant of the above that converts an array of unicode digits containing a
- decimal point at position int_len (but no sign). The decimal point is
- simply ignored. This is used to parse the coefficient of a Decimal
- instance. */
-
-static deccoeff *
-_deccoeff_from_pointed_unicode_and_size(const Py_UNICODE *s, Py_ssize_t s_len,
- Py_ssize_t int_len) {
- Py_ssize_t z_size;
- deccoeff *z;
-
- if (s_len > MAX_DIGITS) {
- PyErr_SetString(PyExc_OverflowError,
- "too many digits");
- return NULL;
- }
-
- z_size = (s_len + LIMB_DIGITS - 1) / LIMB_DIGITS;
- z = _deccoeff_new(z_size);
- if (z == NULL)
- return NULL;
-
- limbs_from_pointed_unicode(z->ob_limbs, s, s_len, int_len);
- return deccoeff_normalize(z);
-}
-
-
/***********************************
* Deccoeff <-> PyLong conversions *
***********************************/
@@ -2437,705 +2365,6 @@
};
-/*****************
- * _Decimal type *
- *****************/
-
-/* class name */
-#define DECIMAL_NAME "_Decimal"
-
-/* A finite decimal object needs a sign, a coefficient and an exponent. An
- infinity has a sign and nothing more; the coefficient and exponent are
- ignored. A (quiet or signalling) nan has a sign, and may carry additional
- information (the payload) in the coefficient. The exponent is not used. */
-
-#define DEC_FLAGS_NEG (1<<0)
-#define DEC_FLAGS_NONZERO (1<<1) /* currently unused; may want this later */
-#define DEC_FLAGS_SPECIAL (1<<2)
-#define DEC_FLAGS_INF (1<<3)
-#define DEC_FLAGS_NAN (1<<4)
-#define DEC_FLAGS_SNAN (1<<5)
-#define DEC_FLAGS_QNAN (1<<6)
-
-#define FINITE_FLAGS 0
-#define INF_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_INF)
-#define QNAN_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_NAN | DEC_FLAGS_QNAN)
-#define SNAN_FLAGS (DEC_FLAGS_SPECIAL | DEC_FLAGS_NAN | DEC_FLAGS_SNAN)
-
-/* note that FINITE_FLAGS < INF_FLAGS < SNAN_FLAGS < QNAN_FLAGS,
- corresponding to the standard total ordering of Decimals */
-
-typedef int dec_flag_t;
-typedef Py_ssize_t exp_t;
-
-typedef struct {
- PyObject_HEAD
- deccoeff *dec_coeff; /* coefficient, or NaN payload; NULL for infinity */
- PyLongObject *dec_exp; /* exponent: NULL for an infinity or NaN */
- dec_flag_t dec_flags; /* flags describing sign and number class */
-} _Decimal;
-
-static PyTypeObject deccoeff__DecimalType;
-
-/* create new _Decimal (or instance of a subclass of _Decimal); no
- validation or conversion---just allocate memory and fill the slots */
-
-static _Decimal *
-__Decimal_new(PyTypeObject *type, dec_flag_t flags, deccoeff *coeff,
- PyLongObject *exp)
-{
- _Decimal *self;
-
- /* sanity checks */
- assert(
- ((flags | 1) == (FINITE_FLAGS | 1)) || /* finite (poss. zero) */
- ((flags | 1) == (INF_FLAGS | 1)) || /* infinity */
- ((flags | 1) == (QNAN_FLAGS | 1)) || /* quiet nan */
- ((flags | 1) == (SNAN_FLAGS | 1))); /* signaling nan */
-
- /* incref coefficient and exponent, but only if they're non-NULL */
- if (flags & DEC_FLAGS_INF)
- assert(coeff == NULL);
- else {
- assert(coeff != NULL);
- Py_INCREF(coeff);
- }
- if (flags & DEC_FLAGS_SPECIAL)
- assert(exp == NULL);
- else {
- assert(exp != NULL);
- Py_INCREF(exp);
- }
-
- self = (_Decimal *)type->tp_alloc(type, 0);
- if (self == NULL)
- return NULL;
- self->dec_flags = flags;
- self->dec_coeff = coeff;
- self->dec_exp = exp;
- return self;
-}
-
-/* deallocate _Decimal instance */
-
-static void
-_Decimal_dealloc(PyObject *self)
-{
- _Decimal *dec;
- dec = (_Decimal *)self;
- /* coefficient should be present iff decimal instance is not infinite */
- if (dec->dec_flags & DEC_FLAGS_INF)
- assert(dec->dec_coeff == NULL);
- else {
- assert(dec->dec_coeff != NULL);
- Py_DECREF(dec->dec_coeff);
- }
- /* exponent is present only for finite numbers */
- if (dec->dec_flags & DEC_FLAGS_SPECIAL)
- assert(dec->dec_exp == NULL);
- else {
- assert(dec->dec_exp != NULL);
- Py_DECREF(dec->dec_exp);
- }
- self->ob_type->tp_free(self);
-}
-
-/* Macros to create finite, infinite, qnan, and snan _Decimal instances */
-
-#define FINITE_DECIMAL(type, sign, coeff, exp) \
- (__Decimal_new(type, sign, coeff, exp))
-#define INF_DECIMAL(type, sign) \
- (__Decimal_new(type, sign | INF_FLAGS, NULL, NULL))
-#define QNAN_DECIMAL(type, sign, payload) \
- (__Decimal_new(type, sign | QNAN_FLAGS, payload, NULL))
-#define SNAN_DECIMAL(type, sign, payload) \
- (__Decimal_new(type, sign | SNAN_FLAGS, payload, NULL))
-
-/* create a new finite _Decimal instance */
-
-static PyObject *
-_Decimal_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- /* create a new finite _Decimal instance, given a sequence consisting
- of its sign (an integer), coefficient and exponent */
-
- PyObject *ocoeff, *oexp;
- deccoeff *coeff;
- PyLongObject *exp;
- int sign;
- static char *kwlist[] = {"sign", "coeff", "exp", 0};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "iOO:" DECIMAL_NAME, kwlist,
- &sign, &ocoeff, &oexp))
- return NULL;
- if (!(sign == 0 || sign == 1)) {
- PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
- return NULL;
- }
- if (ocoeff->ob_type != &deccoeff_DeccoeffType) {
- PyErr_SetString(PyExc_TypeError, "coeff should have type " CLASS_NAME);
- return NULL;
- }
- coeff = (deccoeff *)ocoeff;
- if (oexp->ob_type != &PyLong_Type) {
- PyErr_SetString(PyExc_TypeError, "exp should have type int");
- return NULL;
- }
- exp = (PyLongObject *)oexp;
- return (PyObject *)FINITE_DECIMAL(type, sign, coeff, exp);
-}
-
-/* Create a _Decimal instance directly from a string; classmethod */
-
-static PyObject *
-_Decimal_from_str(PyTypeObject *cls, PyObject *arg)
-{
- PyObject *result=NULL;
- deccoeff *coeff;
- Py_ssize_t ndigits;
- Py_UNICODE *coeff_start, *coeff_end, *s_end, *int_end, *exp_start, *s;
- int sign = 0, exp_sign = 0;
- PyObject *exp, *temp, *frac_digits;
- deccoeff *duexp;
-
- if (!PyUnicode_Check(arg)) {
- PyErr_SetString(PyExc_TypeError,
- "Expected str instance");
- return NULL;
- }
- s = PyUnicode_AS_UNICODE(arg);
- s_end = s + PyUnicode_GET_SIZE(arg);
-
- /* Stage 1: parse and validate the string, identifying the points
- where the coefficients and exponent start and stop */
-
- /* optional sign */
- if (*s == '+')
- s++;
- else if (*s == '-') {
- s++;
- sign = 1;
- }
-
- switch(*s) {
- case 'n':
- case 'N':
- /* nan */
- s++;
- if (*s == 'a' || *s == 'A')
- s++;
- else
- goto parse_error;
- if (*s == 'n' || *s == 'N')
- s++;
- else
- goto parse_error;
- coeff_start = s;
- while ('0' <= *s && *s <= '9')
- s++;
- if (s != s_end)
- goto parse_error;
-
- coeff = _deccoeff_from_unicode_and_size(coeff_start, s-coeff_start);
- if (coeff != NULL) {
- result = (PyObject *)QNAN_DECIMAL(cls, sign, coeff);
- Py_DECREF(coeff);
- }
- break;
- case 's':
- case 'S':
- /* snan */
- s++;
- if (*s == 'n' || *s == 'N')
- s++;
- else
- goto parse_error;
- if (*s == 'a' || *s == 'A')
- s++;
- else
- goto parse_error;
- if (*s == 'n' || *s == 'N')
- s++;
- else
- goto parse_error;
- coeff_start = s;
- while ('0' <= *s && *s <= '9')
- s++;
- if (s != s_end)
- goto parse_error;
-
- coeff = _deccoeff_from_unicode_and_size(coeff_start, s-coeff_start);
- if (coeff != NULL) {
- result = (PyObject *)SNAN_DECIMAL(cls, sign, coeff);
- Py_DECREF(coeff);
- }
- break;
- case 'i':
- case 'I':
- /* inf[inity] */
- s++;
- if (*s == 'n' || *s == 'N')
- s++;
- else
- goto parse_error;
- if (*s == 'f' || *s == 'F')
- s++;
- else
- goto parse_error;
- if (*s == 'i' || *s == 'I') {
- s++;
- if (*s == 'n' || *s == 'N')
- s++;
- else
- goto parse_error;
- if (*s == 'i' || *s == 'I')
- s++;
- else
- goto parse_error;
- if (*s == 't' || *s == 'T')
- s++;
- else
- goto parse_error;
- if (*s == 'y' || *s == 'Y')
- s++;
- else
- goto parse_error;
- }
- /* end of string */
- if (s != s_end)
- goto parse_error;
-
- result = (PyObject *)INF_DECIMAL(cls, sign);
- break;
- default:
- /* numeric part: at least one digit, with an optional decimal point */
- coeff_start = s;
- while ('0' <= *s && *s <= '9')
- s++;
- int_end = s;
- if (*s == '.') {
- s++;
- while ('0' <= *s && *s <= '9')
- s++;
- coeff_end = s-1;
- }
- else
- coeff_end= s;
-
- ndigits = coeff_end - coeff_start;
- if (ndigits == 0)
- goto parse_error;
-
- /* [e <exponent>] */
- if (*s == 'e' || *s == 'E') {
- s++;
- if (*s == '+')
- s++;
- else if (*s == '-') {
- s++;
- exp_sign = 1;
- }
- exp_start = s;
- if (!('0' <= *s && *s <= '9'))
- goto parse_error;
- s++;
- while ('0' <= *s && *s <= '9')
- s++;
- }
- else
- exp_start = s;
-
- /* end of string */
- if (s != s_end)
- goto parse_error;
-
- /* parse exponent (without sign), returning a deccoeff */
- duexp = _deccoeff_from_unicode_and_size(exp_start, s-exp_start);
- if (duexp == NULL)
- return NULL;
-
- /* REF: duexp */
-
- /* Later we'll allow negative deccoeffs, and have the exponent
- be a deccoeff. Later :)
- For now we have to convert this to a Python long */
- exp = (PyObject *)deccoeff_long(duexp);
- Py_DECREF(duexp);
- if (exp == NULL)
- return NULL;
-
- /* REF: exp */
-
- /* adjust exponent: include sign, and adjust by length
- of fractional part of input */
- if (exp_sign == 1) {
- /* negate exp */
- temp = PyNumber_Negative(exp);
- Py_DECREF(exp);
- exp = temp;
- if (exp == NULL)
- return NULL;
- }
-
- /* REF: exp */
-
- /* subtract frac_digits */
- frac_digits = PyLong_FromSize_t(coeff_end - int_end);
- if (frac_digits == NULL) {
- Py_DECREF(exp);
- return NULL;
- }
-
- /* REF: exp, frac_digits */
-
- temp = PyNumber_Subtract(exp, frac_digits);
- Py_DECREF(frac_digits);
- Py_DECREF(exp);
- exp = temp;
- if (exp == NULL)
- return NULL;
-
- /* REF: exp */
-
- /* get coefficient */
- coeff = _deccoeff_from_pointed_unicode_and_size(coeff_start,
- coeff_end - coeff_start, int_end - coeff_start);
-
- if (coeff == NULL) {
- Py_DECREF(exp);
- return NULL;
- }
-
- result = (PyObject *)FINITE_DECIMAL(cls, sign, coeff,
- (PyLongObject *)exp);
- Py_DECREF(coeff);
- Py_DECREF(exp);
- }
- return result;
-
- parse_error:
- PyErr_SetString(PyExc_ValueError,
- "invalid numeric string");
- return NULL;
-
-}
-
-/* Create a new finite _Decimal instance; classmethod */
-
-static PyObject *
-_Decimal_finite(PyTypeObject *cls, PyObject *args)
-{
- PyObject *ocoeff, *oexp;
- deccoeff *coeff;
- PyLongObject *exp;
- int sign;
-
- if (!PyArg_ParseTuple(args, "iOO:" DECIMAL_NAME, &sign, &ocoeff, &oexp))
- return NULL;
- if (ocoeff->ob_type != &deccoeff_DeccoeffType) {
- PyErr_SetString(PyExc_TypeError, "coeff should have type " CLASS_NAME);
- return NULL;
- }
- coeff = (deccoeff *)ocoeff;
- if (oexp->ob_type != &PyLong_Type) {
- PyErr_SetString(PyExc_TypeError, "exp should have type int");
- return NULL;
- }
- exp = (PyLongObject *)oexp;
- if (!(sign == 0 || sign == 1)) {
- PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
- return NULL;
- }
- return (PyObject *)FINITE_DECIMAL(cls, sign, coeff, exp);
-}
-
-/* Create a qNaN; classmethod */
-
-static PyObject *
-_Decimal_qNaN(PyTypeObject *cls, PyObject *args) {
- PyObject *opayload;
- deccoeff *payload;
- int sign;
-
- if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
- return NULL;
- if (opayload->ob_type != &deccoeff_DeccoeffType) {
- PyErr_SetString(PyExc_TypeError,
- "payload should have type " CLASS_NAME);
- return NULL;
- }
- payload = (deccoeff *)opayload;
- if (!(sign == 0 || sign == 1)) {
- PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
- return NULL;
- }
- return (PyObject *)QNAN_DECIMAL(cls, sign, payload);
-}
-
-/* Create an sNaN; classmethod */
-
-static PyObject *
-_Decimal_sNaN(PyTypeObject *cls, PyObject *args) {
- PyObject *opayload;
- deccoeff *payload;
- int sign;
-
- if (!PyArg_ParseTuple(args, "iO:" DECIMAL_NAME, &sign, &opayload))
- return NULL;
- if (opayload->ob_type != &deccoeff_DeccoeffType) {
- PyErr_SetString(PyExc_TypeError,
- "payload should have type " CLASS_NAME);
- return NULL;
- }
- payload = (deccoeff *)opayload;
- if (!(sign == 0 || sign == 1)) {
- PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
- return NULL;
- }
- return (PyObject *)SNAN_DECIMAL(cls, sign, payload);
-}
-
-/* Create an infinity; classmethod */
-
-static PyObject *
-_Decimal_inf(PyTypeObject *cls, PyObject *args) {
- int sign;
-
- if (!PyArg_ParseTuple(args, "i:" DECIMAL_NAME, &sign))
- return NULL;
- if (!(sign == 0 || sign == 1)) {
- PyErr_SetString(PyExc_ValueError, "sign should be 0 or 1");
- return NULL;
- }
- return (PyObject *)INF_DECIMAL(cls, sign);
-}
-
-/* Return the sign of any _Decimal instance */
-
-static PyObject *
-_Decimal_getsign(_Decimal *self, void *closure)
-{
- long sign;
- sign = (long)(self->dec_flags) & DEC_FLAGS_NEG;
- return PyLong_FromLong(sign);
-}
-
-/* Return the coefficient of a finite _Decimal */
-
-static PyObject *
-_Decimal_getcoeff(_Decimal *self, void *closure)
-{
- if (self->dec_flags & DEC_FLAGS_SPECIAL) {
- PyErr_SetString(PyExc_ValueError,
- "infinity or NaN has no coefficient");
- return NULL;
- }
- Py_INCREF(self->dec_coeff);
- return (PyObject *)self->dec_coeff;
-}
-
-/* Return the payload of a NaN */
-
-static PyObject *
-_Decimal_getpayload(_Decimal *self, void *closure)
-{
- if (self->dec_flags & DEC_FLAGS_NAN) {
- Py_INCREF(self->dec_coeff);
- return (PyObject *)self->dec_coeff;
- }
- else {
- PyErr_SetString(PyExc_ValueError,
- "argument is not a NaN");
- return NULL;
- }
-}
-
-/* Return the exponent of a finite _Decimal instance */
-
-static PyObject *
-_Decimal_getexp(_Decimal *self, void *closure)
-{
- if (self->dec_flags & DEC_FLAGS_SPECIAL) {
- PyErr_SetString(PyExc_ValueError,
- "infinity or NaN has no exponent");
- return NULL;
- }
- Py_INCREF(self->dec_exp);
- return (PyObject *)(self->dec_exp);
-}
-
-/* Return True if the given Decimal is special (an infinity or NaN),
- False otherwise. */
-
-static PyObject *
-_Decimal_getspecial(_Decimal *self, void *closure)
-{
- if (self->dec_flags & DEC_FLAGS_SPECIAL)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-
-static PyObject *
-_Decimal_is_finite(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_SPECIAL)
- Py_RETURN_FALSE;
- else
- Py_RETURN_TRUE;
-}
-
-static PyObject *
-_Decimal_is_infinite(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_INF)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_nan(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_NAN)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_qnan(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_QNAN)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_snan(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_SNAN)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_signed(_Decimal *self)
-{
- if (self->dec_flags & DEC_FLAGS_NEG)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
-}
-
-static PyObject *
-_Decimal_is_zero(_Decimal *self)
-{
- if ((self->dec_flags & DEC_FLAGS_SPECIAL) ||
- deccoeff_bool(self->dec_coeff))
- Py_RETURN_FALSE;
- else
- Py_RETURN_TRUE;
-}
-
-static _Decimal *
-_Decimal_copy(_Decimal *self)
-{
- return __Decimal_new(&deccoeff__DecimalType, self->dec_flags,
- self->dec_coeff, self->dec_exp);
-}
-
-static _Decimal *
-_Decimal_copy_negate(_Decimal *self)
-{
- return __Decimal_new(&deccoeff__DecimalType, self->dec_flags ^ 1,
- self->dec_coeff, self->dec_exp);
-}
-
-static _Decimal *
-_Decimal_copy_abs(_Decimal *self)
-{
- return __Decimal_new(&deccoeff__DecimalType, self->dec_flags & (~1),
- self->dec_coeff, self->dec_exp);
-}
-
-static PyMethodDef _Decimal_methods[] = {
- {"_finite", (PyCFunction)_Decimal_finite, METH_VARARGS|METH_CLASS, " "},
- {"_qnan", (PyCFunction)_Decimal_qNaN, METH_VARARGS|METH_CLASS, " "},
- {"_snan", (PyCFunction)_Decimal_sNaN, METH_VARARGS|METH_CLASS, " "},
- {"_inf", (PyCFunction)_Decimal_inf, METH_VARARGS|METH_CLASS, " "},
- {"from_str", (PyCFunction)_Decimal_from_str, METH_O|METH_CLASS, " "},
- {"is_finite", (PyCFunction)_Decimal_is_finite, METH_NOARGS, " "},
- {"is_infinite", (PyCFunction)_Decimal_is_infinite, METH_NOARGS, " "},
- {"is_nan", (PyCFunction)_Decimal_is_nan, METH_NOARGS, " "},
- {"is_qnan", (PyCFunction)_Decimal_is_qnan, METH_NOARGS, " "},
- {"is_snan", (PyCFunction)_Decimal_is_snan, METH_NOARGS, " "},
- {"is_signed", (PyCFunction)_Decimal_is_signed, METH_NOARGS, " "},
- {"is_zero", (PyCFunction)_Decimal_is_zero, METH_NOARGS, " "},
- {"copy", (PyCFunction)_Decimal_copy, METH_NOARGS, " "},
- {"copy_negate", (PyCFunction)_Decimal_copy_negate, METH_NOARGS, " "},
- {"copy_abs", (PyCFunction)_Decimal_copy_abs, METH_NOARGS, " "},
- {NULL, NULL}
-};
-
-static PyGetSetDef _Decimal_getsetters[] = {
- {"_sign", (getter)_Decimal_getsign, NULL, "sign", NULL},
- {"_int", (getter)_Decimal_getcoeff, NULL,
- "coefficient (invalid for NaNs and infinites)", NULL},
- {"_exp", (getter)_Decimal_getexp, NULL,
- "exponent (invalid for NaNs and infinities)", NULL},
- {"_payload", (getter)_Decimal_getpayload, NULL,
- "payload of a NaN (invalid for non-NaNs)", NULL},
- {"_is_special", (getter)_Decimal_getspecial, NULL,
- "True for infinities and NaNs, false otherwise", NULL},
- {NULL}
-};
-
-static PyTypeObject deccoeff__DecimalType = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- MODULE_NAME "." DECIMAL_NAME, /* tp_name */
- sizeof(_Decimal), /* tp_basicsize */
- 0, /* tp_itemsize */
- _Decimal_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- "support for Decimal type", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- _Decimal_methods, /* tp_methods */
- 0, /* tp_members */
- _Decimal_getsetters, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- _Decimal_new, /* tp_new */
- PyObject_Del, /* tp_free */
-};
-
static PyMethodDef deccoeff_module_methods[] = {
{NULL, NULL}
};
@@ -3169,9 +2398,6 @@
if (PyType_Ready(&deccoeff_DeccoeffType) < 0)
return NULL;
- if (PyType_Ready(&deccoeff__DecimalType) < 0)
- return NULL;
-
m = PyModule_Create(&deccoeff_module);
if (m == NULL)
return NULL;
@@ -3182,11 +2408,6 @@
if (check == -1)
return NULL;
- Py_INCREF(&deccoeff__DecimalType);
- check = PyModule_AddObject(m, DECIMAL_NAME,
- (PyObject *) &deccoeff__DecimalType);
- if (check == -1)
- return NULL;
check = PyModule_AddIntMacro(m, LIMB_DIGITS);
if (check == -1)
return NULL;
Modified: sandbox/trunk/decimal/decimal_in_c/decimal.py
==============================================================================
--- sandbox/trunk/decimal/decimal_in_c/decimal.py (original)
+++ sandbox/trunk/decimal/decimal_in_c/decimal.py Tue Oct 20 13:33:41 2009
@@ -132,7 +132,7 @@
'setcontext', 'getcontext', 'localcontext'
]
-from deccoeff import Deccoeff, _Decimal
+from deccoeff import Deccoeff
import copy as _copy
import math as _math
@@ -216,7 +216,7 @@
"""
def handle(self, context, *args):
if args:
- ans = Decimal._qnan(args[0]._sign, args[0]._payload)
+ ans = _dec_from_triple(args[0]._sign, args[0]._int, 'n', True)
return ans._fix_nan(context)
return NaN
@@ -549,7 +549,7 @@
# (because Decimals are not interoperable with floats). See the notes in
# numbers.py for more detail.
-class Decimal(_Decimal):
+class Decimal(object):
"""Floating point class for decimal arithmetic."""
# Generally, the value of the Decimal instance is given by
@@ -575,40 +575,67 @@
# From a string
# REs insist on real strings, so we can too.
if isinstance(value, str):
- try:
- m = cls.from_str(value.strip())
- except ValueError:
+ self = object.__new__(cls)
+
+ m = _parser(value.strip())
+ if m is None:
if context is None:
context = getcontext()
return context._raise_error(ConversionSyntax,
- "Invalid literal for Decimal: %r" % value)
- return m
+ "Invalid literal for Decimal: %r" % value)
- # From another decimal
- if isinstance(value, _Decimal):
- if value._is_special:
- if value.is_infinite():
- return cls._inf(value._sign)
- elif value.is_qnan():
- return cls._qnan(value._sign, value._payload)
- elif value.is_snan():
- return cls._snan(value._sign, value._payload)
- else:
- assert False, "never get here"
+ if m.group('sign') == "-":
+ self._sign = 1
else:
- return cls._finite(value._sign, value._int, value._exp)
+ self._sign = 0
+ intpart = m.group('int')
+ if intpart is not None:
+ # finite number
+ fracpart = m.group('frac') or ''
+ exp = int(m.group('exp') or '0')
+ self._int = Deccoeff(intpart+fracpart)
+ self._exp = exp - len(fracpart)
+ self._is_special = False
+ else:
+ diag = m.group('diag')
+ if diag is not None:
+ # NaN
+ self._int = Deccoeff(diag)
+ if m.group('signal'):
+ self._exp = 'N'
+ else:
+ self._exp = 'n'
+ else:
+ # infinity
+ self._int = Deccoeff(0)
+ self._exp = 'F'
+ self._is_special = True
+ return self
# From an integer
if isinstance(value, int):
+ self = object.__new__(cls)
if value >= 0:
- _sign = 0
+ self._sign = 0
else:
- _sign = 1
- _int = Deccoeff(abs(value))
- return cls._finite(_sign, _int, 0)
+ self._sign = 1
+ self._exp = 0
+ self._int = Deccoeff(abs(value))
+ self._is_special = False
+ return self
+
+ # From another decimal
+ if isinstance(value, Decimal):
+ self = object.__new__(cls)
+ self._exp = value._exp
+ self._sign = value._sign
+ self._int = value._int
+ self._is_special = value._is_special
+ return self
# tuple/list conversion (possibly from as_tuple())
if isinstance(value, (list,tuple)):
+ self = object.__new__(cls)
if len(value) != 3:
raise ValueError('Invalid tuple size in creation of Decimal '
'from list or tuple. The list or tuple '
@@ -618,10 +645,12 @@
raise ValueError("Invalid sign. The first value in the tuple "
"should be an integer; either 0 for a "
"positive number or 1 for a negative number.")
- _sign = value[0]
+ self._sign = value[0]
if value[2] == 'F':
# infinity: value[1] is ignored
- return cls._inf(_sign)
+ self._int = Deccoeff(0)
+ self._exp = value[2]
+ self._is_special = True
else:
# process and validate the digits in value[1]
digits = []
@@ -632,17 +661,20 @@
raise ValueError("The second value in the tuple must "
"be composed of integers in the range "
"0 through 9.")
- _int = Deccoeff(''.join(digits))
- if value[2] == 'n':
- return cls._qnan(_sign, _int)
- elif value[2] == 'N':
- return cls._snan(_sign, _int)
+ self._int = Deccoeff(''.join(digits))
+ self._exp = value[2]
+ if value[2] in ('n', 'N'):
+ # NaN
+ self._is_special = True
elif isinstance(value[2], int):
- return cls._finite(_sign, _int, value[2])
+ # finite number
+ self._is_special = False
else:
raise ValueError("The third value in the tuple must "
"be an integer, or one of the "
"strings 'F', 'n', 'N'.")
+ return self
+
if isinstance(value, float):
raise TypeError("Cannot convert float to Decimal. " +
@@ -749,13 +781,6 @@
other)
return 0
- def __bool__(self):
- """Return True if self is nonzero; otherwise return False.
-
- NaNs and infinities are considered nonzero.
- """
- return self._is_special or bool(self._int)
-
def _cmp(self, other):
"""Compare the two non-NaN decimal instances self and other.
@@ -949,8 +974,8 @@
coeff = (0,)
exp = 'F'
else: # NaN
- if self._payload:
- coeff = tuple(int(x) for x in str(self._payload))
+ if self._int:
+ coeff = tuple(int(x) for x in str(self._int))
else:
coeff = ()
if self.is_qnan():
@@ -983,15 +1008,15 @@
if self.is_infinite():
return sign + 'Infinity'
elif self.is_qnan():
- if not self._payload:
+ if not self._int:
return sign + 'NaN'
else:
- return sign + 'NaN' + str(self._payload)
+ return sign + 'NaN' + str(self._int)
else:
- if not self._payload:
+ if not self._int:
return sign + 'sNaN'
else:
- return sign + 'sNaN' + str(self._payload)
+ return sign + 'sNaN' + str(self._int)
# number of digits of self._int to left of decimal point
si = str(self._int)
@@ -1038,15 +1063,15 @@
if self.is_infinite():
return sign + 'Infinity'
elif self.is_qnan():
- if not self._payload:
+ if not self._int:
return sign + 'NaN'
else:
- return sign + 'NaN' + str(self._payload)
+ return sign + 'NaN' + str(self._int)
else: # self.is_snan()
- if not self._payload:
+ if not self._int:
return sign + 'sNaN'
else:
- return sign + 'sNaN' + str(self._payload)
+ return sign + 'sNaN' + str(self._int)
# deal independently with case of 0
if self._int:
@@ -1624,8 +1649,7 @@
def _fix_nan(self, context):
"""Decapitate the payload of a NaN to fit the context"""
assert self.is_nan()
-
- payload = self._payload
+ payload = self._int
# maximum length of payload is precision if _clamp=0,
# precision-1 if _clamp=1.
@@ -1633,11 +1657,7 @@
if payload.digit_length() > max_payload_len:
# if payload is too long, take *low order* digits
payload = payload[:max_payload_len]
- if self.is_qnan():
- return Decimal._qnan(self._sign, payload)
- else:
- return Decimal._snan(self._sign, payload)
-
+ return _dec_from_triple(self._sign, payload, 'n', True)
return Decimal(self)
def _fix(self, context, rounding=None):
@@ -2817,8 +2837,8 @@
return 0
else: #self_type in (2, 3):
# nans are ordered by payload
- if self._payload != other._payload:
- return [1, -1][self._payload < other._payload]
+ if self._int != other._int:
+ return [1, -1][self._int < other._int]
else:
return 0
@@ -2842,15 +2862,18 @@
def _copy(self):
"""Return a copy of self."""
- return Decimal(_Decimal.copy(self))
+ return _dec_from_triple(self._sign, self._int, self._exp, self._is_special)
def copy_abs(self):
"""Returns a copy with the sign set to 0. """
- return Decimal(_Decimal.copy_abs(self))
+ return _dec_from_triple(0, self._int, self._exp, self._is_special)
def copy_negate(self):
"""Returns a copy with the sign inverted."""
- return Decimal(_Decimal.copy_negate(self))
+ if self._sign:
+ return _dec_from_triple(0, self._int, self._exp, self._is_special)
+ else:
+ return _dec_from_triple(1, self._int, self._exp, self._is_special)
def copy_sign(self, other):
"""Returns self with the sign of other."""
@@ -2930,6 +2953,13 @@
return ans
+ def __bool__(self):
+ """Return True if self is nonzero; otherwise return False.
+
+ NaNs and infinities are considered nonzero.
+ """
+ return self._is_special or bool(self._int)
+
def is_canonical(self):
"""Return True if self is canonical; otherwise return False.
@@ -2938,22 +2968,54 @@
"""
return True
+ def is_finite(self):
+ """Return True if self is finite; otherwise return False.
+
+ A Decimal instance is considered finite if it is neither
+ infinite nor a NaN.
+ """
+ return not self._is_special
+
+ def is_infinite(self):
+ """Return True if self is infinite; otherwise return False."""
+ return self._exp == 'F'
+
+ def is_nan(self):
+ """Return True if self is a qNaN or sNaN; otherwise return False."""
+ return self._exp in ('n', 'N')
+
def is_normal(self, context=None):
"""Return True if self is a normal number; otherwise return False."""
- if self._is_special or not self:
+ if self._is_special or not bool(self._int):
return False
if context is None:
context = getcontext()
- return context.Emin <= self.adjusted() <= context.Emax
+ return self.adjusted() >= context.Emin
+
+ def is_qnan(self):
+ """Return True if self is a quiet NaN; otherwise return False."""
+ return self._exp == 'n'
+
+ def is_signed(self):
+ """Return True if self is negative; otherwise return False."""
+ return self._sign == 1
+
+ def is_snan(self):
+ """Return True if self is a signaling NaN; otherwise return False."""
+ return self._exp == 'N'
def is_subnormal(self, context=None):
"""Return True if self is subnormal; otherwise return False."""
- if self._is_special or not self:
+ if self._is_special or not bool(self._int):
return False
if context is None:
context = getcontext()
return self.adjusted() < context.Emin
+ def is_zero(self):
+ """Return True if self is a zero; otherwise return False."""
+ return not self._is_special and not self._int
+
def _ln_exp_bound(self):
"""Compute a lower bound for the adjusted exponent of self.ln().
In other words, compute r such that self.ln() >= 10**r. Assumes
@@ -3610,10 +3672,14 @@
This function is for *internal use only*.
"""
-
assert type(coefficient) is Deccoeff
- assert not special
- return Decimal._finite(sign, coefficient, exponent)
+ self = object.__new__(Decimal)
+ self._sign = sign
+ self._int = coefficient
+ self._exp = exponent
+ self._is_special = special
+
+ return self
# Register Decimal as a kind of Number (an abstract base class).
# However, do not register it as Real (because Decimals are not
@@ -3788,7 +3854,7 @@
"no trailing or leading whitespace is "
"permitted.")
d = Decimal(num, context=self)
- if d.is_nan() and d._payload.digit_length() + self._clamp > self.prec:
+ if d.is_nan() and d._int.digit_length() + self._clamp > self.prec:
return self._raise_error(ConversionSyntax,
"diagnostic info too long in NaN")
return d._fix(self)
@@ -5438,6 +5504,29 @@
# As the flag UNICODE is not enabled here, we're explicitly avoiding any
# other meaning for \d than the numbers [0-9].
+import re
+_parser = re.compile(r""" # A numeric string consists of:
+# \s*
+ (?P<sign>[-+])? # an optional sign, followed by either...
+ (
+ (?=\d|\.\d) # ...a number (with at least one digit)
+ (?P<int>\d*) # having a (possibly empty) integer part
+ (\.(?P<frac>\d*))? # followed by an optional fractional part
+ (E(?P<exp>[-+]?\d+))? # followed by an optional exponent, or...
+ |
+ Inf(inity)? # ...an infinity, or...
+ |
+ (?P<signal>s)? # ...an (optionally signaling)
+ NaN # NaN
+ (?P<diag>\d*) # with (possibly empty) diagnostic info.
+ )
+# \s*
+ \Z
+""", re.VERBOSE | re.IGNORECASE).match
+
+_all_zeros = re.compile('0*$').match
+_exact_half = re.compile('50*$').match
+
##### PEP3101 support functions ##############################################
# The functions parse_format_specifier and format_align have little to do
# with the Decimal class, and could potentially be reused for other pure
@@ -5448,8 +5537,6 @@
# [[fill]align][sign][0][minimumwidth][.precision][type]
#
-import re
-
_parse_format_specifier_regex = re.compile(r"""\A
(?:
(?P<fill>.)?
More information about the Python-checkins
mailing list