[gcalctool] Tidy up mp.c



commit 2a7cf5225ff75225ee827357335342cae1e2d08c
Author: Robert Ancell <robert ancell gmail com>
Date:   Thu May 7 13:22:24 2009 +1000

    Tidy up mp.c
---
 gcalctool/mp-internal.h |    1 -
 gcalctool/mp.c          |  198 ++++++++++++++++------------------------------
 gcalctool/unittest.c    |    4 +
 3 files changed, 73 insertions(+), 130 deletions(-)

diff --git a/gcalctool/mp-internal.h b/gcalctool/mp-internal.h
index ad8ddfe..8a233fc 100644
--- a/gcalctool/mp-internal.h
+++ b/gcalctool/mp-internal.h
@@ -43,7 +43,6 @@ void mpchk(int i, int j);
 void mpgcd(int *, int *);
 void mpmul2(MPNumber *, int, MPNumber *, int);
 void mp_normalize(MPNumber *, int trunc);
-void mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc);
 void mpexp1(const MPNumber *, MPNumber *);
 void mpmulq(MPNumber *, int, int, MPNumber *);
 void mp_reciprocal(const MPNumber *, MPNumber *);
diff --git a/gcalctool/mp.c b/gcalctool/mp.c
index 3f6ecbe..37375ac 100644
--- a/gcalctool/mp.c
+++ b/gcalctool/mp.c
@@ -28,9 +28,6 @@
 #include "mp-internal.h"
 #include "calctool.h"
 
-/* True if errors should be printed to stderr */
-static int mp_show_errors = 0;
-
 static int mp_compare_mp_to_float(const MPNumber *, float);
 static int pow_ii(int, int);
 
@@ -39,17 +36,9 @@ static int  mpadd3(const MPNumber *, const MPNumber *, int *, int, int);
 static void mpext(int, int, MPNumber *);
 static void mplns(const MPNumber *, MPNumber *);
 static void mpmaxr(MPNumber *);
-static void mpmlp(int *, const int *, int, int);
 static void mpovfl(MPNumber *, const char *);
 static void mpunfl(MPNumber *);
 
-
-void
-mp_set_show_errors(int show_errors)
-{
-    mp_show_errors = show_errors;
-}
-
 /* SETS Y = ABS(X) FOR MP NUMBERS X AND Y */
 void
 mp_abs(const MPNumber *x, MPNumber *y)
@@ -58,8 +47,6 @@ mp_abs(const MPNumber *x, MPNumber *y)
     y->sign = abs(y->sign);
 }
 
-
-
 /*  ADDS X AND Y, FORMING RESULT IN Z, WHERE X, Y AND Z ARE MP
  *  NUMBERS.  FOUR GUARD DIGITS ARE USED, AND THEN R*-ROUNDING.
  */
@@ -91,7 +78,7 @@ mpadd2(const MPNumber *x, const MPNumber *y, MPNumber *z, int y_sign, int trunc)
     }
 
     /* Y = 0 OR NEGLIGIBLE, SO RESULT = X */    
-    if (y_sign == 0  ||  y->sign == 0) {
+    if (y_sign == 0 || y->sign == 0) {
         mp_set_from_mp(x, z);
         return;
     }
@@ -361,7 +348,8 @@ mp_atan1N(int n, MPNumber *z)
 
         /* ADD TO SUM */
         mp_add(&t, z, z);
-        if (t.sign == 0) break;
+        if (t.sign == 0)
+            break;
     }
     MP.t = ts;
 }
@@ -414,15 +402,13 @@ mpcmf(const MPNumber *x, MPNumber *y)
         return;
     }
 
-    /* CLEAR ACCUMULATOR */
+    /* MOVE FRACTIONAL PART OF X TO ACCUMULATOR */
     y->sign = x->sign;
     y->exponent = x->exponent;
     memset(y->fraction, 0, y->exponent*sizeof(int));
