[Python-checkins] r58462 - sandbox/trunk/decimal-c/_decimal.c
mateusz.rukowicz
python-checkins at python.org
Sun Oct 14 23:07:47 CEST 2007
Author: mateusz.rukowicz
Date: Sun Oct 14 23:07:47 2007
New Revision: 58462
Modified:
sandbox/trunk/decimal-c/_decimal.c
Log:
Added 05up rounding. Fixed some issues with NaNs and precision (now NaNs diagnostics are truncated to context precision digits).
Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c (original)
+++ sandbox/trunk/decimal-c/_decimal.c Sun Oct 14 23:07:47 2007
@@ -1157,7 +1157,8 @@
#define ROUND_HALF_UP 4
#define ROUND_FLOOR 5
#define ROUND_CEILING 6
-#define VALID_ROUND(x) ((x) <= ROUND_CEILING && (x) >= ROUND_DOWN)
+#define ROUND_05UP 7
+#define VALID_ROUND(x) ((x) <= ROUND_05UP && (x) >= ROUND_DOWN)
/* for context->rounding_dec */
#define ALWAYS_ROUND 0
@@ -1277,6 +1278,7 @@
static decimalobject *_do_decimal_subtract(decimalobject *, decimalobject *, contextobject *);
static PyObject *context_ignore_flags(contextobject *self, PyObject *args);
static decimalobject *_do_decimal_power(decimalobject *, decimalobject *, decimalobject *, contextobject *);
+static decimalobject *_decimal_fix_nan(decimalobject *self, contextobject *ctx);
static int _decimal_isint(decimalobject*);
/* Exception handlers *********************************************************/
@@ -1306,7 +1308,7 @@
handle_InvalidOperation(PyTypeObject *type, contextobject *ctx,
char *expl, decimalobject *thing)
{
- decimalobject *res;
+ decimalobject *res, *res2;
long sign, i;
HANDLE_ERROR(ctx, S_INV_OPERATION, expl, NULL);
@@ -1320,13 +1322,16 @@
sign = SIGN_NEGNAN;
else
sign = SIGN_POSNAN;
-
+ /* TODO actually, we don't need to call fixnan, but we do in case it will change */
res = _new_decimalobj(type, thing->ob_size, sign, exp_from_i(0));
if (!res) return NULL;
for (i = 0; i< res->limb_count;i++)
res->limbs[i] = thing->limbs[i];
- return res;
+ res2 = _decimal_fix_nan(res, ctx);
+ if(!res2) return NULL;
+ Py_DECREF(res);
+ return res2;
}
static decimalobject *
@@ -1545,14 +1550,11 @@
return -1;
return 1;
}
-
+ /* decimal_fix gives us new reference, no INCREF requiered */
if (nan1)
- *res = x;
+ *res = _decimal_fix_nan(x, ctx);
else
- *res = y;
- /* since handle_InvalidOperation above returns new references, to be
- * consistent we must incref the returns here too. */
- Py_INCREF(*res);
+ *res = _decimal_fix_nan(y, ctx);
return 1;
}
return 0;
@@ -1743,12 +1745,21 @@
return _round_down(self, prec, expdiff, ctx);
}
+/* Round up if digit prec-1 (0 based) is 0 or 5, otherwise round down*/
+static decimalobject *
+_round_05up(decimalobject *self, long prec, exp_t expdiff, contextobject *ctx) {
+ long dig = _limb_get_digit(self->limbs, self->ob_size, prec-1);
+ if(dig == 0 || dig == 5)
+ return _round_up(self, prec, expdiff, ctx);
+ else return _round_down(self, prec, expdiff, ctx);
+}
+
/* Mapping rounding constants to functions. Since in C this can be indexed with
any value, it's important to check the rounding constants before! */
typedef decimalobject*(*round_func)(decimalobject *, long, exp_t, contextobject *);
static round_func round_funcs[] = {
_round_down, _round_up, _round_half_down, _round_half_even,
- _round_half_up, _round_floor, _round_ceiling
+ _round_half_up, _round_floor, _round_ceiling, _round_05up
};
/* default: prec=-1, rounding=-1 (use context values), see the ROUND_* constants */
@@ -2116,12 +2127,35 @@
return NULL;
}
+
+static decimalobject *
+_decimal_fix_nan(decimalobject *self, contextobject *ctx) {
+ long max_diagnostic_len = ctx->prec - ctx->clamp;
+ long limbs = (max_diagnostic_len + LOG - 1) / LOG;
+ int i;
+ if(self->ob_size <= max_diagnostic_len) {
+ Py_INCREF(self);
+ return self;
+ }
+ /* we need to copy first ceil(self->ob_size / LOG) limbs, and set size
+ * because we truncate most significant limbs */
+ decimalobject *ans = _new_decimalobj(self->ob_type, max_diagnostic_len, self->sign, self->exp);
+ if(!ans)
+ return NULL;
+ for(i = 0; i < limbs; i ++) {
+ ans->limbs[i] = self->limbs[i];
+ }
+ return ans;
+}
+
static decimalobject *
_decimal_fix(decimalobject *self, contextobject *ctx)
{
decimalobject *ans = NULL;
if (ISSPECIAL(self)) {
+ if(GETNAN(self))
+ return _decimal_fix_nan(self, ctx);
Py_INCREF(self);
return self;
}
@@ -2144,6 +2178,8 @@
return ans;
}
+//this one cuts off diagnostic information
+
static PyObject *
decimal_fix(decimalobject *self, PyObject *args, PyObject *kwds)
{
@@ -6633,8 +6669,9 @@
return NULL;
finish:
- if (size > ctx->prec)
- return handle_ConversionSyntax(type, ctx, "diagnostic info too long");
+ /* not used anymore */
+/* if (size > ctx->prec)
+ return handle_ConversionSyntax(type, ctx, "diagnostic info too long"); */
new = _new_decimalobj(type, size, sign, exp_from_i(0));
if (!new)
@@ -8297,6 +8334,9 @@
case ROUND_CEILING:
strcat(roundstr, "CEILING");
break;
+ case ROUND_05UP:
+ strcat(roundstr, "05UP");
+ break;
default:
strcpy(roundstr, "None");
}
@@ -8553,19 +8593,21 @@
if (PyString_Check(value)) {
char *buffer = PyString_AS_STRING(value);
if (!strcmp("ROUND_DOWN", buffer))
- new_round = 0;
+ new_round = ROUND_DOWN;
else if (!strcmp("ROUND_UP", buffer))
- new_round = 1;
+ new_round = ROUND_UP;
else if (!strcmp("ROUND_HALF_DOWN", buffer))
- new_round = 2;
+ new_round = ROUND_HALF_DOWN;
else if (!strcmp("ROUND_HALF_EVEN", buffer))
- new_round = 3;
+ new_round = ROUND_HALF_EVEN;
else if (!strcmp("ROUND_HALF_UP", buffer))
- new_round = 4;
+ new_round = ROUND_HALF_UP;
else if (!strcmp("ROUND_FLOOR", buffer))
- new_round = 5;
+ new_round = ROUND_FLOOR;
else if (!strcmp("ROUND_CEILING", buffer))
- new_round = 6;
+ new_round = ROUND_CEILING;
+ else if (!strcmp("ROUND_05UP", buffer))
+ new_round = ROUND_05UP;
}
else if (new_round == -1) {
PyErr_SetString(PyExc_TypeError, "Rounding should be int or string");
@@ -8813,6 +8855,7 @@
ADD_CONST(m, ROUND_HALF_UP);
ADD_CONST(m, ROUND_FLOOR);
ADD_CONST(m, ROUND_CEILING);
+ ADD_CONST(m, ROUND_05UP);
ADD_CONST(m, ALWAYS_ROUND);
ADD_CONST(m, NEVER_ROUND);
More information about the Python-checkins
mailing list