[Python-checkins] r51124 - sandbox/trunk/decimal-c/_decimal.c

mateusz.rukowicz python-checkins at python.org
Sun Aug 6 02:24:51 CEST 2006


Author: mateusz.rukowicz
Date: Sun Aug  6 02:24:49 2006
New Revision: 51124

Modified:
   sandbox/trunk/decimal-c/_decimal.c
Log:
Now every function work properly and passes most actual tests (except some powering tests, which cannot be passed - making code passing them, will make it unable to pass others).


Modified: sandbox/trunk/decimal-c/_decimal.c
==============================================================================
--- sandbox/trunk/decimal-c/_decimal.c	(original)
+++ sandbox/trunk/decimal-c/_decimal.c	Sun Aug  6 02:24:49 2006
@@ -1919,14 +1919,52 @@
         ans->limbs[0] = 1;
         digits = 1;
     } else {    /* SLOW */
+        ans = _decimal_get_copy(self);
         ans = _NEW_decimalobj(self->ob_size+1, self->sign, self->exp);
         if (!ans)
             return NULL;
-        for(i=0;i<ans->limb_count;i++)
-            ans->limbs[i] = 0;
-        _limb_first_n_digits(self->limbs, self->ob_size, 0, ans->limbs, ans->ob_size-1);
+        ans->limbs[ans->limb_count-1] = 0;
+        for (i=0 ; i < self->limb_count;i++)
+            ans->limbs[i] = self->limbs[i];
     }
 
+    /* if watchexp, we need to check if after rounding ob_size is still <= prec 
+     * there might be faster and easier solution I cannot see */
+    if (watchexp && digits > ctx->prec) {
+        PyObject *flags;
+        PyObject *r;
+        flags = context_ignore_all_flags(ctx);
+        if (!flags) {
+            Py_DECREF(ans);
+            return NULL;
+        }
+        
+        tmp = _decimal_round(ans, digits, ctx, rounding);
+        if (!tmp) {
+            r = context_regard_flags(ctx, flags);
+            Py_DECREF(flags);
+            Py_XDECREF(r);
+            Py_DECREF(ans);
+            return NULL;
+        }
+        r = context_regard_flags(ctx, flags);
+        Py_DECREF(flags);
+        if (!r) {
+            Py_DECREF(ans);
+            Py_DECREF(tmp);
+            return NULL;
+        }
+        if (_limb_get_digit(tmp->limbs, tmp->ob_size, 0) == 0 && tmp->ob_size > 1)
+            tmp->ob_size --; 
+
+        if (tmp->ob_size > ctx->prec) {
+            Py_DECREF(tmp);
+            Py_DECREF(ans);
+            return handle_InvalidOperation(self->ob_type, ctx,
+                                            "Rescale > prec", NULL);
+        }
+        Py_DECREF(tmp);
+    }
     tmp = _decimal_round(ans, digits, ctx, rounding);
     Py_DECREF(ans);
     if (!tmp)
@@ -4967,62 +5005,68 @@
 }
 DECIMAL_UNARY_FUNC(log10);
 