-
-    /* MOVE FRACTIONAL PART OF X TO ACCUMULATOR */
-    memcpy (y->fraction + y->exponent, x->fraction + x->exponent,
-            (MP.t - x->exponent)*sizeof(int));
-
+    if (x != y)
+        memcpy(y->fraction + y->exponent, x->fraction + x->exponent,
+               (MP.t - x->exponent)*sizeof(int));
     memset(y->fraction + MP.t, 0, 4*sizeof(int));
 
     /* NORMALIZE RESULT AND RETURN */
@@ -441,9 +427,8 @@ mpcmim(const MPNumber *x, MPNumber *y)
 
     mpchk(1, 4);
     mp_set_from_mp(x, y);
-    if (y->sign == 0) {
+    if (y->sign == 0)
         return;
-    }
 
     /* IF EXPONENT LARGE ENOUGH RETURN Y = X */
     if (y->exponent >= MP.t) {
@@ -591,44 +576,38 @@ mpdivi(const MPNumber *x, int iy, MPNumber *z)
     int c, i, k, b2, c2, i2, j1, j2, r1;
     int j11, kh, iq, ir, iqj;
 
-    z->sign = x->sign;
-
     if (iy == 0) {
         mperr("*** ATTEMPTED DIVISION BY ZERO IN CALL TO MPDIVI ***");
         z->sign = 0;
         return;
     }
 
+    z->sign = x->sign;
     if (iy < 0) {
         iy = -iy;
         z->sign = -z->sign;
     }
-
-    z->exponent = x->exponent;
-
-    /* CHECK FOR ZERO DIVIDEND */
-    if (z->sign == 0) {
-        z->sign = 0;
+    if (z->sign == 0)
         return;
-    }
+    z->exponent = x->exponent;
 
     /* CHECK FOR DIVISION BY B */
     if (iy == MP.b) {
-        mp_set_from_mp(x, z);
-        if (z->exponent <= -MP.m)
+        if (x->exponent <= -MP.m)
         {
             mpunfl(z);
             return;
         }
-        z->sign = z->sign;
-        z->exponent = z->exponent - 1;
+        mp_set_from_mp(x, z);
+        z->exponent--;
         return;
     }
 
     /* CHECK FOR DIVISION BY 1 OR -1 */
     if (iy == 1) {
+        int s = z->sign;
         mp_set_from_mp(x, z);
-        z->sign = z->sign;
+        z->sign = s;
         return;
     }
 
@@ -658,7 +637,7 @@ mpdivi(const MPNumber *x, int iy, MPNumber *z)
         z->exponent += 1 - i;
         z->fraction[0] = r1;
         c = MP.b * (c - iy * r1);
-        kh = 2;
+        kh = 1;
         if (i < MP.t) {
             kh = MP.t + 1 - i;
             for (k = 1; k < kh; k++) {
@@ -669,10 +648,9 @@ mpdivi(const MPNumber *x, int iy, MPNumber *z)
             }
             if (c < 0)
                 goto L210;
-            ++kh;
         }
         
-        for (k = kh - 1; k < i2; k++) {
+        for (k = kh; k < i2; k++) {
             z->fraction[k] = c / iy;
             c = MP.b * (c - iy * z->fraction[k]);
         }
@@ -798,11 +776,9 @@ mperr(const char *format, ...)
     char text[MAXLINE];
     va_list args;
     
-    if (mp_show_errors) {
-        va_start(args, format);
-        vsnprintf(text, MAXLINE, format, args);
-        va_end(args);
-    }
+    va_start(args, format);
+    vsnprintf(text, MAXLINE, format, args);
+    va_end(args);
     doerr(text);
 }
 
@@ -1353,19 +1329,6 @@ mpmaxr(MPNumber *x)
 }
 
 
