[Python-checkins] r46091 - sandbox/trunk/decimal-c/_decimal.c
georg.brandl
python-checkins at python.org
Tue May 23 11:53:13 CEST 2006
Author: georg.brandl
Date: Tue May 23 11:53:12 2006
New Revision: 46091
Modified:
sandbox/trunk/decimal-c/_decimal.c
Log:
Update to current status.
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c (original)
+++ sandbox/trunk/decimal-c/_decimal.c Tue May 23 11:53:12 2006
@@ -6,6 +6,8 @@
#include "structmember.h"
#include "decimal.h"
+/* XXX: getcontext() perhaps shouldn't INCREF the ctx */
+
/* helpful macros ************************************************************/
#define MODULE_NAME "_decimal"
@@ -244,12 +246,159 @@
return 0;
}
-/* default: rounding=-1 (use context), see the ROUND_* constants */
+static decimalobject *
+_round_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_half_down(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_half_even(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_half_up(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_floor(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+static decimalobject *
+_round_ceiling(decimalobject *self, long prec, long expdiff, contextobject *ctx)
+{
+}
+
+typedef decimalobject*(*round_func)(decimalobject *, long, long, contextobject *);
+static round_func round_funcs[] = {
+ _round_down, _round_up, _round_half_down, _round_half_even,
+ _round_half_up, _round_floor, _round_ceiling
+};
+
+/* default: prec=-1, rounding=-1 (use context), see the ROUND_* constants */
static decimalobject *
_decimal_round(decimalobject *self, long prec, contextobject *ctx, int rounding)
{
- /* XXX */
- Py_RETURN_NONE;
+ decimalobject *new, *new2, *errres;
+ Py_ssize_t i, expdiff;
+ round_func rnd_func;
+
+ if (ISSPECIAL(self)) {
+ decimalobject *nan = NULL;
+ int ret;
+ ret = _check_nans(self, NULL, ctx, &nan);
+ if (ret != 0) return nan;
+ if (ISINF(self)) return decimal_copy(self);
+ }
+ if (rounding == -1)
+ rounding = ctx->rounding;
+ if (prec == -1)
+ prec = ctx->prec;
+
+ if (rounding < 0 || rounding > ROUND_CEILING) {
+ PyErr_SetString(PyExc_ValueError, "invalid rounding mode");
+ return NULL;
+ }
+
+ if (!decimal_nonzero(self)) {
+ if (prec <= 0)
+ i = 1;
+ else
+ i = prec;
+
+ new = _new_decimalobj(i, self->sign,
+ self->ob_size - prec + self->exp);
+ if (!new) return NULL;
+ while (i--)
+ new->digits[i] = 0;
+
+ errres = context_raise_error(ctx, S_ROUNDED, NULL, NULL);
+ if (!errres) {
+ Py_DECREF(new);
+ return NULL; /* error was set */
+ }
+ Py_DECREF(errres); /* we don't need the returned object */
+ return new;
+ }
+
+ if (prec == 0) {
+ new = _new_decimalobj(self->ob_size+1, self->sign, self->exp);
+ if (!new) return NULL;
+ new->digits[0] = 0;
+ for (i = 1; i < new->ob_size; i++)
+ new->digits[i] = self->digits[i-1];
+ prec = 1;
+ } else if (prec < 0) {
+ new = _new_decimalobj(2, self->sign,
+ self->exp + self->ob_size - prec - 1);
+ if (!new) return NULL;
+ new->digits[0] = 0;
+ new->digits[1] = 1;
+ prec = 1;
+ } else {
+ new = decimal_copy(self);
+ if (!new) return NULL;
+ }
+
+ expdiff = prec - new->ob_size;
+ if (expdiff == 0)
+ return new;
+ else if (expdiff > 0) {
+ /* we need to extend precision */
+ new2 = _new_decimalobj(prec, new->sign, new->exp - expdiff);
+ if (!new2) {
+ Py_DECREF(new);
+ return NULL;
+ }
+ for (i = 0; i < new->ob_size; i++) {
+ new2->digits[i] = new->digits[i];
+ }
+ for (i = new->ob_size; i < new2->ob_size; i++) {
+ new2->digits[i] = 0;
+ }
+ Py_DECREF(new);
+ return new2;
+ }
+
+ /* Maybe all the lost digits are 0. */
+ for (i = expdiff; i < self->ob_size; i++) {
+ if (self->digits[i] > 0)
+ goto no_way;
+ }
+ /* All lost digits are 0. */
+ new2 = _new_decimalobj(prec, new->sign, new->exp - expdiff);
+ if (!new2) {
+ Py_DECREF(new);
+ return NULL;
+ }
+ for (i = 0; i < new2->ob_size; i++)
+ new2->digits[i] = new->digits[i];
+ Py_DECREF(new);
+ errres = context_raise_error(ctx, S_ROUNDED, NULL, NULL);
+ if (!errres) {
+ Py_DECREF(new2);
+ return NULL;
+ }
+ Py_DECREF(errres);
+ return new2;
+
+no_way:
+ /* Now rounding starts. */
+ rnd_func = round_funcs[rounding];
+
+
}
/* Default values: rounding=-1 (use context), watchexp=1 */
@@ -257,9 +406,9 @@
_decimal_rescale(decimalobject *self, long exp, contextobject *ctx,
int rounding, int watchexp)
{
- decimalobject *ans = NULL;
+ decimalobject *ans = NULL, *tmp, *tmp2;
int ret;
- long diff;
+ long diff, adj;
Py_ssize_t digits, i;
if (ISSPECIAL(self)) {
@@ -276,7 +425,7 @@
if (!decimal_nonzero(self)) {
ans = _new_decimalobj(1, self->sign, exp);
- if (!ans)
+ if (!ans)
return NULL;
ans->digits[0] = 0;
return ans;
@@ -289,20 +438,54 @@
return context_raise_error(ctx, S_INV_OPERATION, "Rescale > prec", NULL);
digits += 1;
- ans = _new_decimalobj(self->ob_size+1, self->sign, self->exp);
- if (!ans)
- return NULL;
- for (i = 0; i < self->ob_size; i++)
- ans->digits[i+1] = self->digits[i];
- ans->digits[0] = 0;
-
if (digits < 0) {
- ans->exp = -digits + ans->exp;
- /* XXX: not complete... */
+ ans = _new_decimalobj(2, self->sign, self->exp - digits);
+ if (!ans)
+ return NULL;
+ ans->digits[0] = 0;
+ ans->digits[1] = 1;
+ digits = 1;
+ } else {
+ ans = _new_decimalobj(self->ob_size+1, self->sign, self->exp);
+ if (!ans)
+ return NULL;
+ for (i = 0; i < self->ob_size; i++)
+ ans->digits[i+1] = self->digits[i];
+ ans->digits[0] = 0;
}
-
+ tmp = _decimal_round(ans, digits, ctx, rounding);
+ Py_DECREF(ans);
+ if (!tmp)
+ return NULL;
+ if (tmp->digits[0] == 0 && tmp->ob_size > 1) {
+ tmp2 = _new_decimalobj(tmp->ob_size-1, tmp->sign, tmp->exp);
+ if (!tmp2) {
+ Py_DECREF(tmp);
+ return NULL;
+ }
+ for (i = 1; i < tmp->ob_size; i++)
+ tmp2->digits[i] = tmp->digits[i];
+ Py_DECREF(tmp);
+ tmp = tmp2;
+ }
+ tmp->exp = exp;
+
+ adj = ADJUSTED(tmp);
+ if (decimal_nonzero(tmp)) {
+ if (adj < ctx->Emin) {
+ ans = context_raise_error(ctx, S_SUBNORMAL, NULL, NULL);
+ Py_DECREF(tmp);
+ return ans;
+ } else if (adj > ctx->Emax) {
+ ans = context_raise_error(ctx, S_INV_OPERATION,
+ "rescale(a, INF)", NULL);
+ Py_DECREF(tmp);
+ return ans;
+ }
+ }
+ return tmp;
}
/* Fix the exponents and return a copy with the exponents in bounds.
@@ -443,35 +626,142 @@
{ return NULL; } \
if (ctx == NULL) { \
if (!(ctx = getcontext())) return NULL; \
+ } else if (!PyDecimalContext_Check(ctx)) { \
+ PyErr_SetString(PyExc_TypeError, "context must be a Context object"); \
+ return NULL; \
}
STUB(compare)
STUB(max)
STUB(min)
-static PyObject *
+static decimalobject *
decimal_normalize(decimalobject *self, PyObject *args, PyObject *kwds)
{
- decimalobject *dup;
+ decimalobject *dup, *new;
contextobject *ctx = NULL;
+ Py_ssize_t end, i;
+ long exp;
PARSECONTEXT("normalize");
if (ISSPECIAL(self)) {
decimalobject *nan = NULL;
int res;
res = _check_nans(self, NULL, ctx, &nan);
- /* if error set or NaN returned, return */
- if (res != 0) return (PyObject *)nan;
+ if (res != 0) return nan; /* can be NULL on error */
}
dup = _decimal_fix(self, ctx);
+ if (ISINF(dup))
+ return dup;
+
+ if (!decimal_nonzero(dup)) {
+ new = _new_decimalobj(1, dup->sign, 0);
+ Py_DECREF(dup);
+ if (!new) return NULL;
+ new->digits[0] = 0;
+ return new;
+ }
+
+ end = dup->ob_size;
+ exp = dup->exp;
+ while (dup->digits[end-1] == 0) {
+ end--;
+ exp++;
+ }
+ new = _new_decimalobj(end, dup->sign, exp);
+ if (!new) {
+ Py_DECREF(dup);
+ return NULL;
+ }
+ for (i = 0; i < end; i++)
+ new->digits[i] = dup->digits[i];
+ Py_DECREF(dup);
+ return new;
+
+}
- /* XXX: incomplete */
+static decimalobject *
+decimal_quantize(decimalobject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"exp", "rounding", "context", "watchexp", 0};
+ contextobject *ctx = NULL;
+ decimalobject *other = NULL;
+ int rounding = -1, watchexp = 1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iOi:quantize", kwlist,
+ &other, &rounding, &ctx, &watchexp))
+ return NULL;
+
+ if (ctx == NULL) {
+ if (!(ctx = getcontext()))
+ return NULL;
+ } else if (!PyDecimalContext_Check(ctx)) {
+ PyErr_SetString(PyExc_TypeError, "context must be a Context object");
+ return NULL;
+ }
+ if (!PyDecimal_Check(other)) {
+ PyErr_SetString(PyExc_TypeError, "exp must be a Decimal object");
+ return NULL;
+ }
+ if (ISSPECIAL(self) || ISSPECIAL(other)) {
+ decimalobject *nan = NULL;
+ int res;
+ res = _check_nans(self, other, ctx, &nan);
+ if (res != 0) return nan; /* can be NULL on error */
+
+ if (ISINF(self) || ISINF(other)) {
+ if (ISINF(self) && ISINF(other)) {
+ Py_INCREF(self);
+ return self;
+ }
+ return context_raise_error(ctx, S_INV_OPERATION,
+ "quantize with one INF", NULL);
+ }
+ }
+ return _decimal_rescale(self, other->exp, ctx, rounding, watchexp);
}
-STUB(quantize)
+
STUB(remainder_near)
-STUB(same_quantum)
+
+static PyObject *
+decimal_same_quantum(decimalobject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"other", 0};
+ decimalobject *other = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:same_quantum", kwlist,
+ &other))
+ return NULL;
+
+ if (!PyDecimal_Check(other)) {
+ PyErr_SetString(PyExc_TypeError, "other must be a Decimal object");
+ return NULL;
+ }
+
+ if (ISSPECIAL(self) && ISSPECIAL(other)) {
+ if (GETNAN(self) || GETNAN(other)) {
+ if (GETNAN(self) && GETNAN(other))
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+ if (ISINF(self) || ISINF(other)) {
+ if (ISINF(self) && ISINF(other))
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+ }
+
+ if (self->exp == other->exp)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
STUB(sqrt)
STUB(to_eng_string)
STUB(to_integral)
@@ -695,7 +985,7 @@
char literalsign = 0, sign = 0;
decimalobject *new;
Py_ssize_t size = 0, i;
- char *start, *p;
+ char *start = NULL, *p;
if (len < 3)
return NULL;
@@ -908,7 +1198,7 @@
PyObject *
PyDecimal_FromSequence(PyObject *seq)
{
- decimalobject *new;
+ decimalobject *new = NULL;
PyObject *tup, *digits, *digtup = NULL, *item;
int sign;
long exp;
@@ -1123,7 +1413,7 @@
tmp2 = PyTuple_New(0);
if (!tmp2)
return -1;
- tmp = decimal_normalize(d, tmp2, NULL);
+ tmp = (PyObject *)decimal_normalize(d, tmp2, NULL);
Py_DECREF(tmp2);
if (!tmp)
return -1;
More information about the Python-checkins
mailing list