+
+/* due to some nasty special cases, this code looks quite ugly */
 static int
 _do_real_decimal_comparetotal(decimalobject *self, decimalobject *other, contextobject *ctx) {
     exp_t adj_self;
     exp_t adj_other;
+    /* what should we return when less, greater, equal ie:
+     * when both are > 0 and aren't special then l = -1 g = 1 eq = 0
+     * when both are < 0 and aren't special then l = 1 g = -1 eq = 0
+     * when self is sNaN and other is NaN then l and g are as above, but eq = -1
+     * etc ... */
+    int when_l;         
+    int when_g;
+    int cmp;    /* comparison of abs(self) and abs(other) (remember, abs(NaN50) = 50 ) */
     if (!ctx)
         ctx = getcontext();
     if (!ctx)
         return 0;
+    /* sign is most important */
+    if ((other->sign &1) && !(self->sign&1))
+        return 1;
+    if ((self->sign &1) && !(other->sign&1))
+        return -1;
+    
+    if (self->sign &1) {
+        when_l = 1;
+        when_g = -1;
+    }
+    else {
+        when_l = -1;
+        when_g = 1;
+    }
 
-    if (ISSPECIAL(self) || ISSPECIAL(other)) {
-
-        if (GETNAN(self) || GETNAN(other)) {
-            if (!GETNAN(other))
-                return 1;
-            if (!GETNAN(self))
-                return -1;
-            if ((self->sign &1) && !(other->sign&1))
-                return -1;
-            if ((other->sign&1) && !(self->sign&1))
-                return 1;
-            if (GETNAN(other) == GETNAN(self)) {
-                return 0;
-            }
-
-            
-            if (GETNAN(other) == 2)
-                return (1 ^ self->sign&1) * 2 -1;
-            if (GETNAN(self) == 2)
-                return (0 ^ self->sign&1) * 2 -1;
-        }
-
-        if (ISINF(self) ||  ISINF(other)) {
-            if (ISINF(self) == ISINF(other))
-                return 0;
+    /* abs(nan) always greater than abs(non-nan) */
+    if (GETNAN(self) && !GETNAN(other))
+        return when_g;
+    if (GETNAN(other) && !GETNAN(self))
+        return when_l;
+
+    /* both are nans */
+    if (GETNAN(self)) {
+        /* one is sNaN, and one NaN, in this case, when abs(sNaN) == abs(NaN)
+         * then NaN is greater if both signs are + and is less, if both signs
+         * are - */
+        if (GETNAN(self) != GETNAN(other)) {
+            if (GETNAN(self) == 2) 
+                return when_l;
             else
-                return ISINF(self) > ISINF(other) ? 1 : -1;
+                return when_g;
+                /* now 'add' sign to this */
         }
     }
 
-    if (!decimal_nonzero(self) && !decimal_nonzero(other)) {
-        if ((self->sign&1) && !(other->sign&1))
-            return -1;
-        if ((other->sign&1) && !(self->sign&1))
-            return 1;
-
-        if (exp_eq(self->exp, other->exp))
+    if (ISINF(self) || ISINF(other)) {
+        if (ISINF(self) && ISINF(other))
             return 0;
-        
-        return (((exp_l(other->exp, self->exp) ? 1 : 0) ^ (self->sign&1)) * 2) -1;
+        if (ISINF(self) && !ISINF(other))
+            return when_g;
+        return when_l;
     }
 
-    /* pretty obvious */
-    if ((other->sign &1) && !(self->sign&1))
-        return 1;
-    if ((self->sign &1) && !(other->sign&1))
-        return -1;
+    /* we now know that self->sign == other->sign, and everything is just fine ;P */
 
     adj_self = ADJUSTED(self);
     adj_other = ADJUSTED(other);
@@ -5039,29 +5083,40 @@
             d_s = _limb_get_digit(self->limbs, self->ob_size, i);
             d_o = _limb_get_digit(other->limbs, other->ob_size, i);
             if (d_s != d_o) {
-                ret = d_s > d_o;
-                if (ret ^ (self->sign&1))
-                    return 1;
+                if (d_s > d_o)
+                    cmp = 1;
                 else
-                    return -1;
+                    cmp = -1;
+                break;
             }
         }
 
-        if (exp_eq(self->exp, other->exp)) {
-            return 0;
-        }
-        else if (exp_g(self->exp, other->exp))
-        {
-            return (1 ^ self->sign&1) * 2 -1;
+        /* equal */
+        /* abs(0.0000) > abs(0.0) */
+        if (i == digits) {
+            if (exp_eq(self->exp, other->exp)) {
+                cmp = 0;
+            }
+            else if (exp_g(self->exp, other->exp))
+                cmp = 1;
+            else cmp = -1;
         }
-        else return (0 ^ self->sign&1) * 2 -1;
     }
 
-    if (exp_g(adj_self, adj_other))
-        return (1 ^ self->sign &1) * 2 -1;
+    else if (exp_g(adj_self, adj_other))
+        cmp = 1;
     else 
-        return (0 ^ self->sign &1) * 2 -1;
+        cmp = -1;
     
+
+    switch (cmp) {
+        case 1:  return when_g;
+                 break;
+        case 0:  return 0;
+                 break;
+        case -1: return when_l;
+                 break;
+    }
 }
 
 static decimalobject *


More information about the Python-checkins mailing list