-/*  PERFORMS INNER MULTIPLICATION LOOP FOR MPMUL
- *  NOTE THAT CARRIES ARE NOT PROPAGATED IN INNER LOOP,
- *  WHICH SAVES TIME AT THE EXPENSE OF SPACE.
- */
-static void
-mpmlp(int *u, const int *v, int w, int j)
-{
-    int i;
-    for (i = 0; i < j; i++)
-        u[i] += w * v[i];
-}
-
-
 /*  MULTIPLIES X AND Y, RETURNING RESULT IN Z, FOR MP X, Y AND Z.
  *  THE SIMPLE O(T**2) ALGORITHM IS USED, WITH
  *  FOUR GUARD DIGITS AND R*-ROUNDING.
@@ -1382,33 +1345,27 @@ mpmlp(int *u, const int *v, int w, int j)
 void
 mpmul(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
-    int i__1;
-    int c, i, j, i2, j1, ri, xi, i2p;
+    int c, i, j, i2, xi;
     MPNumber r;
 
     mpchk(1, 4);
     i2 = MP.t + 4;
-    i2p = i2 + 1;
 
     /* FORM SIGN OF PRODUCT */
-    r.sign = x->sign * y->sign;
-    if (r.sign == 0) {
-        /* SET RESULT TO ZERO */
-        z->sign = 0;
+    z->sign = x->sign * y->sign;
+    if (z->sign == 0)
         return;
-    }
 
     /* FORM EXPONENT OF PRODUCT */
-    r.exponent = x->exponent + y->exponent;
-
+    z->exponent = x->exponent + y->exponent;
+    
     /* CLEAR ACCUMULATOR */
     for (i = 0; i < i2; i++)
         r.fraction[i] = 0;
 
     /* PERFORM MULTIPLICATION */
     c = 8;
-    i__1 = MP.t;
-    for (i = 0; i < i__1; i++) {
+    for (i = 0; i < MP.t; i++) {
         xi = x->fraction[i];
 
         /* FOR SPEED, PUT THE NUMBER WITH MANY ZEROS FIRST */
@@ -1416,8 +1373,9 @@ mpmul(const MPNumber *x, const MPNumber *y, MPNumber *z)
             continue;
 
         /* Computing MIN */
-        mpmlp(&r.fraction[i+1], y->fraction, xi, min(MP.t, i2 - i - 1));
-        --c;
+        for (j = 0; j < min(MP.t, i2 - i - 1); j++)
+            r.fraction[i+j+1] += xi * y->fraction[j];
+        c--;
         if (c > 0)
             continue;
 
@@ -1431,16 +1389,15 @@ mpmul(const MPNumber *x, const MPNumber *y, MPNumber *z)
         /*  PROPAGATE CARRIES AT END AND EVERY EIGHTH TIME,
          *  FASTER THAN DOING IT EVERY TIME.
          */
-        for (j = 1; j <= i2; ++j) {
-            j1 = i2p - j;
-            ri = r.fraction[j1 - 1] + c;
+        for (j = i2 - 1; j >= 0; j--) {
+            int ri = r.fraction[j] + c;
             if (ri < 0) {
                 mperr("*** INTEGER OVERFLOW IN MPMUL, B TOO LARGE ***");
                 z->sign = 0;
                 return;
             }
             c = ri / MP.b;
-            r.fraction[j1 - 1] = ri - MP.b * c;
+            r.fraction[j] = ri - MP.b * c;
         }
         if (c != 0) {
             mperr("*** ILLEGAL BASE B DIGIT IN CALL TO MPMUL, POSSIBLE OVERWRITING PROBLEM ***");
@@ -1458,16 +1415,15 @@ mpmul(const MPNumber *x, const MPNumber *y, MPNumber *z)
         }
     
         c = 0;
-        for (j = 1; j <= i2; ++j) {
-            j1 = i2p - j;
-            ri = r.fraction[j1 - 1] + c;
+        for (j = i2 - 1; j >= 0; j--) {
+            int ri = r.fraction[j] + c;
             if (ri < 0) {
                 mperr("*** INTEGER OVERFLOW IN MPMUL, B TOO LARGE ***");
                 z->sign = 0;
                 return;
             }
             c = ri / MP.b;
-            r.fraction[j1 - 1] = ri - MP.b * c;
+            r.fraction[j] = ri - MP.b * c;
         }
         
         if (c != 0) {
@@ -1478,7 +1434,10 @@ mpmul(const MPNumber *x, const MPNumber *y, MPNumber *z)
     }
 
     /* NORMALIZE AND ROUND RESULT */
-    mp_get_normalized_register(&r, z, 0);
+    // FIXME: I don't know why but using z->fraction directly does not work
+    for (i = 0; i < i2; i++)
+        z->fraction[i] = r.fraction[i];
+    mp_normalize(z, 0);
 }
 
 
@@ -1605,16 +1564,14 @@ mpmul2(MPNumber *x, int iy, MPNumber *z, int trunc)
 }
 
 
-void
-mpmuli(MPNumber *x, int iy, MPNumber *z)
-{
-
 /*  MULTIPLIES MP X BY SINGLE-PRECISION INTEGER IY GIVING MP Z.
  *  THIS IS FASTER THAN USING MPMUL.  RESULT IS ROUNDED.
  *  MULTIPLICATION BY 1 MAY BE USED TO NORMALIZE A NUMBER
  *  EVEN IF THE LAST DIGIT IS B.
  */
-
+void
+mpmuli(MPNumber *x, int iy, MPNumber *z)
+{
     mpmul2(x, iy, z, 0);
 }
 
@@ -1659,12 +1616,6 @@ mp_invert_sign(const MPNumber *x, MPNumber *y)
     y->sign = -y->sign;
 }
 
-void
-mp_normalize(MPNumber *x, int trunc)
-{
-    mp_get_normalized_register(x, x, trunc);
-}
-
 /*  ASSUMES LONG (I.E. (T+4)-DIGIT) FRACTION IN
  *  R, SIGN = REG_SIGN, EXPONENT = REG_EXP.  NORMALIZES,
  *  AND RETURNS MP RESULT IN Z.  INTEGER ARGUMENTS REG_EXP IS
@@ -1672,40 +1623,38 @@ mp_normalize(MPNumber *x, int trunc)
  */
 // FIXME: Is r->fraction large enough?  It seems to be in practise but it may be MP.t+4 instead of MP.t
 void
-mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc)
+mp_normalize(MPNumber *x, int trunc)
 {
     int i__1, i, j, b2, i2, i2m, round;
 
     /* Normalized zero is zero */
-    if (r->sign == 0) {
-        z->sign = 0;
+    if (x->sign == 0)
         return;
-    }
     
     /* CHECK THAT SIGN = +-1 */
-    if (abs(r->sign) > 1) {
-        mperr("*** SIGN NOT 0, +1 OR -1 IN CALL TO MP_GET_NORMALIZED_REGISTER, POSSIBLE OVERWRITING PROBLEM ***");
-        z->sign = 0;
+    if (abs(x->sign) > 1) {
+        mperr("*** SIGN NOT 0, +1 OR -1 IN CALL TO MP_NORMALIZE, POSSIBLE OVERWRITING PROBLEM ***");
+        x->sign = 0;
         return;
     }
 
     i2 = MP.t + 4;
 
     /* Normalize by shifting the fraction to the left */    
-    if (r->fraction[0] == 0) {
+    if (x->fraction[0] == 0) {
         /* Find how many places to shift and detect 0 fraction */
-        for (i = 1; i < i2 && r->fraction[i] == 0; i++);
+        for (i = 1; i < i2 && x->fraction[i] == 0; i++);
         if (i == i2) {
-            z->sign = 0;
+            x->sign = 0;
             return;
         }
         
-        r->exponent -= i;
+        x->exponent -= i;
         i2m = i2 - i;
         for (j = 0; j < i2m; j++)
-            r->fraction[j] = r->fraction[j + i];
+            x->fraction[j] = x->fraction[j + i];
         for (; j < i2; j++)
-            r->fraction[j] = 0;
+            x->fraction[j] = 0;
     }
 
     /* CHECK TO SEE IF TRUNCATION IS DESIRED */
@@ -1718,7 +1667,7 @@ mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc)
             round = 0;
             /* ODD BASE, ROUND IF R(T+1)... > 1/2 */
             for (i = 0; i < 4; i++) {
-                i__1 = r->fraction[MP.t + i] - b2;
+                i__1 = x->fraction[MP.t + i] - b2;
                 if (i__1 < 0)
                     break;
                 else if (i__1 == 0)
@@ -1734,12 +1683,12 @@ mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc)
              *  AFTER R(T+2).
              */
             round = 1;
-            i__1 = r->fraction[MP.t] - b2;
+            i__1 = x->fraction[MP.t] - b2;
             if (i__1 < 0)
                 round = 0;
             else if (i__1 == 0) {
-                if (r->fraction[MP.t - 1] % 2 != 0) {
-                    if (r->fraction[MP.t + 1] + r->fraction[MP.t + 2] + r->fraction[MP.t + 3] == 0) {
+                if (x->fraction[MP.t - 1] % 2 != 0) {
+                    if (x->fraction[MP.t + 1] + x->fraction[MP.t + 2] + x->fraction[MP.t + 3] == 0) {
                         round = 0;
                     }
                 }
@@ -1749,35 +1698,29 @@ mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc)
         /* ROUND */
         if (round) {
             for (j = MP.t - 1; j >= 0; j--) {
-                ++r->fraction[j];
-                if (r->fraction[j] < MP.b)
+                ++x->fraction[j];
+                if (x->fraction[j] < MP.b)
                     break;
-                r->fraction[j] = 0;
+                x->fraction[j] = 0;
             }
 
             /* EXCEPTIONAL CASE, ROUNDED UP TO .10000... */
             if (j < 0) {
-                r->exponent++;
-                r->fraction[0] = 1;
+                x->exponent++;
+                x->fraction[0] = 1;
             }
         }
     }
 
     /* Check for over and underflow */
-    if (r->exponent > MP.m) {
-        mpovfl(z, "*** OVERFLOW OCCURRED IN MP_GET_NORMALIZED_REGISTER ***");
+    if (x->exponent > MP.m) {
+        mpovfl(x, "*** OVERFLOW OCCURRED IN MP_NORMALIZE ***");
         return;
     }
-    if (r->exponent < -MP.m) {
-        mpunfl(z);
+    if (x->exponent < -MP.m) {
+        mpunfl(x);
         return;
     }
-    
-    /* Copy result */
-    z->sign = r->sign;
-    z->exponent = r->exponent;
-    for (i = 0; i < MP.t; i++)
-        z->fraction[i] = r->fraction[i];
 }
 
 
@@ -1793,9 +1736,7 @@ mp_get_normalized_register(MPNumber *r, MPNumber *z, int trunc)
 static void
 mpovfl(MPNumber *x, const char *error)
 {
-    if (mp_show_errors) {
-        fprintf(stderr, "%s\n", error);
-    }
+    fprintf(stderr, "%s\n", error);
     
     mpchk(1, 4);
 
@@ -2355,8 +2296,7 @@ mp_factorial(MPNumber *MPval, MPNumber *MPres)
     mp_set_from_mp(MPval, &MPa);
     mpcmim(MPval, &MP1);
     mp_set_from_integer(0, &MP2);
-    if (mp_is_equal(MPval, &MP1)
-	&& mp_is_greater_equal(MPval, &MP2)) {   /* Only positive integers. */
+    if (mp_is_equal(MPval, &MP1) && mp_is_greater_equal(MPval, &MP2)) {   /* Only positive integers. */
         if (mp_is_equal(&MP1, &MP2)) {    /* Special case for 0! */
             mp_set_from_integer(1, MPres);
             return;
diff --git a/gcalctool/unittest.c b/gcalctool/unittest.c
index d204d0d..ddab647 100644
--- a/gcalctool/unittest.c
+++ b/gcalctool/unittest.c
@@ -93,6 +93,10 @@ test_parser()
     //FIXME: Need to update mperr() test("1/2", "0.5", 0);
     //FIXME: Need to update mperr() test("1/0", "", 0);
     //FIXME: Need to update mperr() test("0/0", "", 0);
+    test("6/3", "2", 0);
+    test("-6/3", "-2", 0);
+    test("6/-3", "-2", 0);
+    test("-6/-3", "2", 0);
     test("2/2", "1", 0);
     test("1203/1", "1203", 0);
     test("-0/32352.689", "0", 0);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]