[gcalctool] Got complex arithmetic working



commit 02ce7836f9c7d013bc2ded79aaef86617855b2fa
Author: Robert Ancell <robert ancell gmail com>
Date:   Mon May 17 17:01:47 2010 +1000

    Got complex arithmetic working

 src/gcalctool.c        |    2 +-
 src/mp-convert.c       |   41 +++--
 src/mp-equation.c      |    5 +-
 src/mp-internal.h      |    2 +
 src/mp-trigonometric.c |    4 +-
 src/mp.c               |  455 ++++++++++++++++++++++++++----------------------
 src/mp.h               |    6 +-
 src/unittest.c         |   27 +++-
 8 files changed, 305 insertions(+), 237 deletions(-)
---
diff --git a/src/gcalctool.c b/src/gcalctool.c
index 1eed178..6de9e4c 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -329,7 +329,7 @@ main(int argc, char **argv)
     int accuracy = 9, word_size = 64, base = 10;
     gboolean show_tsep = FALSE, show_zeroes = FALSE;
     gchar *number_format, *angle_units, *button_mode;
-  
+
     g_type_init();
 
     bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
diff --git a/src/mp-convert.c b/src/mp-convert.c
index c57ee9e..e824fb5 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -40,7 +40,7 @@ mp_set_from_float(float rx, MPNumber *z)
     int i, k, ib, ie, tp;
     float rj;
 
-    memset(z, 0, sizeof(MPNumber));
+    mp_set_from_integer(0, z);
 
     /* CHECK SIGN */
     if (rx < 0.0f) {
@@ -113,7 +113,7 @@ mp_set_from_double(double dx, MPNumber *z)
     int i, k, ib, ie, tp;
     double dj;
 
-    memset(z, 0, sizeof(MPNumber));
+    mp_set_from_integer(0, z);
 
     /* CHECK SIGN */
     if (dx < 0.0)  {
@@ -196,8 +196,8 @@ mp_set_from_integer(int64_t x, MPNumber *z)
 
     while (x != 0) {
         z->fraction[z->exponent] = x % MP_BASE;
-        x = x / MP_BASE;
         z->exponent++;
+        x /= MP_BASE;
     }
     for (i = 0; i < z->exponent / 2; i++) {
         int t = z->fraction[i];
@@ -212,7 +212,7 @@ mp_set_from_unsigned_integer(uint64_t x, MPNumber *z)
 {
     int i;
 
-    memset(z, 0, sizeof(MPNumber));
+    mp_set_from_integer(0, z);
 
     if (x == 0) {
         z->sign = 0;
@@ -269,13 +269,15 @@ mp_set_from_polar(const MPNumber *r, MPAngleUnit unit, const MPNumber *theta, MP
 void
 mp_set_from_complex(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
-    //MPNumber i;
+    /* NOTE: Do imaginary component first as z may be x or y */
+    z->im_sign = y->sign;
+    z->im_exponent = y->exponent;
+    memcpy(z->im_fraction, y->fraction, sizeof(int) * MP_SIZE);
 
-    // FIXME: There is some corruption here as i is currently defined to zero but the result does not work
-    //mp_get_i(&i);
-    //mp_multiply(y, &i, z);
-    //mp_add(x, z, z);
-    mp_set_from_mp(x, z);
+    z->sign = x->sign;
+    z->exponent = x->exponent;
+    if (z != x)
+        memcpy(z->fraction, x->fraction, sizeof(int) * MP_SIZE);
 }
 
 
@@ -568,7 +570,7 @@ mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accura
         g_string_truncate(string, last_non_zero);
 
     /* Add sign on non-zero values */
-    if (strcmp(string->str, "0") != 0) {
+    if (strcmp(string->str, "0") != 0 || force_sign) {
         if (mp_is_negative(x))
             g_string_prepend(string, "â??");
         else if (force_sign)
@@ -597,22 +599,23 @@ mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accura
 void
 mp_cast_to_string(const MPNumber *x, int default_base, int base, int accuracy, bool trim_zeroes, char *buffer, int buffer_length)
 {
-    MPNumber x_real, x_im;
     GString *string;
+    MPNumber x_real;
 
     string = g_string_sized_new(buffer_length);
 
     mp_real_component(x, &x_real);
-    mp_imaginary_component(x, &x_im);
-
     mp_cast_to_string_real(&x_real, default_base, base, accuracy, trim_zeroes, FALSE, string);
     if (mp_is_complex(x)) {
         GString *s;
         gboolean force_sign = TRUE;
-        
+        MPNumber x_im;
+
+        mp_imaginary_component(x, &x_im);
+
         if (strcmp(string->str, "0") == 0) {
             g_string_assign(string, "");
-            force_sign = FALSE;
+            force_sign = false;
         }
 
         s = g_string_sized_new(buffer_length);
@@ -627,7 +630,11 @@ mp_cast_to_string(const MPNumber *x, int default_base, int base, int accuracy, b
             g_string_append(string, "â??i");
         }
         else {
-            g_string_append(string, s->str);
+            if (strcmp(s->str, "+0") == 0)
+                g_string_append(string, "+");
+            else if (strcmp(s->str, "0") != 0)
+                g_string_append(string, s->str);
+
             g_string_append(string, "i");
         }
         g_string_free(s, TRUE);
diff --git a/src/mp-equation.c b/src/mp-equation.c
index 89fcdf3..6bdce64 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -61,7 +61,7 @@ static void
 set_variable(MPEquationParserState *state, const char *name, const MPNumber *x)
 {
     // Reserved words, e, Ï?, mod, and, or, xor, not, abs, log, ln, sqrt, int, frac, sin, cos, ...
-    if (strcmp(name, "e") == 0 || strcmp(name, "Ï?") == 0)
+    if (strcmp(name, "e") == 0 || strcmp(name, "i") == 0 || strcmp(name, "Ï?") == 0)
         return; // FALSE
 
     if (state->options->set_variable)
@@ -129,6 +129,7 @@ function_is_defined(MPEquationParserState *state, const char *name)
         strcmp(lower_name, "ln") == 0 ||
         strcmp(lower_name, "sqrt") == 0 ||
         strcmp(lower_name, "abs") == 0 ||
+        strcmp(lower_name, "arg") == 0 ||
         strcmp(lower_name, "conj") == 0 ||
         strcmp(lower_name, "int") == 0 ||
         strcmp(lower_name, "frac") == 0 ||
@@ -181,6 +182,8 @@ get_function(MPEquationParserState *state, const char *name, const MPNumber *x,
         mp_sqrt(x, z);
     else if (strcmp(lower_name, "abs") == 0) // |x|
         mp_abs(x, z);
+    else if (strcmp(lower_name, "arg") == 0)
+        mp_arg(x, state->options->angle_units, z);
     else if (strcmp(lower_name, "conj") == 0)
         mp_conjugate(x, z);
     else if (strcmp(lower_name, "int") == 0)
diff --git a/src/mp-internal.h b/src/mp-internal.h
index a441a8b..78d1b31 100644
--- a/src/mp-internal.h
+++ b/src/mp-internal.h
@@ -41,5 +41,7 @@
 void mperr(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void mp_gcd(int64_t *, int64_t *);
 void mp_normalize(MPNumber *);
+void convert_to_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
+void convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
 #endif /* MP_INTERNAL_H */
diff --git a/src/mp-trigonometric.c b/src/mp-trigonometric.c
index 95989ad..985475d 100644
--- a/src/mp-trigonometric.c
+++ b/src/mp-trigonometric.c
@@ -35,7 +35,7 @@ mp_compare_mp_to_int(const MPNumber *x, int i)
 
 
 /* Convert x to radians */
-static void
+void
 convert_to_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber t1, t2;
@@ -68,7 +68,7 @@ mp_get_pi(MPNumber *z)
 }
 
 
-static void
+void
 convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber t1, t2;
diff --git a/src/mp.c b/src/mp.c
index 320c3b2..f8582a4 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -106,13 +106,13 @@ mp_get_eulers(MPNumber *z)
 }
 
 
-void mp_get_i(MPNumber *z)
+void
+mp_get_i(MPNumber *z)
 {
     mp_set_from_integer(0, z);
-    //memset(z, 0, sizeof(MPNumber));
-    //z->im_sign = 1;
-    //z->im_exponent = 1;
-    //z->im_fraction[0] = 1;
+    z->im_sign = 1;
+    z->im_exponent = 1;
+    z->im_fraction[0] = 1;
 }
 
 
@@ -121,8 +121,10 @@ mp_abs(const MPNumber *x, MPNumber *z)
 {
     if (mp_is_complex(x)){
         MPNumber x_real, x_im;
+
         mp_real_component(x, &x_real);
         mp_imaginary_component(x, &x_im);
+
         mp_multiply(&x_real, &x_real, &x_real);
         mp_multiply(&x_im, &x_im, &x_im);
         mp_add(&x_real, &x_im, z);
@@ -140,26 +142,34 @@ void
 mp_arg(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber x_real, x_im, t;
-    
+    bool invert;
+
+    if (mp_is_zero(x)) {
+        /* Translators: Error display when attempting to take argument of zero */
+        mperr(_("Argument not defined for zero"));
+        mp_set_from_integer(0, z);
+        return;
+    }
+
     mp_real_component(x, &x_real);
     mp_imaginary_component(x, &x_im);
 
     if (mp_is_zero(&x_real)) {
         mp_get_pi(z);
+        convert_from_radians(z, unit, z);
         mp_divide_integer(z, 2, z);
-        if (mp_is_negative(&x_im)){
-            mp_get_pi(&t);
-            mp_add(z, &t, z);
-        }
+        invert = mp_is_negative(&x_im);
     }
     else {
         mp_divide(&x_im, &x_real, &t);
-        mp_atan(&t, MP_RADIANS, z);
-
-        if (mp_is_negative(&x_real)) {
-            mp_get_pi(&t);
-            mp_add(z, &t, z);
-        }
+        mp_atan(&t, unit, z);
+        invert = mp_is_negative(&x_real);
+    }
+  
+    if (invert) {
+        mp_get_pi(&t);
+        convert_from_radians(&t, unit, &t);
+        mp_add(z, &t, z);
     }
 }
 
@@ -168,7 +178,7 @@ void
 mp_conjugate(const MPNumber *x, MPNumber *z)
 {
     mp_set_from_mp(x, z);
-    //z->im_sign = -z->im_sign;
+    z->im_sign = -z->im_sign;
 }
 
 
@@ -176,102 +186,105 @@ void
 mp_real_component(const MPNumber *x, MPNumber *z)
 {
     mp_set_from_mp(x, z);
-    //z->im_sign = 0;
-    //z->im_exponent = 0;
-    //memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
+
+    /* Clear imaginary component */
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
 }
 
 
 void
 mp_imaginary_component(const MPNumber *x, MPNumber *z)
 {
-    mp_set_from_integer(0, z);
-    //mp_set_from_mp(x, z);
-    //z->sign = z->im_sign;
-    //z->exponent = z->im_exponent;
-    //memcpy(z->fraction, z->im_fraction, sizeof(int) * MP_SIZE);
-    //z->im_sign = 0;
-    //z->im_exponent = 0;
-    //memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
+    /* Copy imaginary component to real component */
+    z->sign = x->im_sign;
+    z->exponent = x->im_exponent;
+    memcpy(z->fraction, x->im_fraction, sizeof(int) * MP_SIZE);
+  
+    /* Clear (old) imaginary component */   
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
 }
 
 
 static void
-mp_add_real(int x_sign, int x_exponent, const int *x_fraction,
-            int y_sign, int y_exponent, const int *y_fraction,
-            int *z_sign, int *z_exponent, int *z_fraction)
+mp_add_real(const MPNumber *x, int y_sign, const MPNumber *y, MPNumber *z)
 {
     int sign_prod, i, c;
     int exp_diff, med;
-    int x_largest = 0;
+    bool x_largest = false;
     const int *big_fraction, *small_fraction;
-    
-    if (x_sign == 0) {
-        *z_sign = y_sign;
-        *z_exponent = y_exponent;
-        memcpy(z_fraction, y_fraction, sizeof(int) * MP_SIZE);
+    MPNumber x_copy, y_copy;
+
+    /* 0 + y = y */
+    if (mp_is_zero(x)) {
+        mp_set_from_mp(y, z);
+        z->sign = y_sign;
         return;
     }
-    else if (y_sign == 0) {
-        *z_sign = x_sign;
-        *z_exponent = x_exponent;
-        memcpy(z_fraction, x_fraction, sizeof(int) * MP_SIZE);
+    /* x + 0 = x */ 
+    else if (mp_is_zero(y)) {
+        mp_set_from_mp(x, z);
         return;
     }
 
-    sign_prod = y_sign * x_sign;
-    exp_diff = x_exponent - y_exponent;
+    sign_prod = y_sign * x->sign;
+    exp_diff = x->exponent - y->exponent;
     med = abs(exp_diff);
     if (exp_diff < 0) {
-        x_largest = 0;
+        x_largest = false;
     } else if (exp_diff > 0) {
-        x_largest = 1;
+        x_largest = true;
     } else {
         /* EXPONENTS EQUAL SO COMPARE SIGNS, THEN FRACTIONS IF NEC. */
         if (sign_prod < 0) {
             /* Signs are not equal.  find out which mantissa is larger. */
             int j;
             for (j = 0; j < MP_T; j++) {
-                int i = x_fraction[j] - y_fraction[j];
+                int i = x->fraction[j] - y->fraction[j];
                 if (i == 0)
                     continue;
                 if (i < 0)
-                    x_largest = 0;
+                    x_largest = false;
                 else if (i > 0)
-                    x_largest = 1;
+                    x_largest = true;
                 break;
             }
 
             /* Both mantissas equal, so result is zero. */
             if (j >= MP_T) {
-                *z_sign = 0;
-                *z_exponent = 0;
-                memset(z_fraction, 0, sizeof(int) * MP_SIZE);
+                mp_set_from_integer(0, z);
                 return;
             }
         }
     }
 
+    mp_set_from_mp(x, &x_copy);
+    mp_set_from_mp(y, &y_copy);
+    mp_set_from_integer(0, z);
+
     if (x_largest) {
-        *z_sign = x_sign;
-        *z_exponent = x_exponent;
-        big_fraction = x_fraction;
-        small_fraction = y_fraction;
+        z->sign = x_copy.sign;
+        z->exponent = x_copy.exponent;
+        big_fraction = x_copy.fraction;
+        small_fraction = y_copy.fraction;
     } else {
-        *z_sign = y_sign;
-        *z_exponent = y_exponent;
-        big_fraction = y_fraction;
-        small_fraction = x_fraction;
+        z->sign = y_sign;
+        z->exponent = y_copy.exponent;
+        big_fraction = y_copy.fraction;
+        small_fraction = x_copy.fraction;
     }
 
     /* CLEAR GUARD DIGITS TO RIGHT OF X DIGITS */
     for(i = 3; i >= med; i--)
-        z_fraction[MP_T + i] = 0;
+        z->fraction[MP_T + i] = 0;
 
     if (sign_prod >= 0) {
         /* HERE DO ADDITION, EXPONENT(Y) >= EXPONENT(X) */
         for (i = MP_T + 3; i >= MP_T; i--)
-            z_fraction[i] = small_fraction[i - med];
+            z->fraction[i] = small_fraction[i - med];
 
         c = 0;
         for (; i >= med; i--) {
@@ -279,11 +292,11 @@ mp_add_real(int x_sign, int x_exponent, const int *x_fraction,
 
             if (c < MP_BASE) {
                 /* NO CARRY GENERATED HERE */
-                z_fraction[i] = c;
+                z->fraction[i] = c;
                 c = 0;
             } else {
                 /* CARRY GENERATED HERE */
-                z_fraction[i] = c - MP_BASE;
+                z->fraction[i] = c - MP_BASE;
                 c = 1;
             }
         }
@@ -292,92 +305,104 @@ mp_add_real(int x_sign, int x_exponent, const int *x_fraction,
         {
             c = big_fraction[i] + c;
             if (c < MP_BASE) {
-                z_fraction[i] = c;
+                z->fraction[i] = c;
                 i--;
 
                 /* NO CARRY POSSIBLE HERE */
                 for (; i >= 0; i--)
-                    z_fraction[i] = big_fraction[i];
+                    z->fraction[i] = big_fraction[i];
 
-                return;
+                c = 0;
+                break;
             }
 
-            z_fraction[i] = 0;
+            z->fraction[i] = 0;
             c = 1;
         }
 
         /* MUST SHIFT RIGHT HERE AS CARRY OFF END */
         if (c != 0) {
             for (i = MP_T + 3; i > 0; i--)
-                z_fraction[i] = z_fraction[i - 1];
-            z_fraction[0] = 1;
-            (*z_exponent)++;
+                z->fraction[i] = z->fraction[i - 1];
+            z->fraction[0] = 1;
+            z->exponent++;
         }
-
-        return;
     }
-
-    c = 0;
-    for (i = MP_T + med - 1; i >= MP_T; i--) {
-        /* HERE DO SUBTRACTION, ABS(Y) > ABS(X) */
-        z_fraction[i] = c - small_fraction[i - med];
+    else  {
         c = 0;
+        for (i = MP_T + med - 1; i >= MP_T; i--) {
+            /* HERE DO SUBTRACTION, ABS(Y) > ABS(X) */
+            z->fraction[i] = c - small_fraction[i - med];
+            c = 0;
 
-        /* BORROW GENERATED HERE */
-        if (z_fraction[i] < 0) {
-            c = -1;
-            z_fraction[i] += MP_BASE;
+            /* BORROW GENERATED HERE */
+            if (z->fraction[i] < 0) {
+                c = -1;
+                z->fraction[i] += MP_BASE;
+            }
         }
-    }
 
-    for(; i >= med; i--) {
-        c = big_fraction[i] + c - small_fraction[i - med];
-        if (c >= 0) {
-            /* NO BORROW GENERATED HERE */
-            z_fraction[i] = c;
-            c = 0;
-        } else {
-            /* BORROW GENERATED HERE */
-            z_fraction[i] = c + MP_BASE;
+        for(; i >= med; i--) {
+            c = big_fraction[i] + c - small_fraction[i - med];
+            if (c >= 0) {
+                /* NO BORROW GENERATED HERE */
+                z->fraction[i] = c;
+                c = 0;
+            } else {
+                /* BORROW GENERATED HERE */
+                z->fraction[i] = c + MP_BASE;
+                c = -1;
+            }
+        }
+
+        for (; i >= 0; i--) {
+            c = big_fraction[i] + c;
+
+            if (c >= 0) {
+                z->fraction[i] = c;
+                i--;
+
+                /* NO CARRY POSSIBLE HERE */
+                for (; i >= 0; i--)
+                    z->fraction[i] = big_fraction[i];
+
+                break;
+            }
+
+            z->fraction[i] = c + MP_BASE;
             c = -1;
         }
     }
 
-    for (; i >= 0; i--) {
-        c = big_fraction[i] + c;
+    mp_normalize(z);
+}
 
-        if (c >= 0) {
-            z_fraction[i] = c;
-            i--;
 
-            /* NO CARRY POSSIBLE HERE */
-            for (; i >= 0; i--)
-                z_fraction[i] = big_fraction[i];
+static void
+mp_add_with_sign(const MPNumber *x, int y_sign, const MPNumber *y, MPNumber *z)
+{
+    if (mp_is_complex(x) || mp_is_complex(y)) {
+        MPNumber real_x, real_y, im_x, im_y, real_z, im_z;
 
-            return;
-        }
+        mp_real_component(x, &real_x);
+        mp_imaginary_component(x, &im_x);
+        mp_real_component(y, &real_y);
+        mp_imaginary_component(y, &im_y);
+
+        mp_add_real(&real_x, y_sign * y->sign, &real_y, &real_z);
+        mp_add_real(&im_x, y_sign * y->im_sign, &im_y, &im_z);
 
-        z_fraction[i] = c + MP_BASE;
-        c = -1;
+        mp_set_from_complex(&real_z, &im_z, z);
     }
+    else
+        mp_add_real(x, y_sign * y->sign, y, z);
 }
 
 
 void
 mp_add(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
-    /* 0 + y = y
-     * x + 0 = x */
-    if (mp_is_zero(x))
-        mp_set_from_mp(y, z);
-    else if (mp_is_zero(y))
-        mp_set_from_mp(x, z);
-    else {
-        mp_add_real(x->sign, x->exponent, x->fraction,
-                    y->sign, y->exponent, y->fraction,
-                    &z->sign, &z->exponent, z->fraction);
-        mp_normalize(z);
-    }
+    mp_add_with_sign(x, 1, y, z);
 }
 
 
@@ -402,20 +427,7 @@ mp_add_fraction(const MPNumber *x, int64_t i, int64_t j, MPNumber *y)
 void
 mp_subtract(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
-    /* 0 - y = -y
-     * x - 0 = x */
-    if (mp_is_zero(x)) {
-        mp_set_from_mp(y, z);
-        mp_invert_sign(z, z);
-    }
-    else if (mp_is_zero(y))
-        mp_set_from_mp(x, z);
-    else {
-        mp_add_real(x->sign, x->exponent, x->fraction,
-                    -y->sign, y->exponent, y->fraction,
-                    &z->sign, &z->exponent, z->fraction);
-        mp_normalize(z);
-    }
+    mp_add_with_sign(x, -1, y, z);
 }
 
 
@@ -450,6 +462,10 @@ mp_fractional_component(const MPNumber *x, MPNumber *z)
     }
     if (z->fraction[0] == 0)
         z->sign = 0;
+
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
 }
 
 
@@ -466,7 +482,7 @@ void
 mp_floor(const MPNumber *x, MPNumber *z)
 {
     int i;
-    bool have_fraction = false;
+    bool have_fraction = false, is_negative;
 
     /* Integer component of zero = 0 */
     if (mp_is_zero(x)) {
@@ -480,6 +496,8 @@ mp_floor(const MPNumber *x, MPNumber *z)
         return;
     }
 
+    is_negative = mp_is_negative(x);
+
     /* Clear fraction */
     mp_set_from_mp(x, z);
     for (i = z->exponent; i < MP_SIZE; i++) {
@@ -487,8 +505,11 @@ mp_floor(const MPNumber *x, MPNumber *z)
             have_fraction = true;
         z->fraction[i] = 0;
     }
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);
 
-    if (have_fraction && mp_is_negative(x))
+    if (have_fraction && is_negative)
        mp_add_integer(z, -1, z);
 }
 
@@ -525,7 +546,6 @@ mp_round(const MPNumber *x, MPNumber *z)
         mp_floor(x, z);
     else
         mp_ceiling(x, z);
-
 }
 
 int
@@ -600,10 +620,11 @@ mp_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
 }
 
 
-void
-mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
+static void
+mp_divide_integer_real(const MPNumber *x, int64_t y, MPNumber *z)
 {
     int c, i, k, b2, c2, j1, j2;
+    MPNumber x_copy;
 
     /* x/0 */
     if (y == 0) {
@@ -621,31 +642,24 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
 
     /* Division by -1 or 1 just changes sign */
     if (y == 1 || y == -1) {
-        mp_set_from_mp(x, z);
         if (y < 0)
-            mp_invert_sign(z, z);
-        return;
-    }
-
-    /* If dividing by base then can optimise */
-    if (y % MP_BASE == 0) {
-        mp_set_from_mp(x, z);
-        if (y < 0) {
-            z->sign = -z->sign;
-            z->exponent -= -y / MP_BASE;
-        }
+            mp_invert_sign(x, z);
         else
-            z->exponent -= y / MP_BASE;
+            mp_set_from_mp(x, z);
         return;
     }
 
+    /* Copy x as z may also refer to x */
+    mp_set_from_mp(x, &x_copy);
+    mp_set_from_integer(0, z);
+
     if (y < 0) {
         y = -y;
-        z->sign = -x->sign;
+        z->sign = -x_copy.sign;
     }
     else
-        z->sign = x->sign;
-    z->exponent = x->exponent;
+        z->sign = x_copy.sign;
+    z->exponent = x_copy.exponent;
 
     c = 0;
     i = 0;
@@ -663,7 +677,7 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
         do {
             c = MP_BASE * c;
             if (i < MP_T)
-                c += x->fraction[i];
+                c += x_copy.fraction[i];
             i++;
             r1 = c / y;
             if (r1 < 0)
@@ -678,7 +692,7 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
         if (i < MP_T) {
             kh = MP_T + 1 - i;
             for (k = 1; k < kh; k++) {
-                c += x->fraction[i];
+                c += x_copy.fraction[i];
                 z->fraction[k] = c / y;
                 c = MP_BASE * (c - y * z->fraction[k]);
                 i++;
@@ -694,9 +708,7 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
         if (c < 0)
             goto L210;
 
-        /* NORMALIZE AND ROUND RESULT */
         mp_normalize(z);
-
         return;
     }
 
@@ -708,17 +720,16 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
     c2 = 0;
     do {
         c = MP_BASE * c + c2;
-        c2 = i < MP_T ? x->fraction[i] : 0;
+        c2 = i < MP_T ? x_copy.fraction[i] : 0;
         i++;
     } while (c < j1 || (c == j1 && c2 < j2));
 
     /* COMPUTE T+4 QUOTIENT DIGITS */
     z->exponent += 1 - i;
     i--;
-    k = 1;
 
     /* MAIN LOOP FOR LARGE ABS(y) CASE */
-    while (true) {
+    for (k = 1; k <= MP_T + 4; k++) {
         int ir, iq, iqj;
 
         /* GET APPROXIMATE QUOTIENT FIRST */
@@ -740,7 +751,7 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
         }
 
         if (i < MP_T)
-            iq += x->fraction[i];
+            iq += x_copy.fraction[i];
         i++;
         iqj = iq / y;
 
@@ -750,21 +761,10 @@ mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
 
         if (c < 0)
             goto L210;
-
-        ++k;
-        if (k > MP_T + 4) {
-            mp_normalize(z);
-            
-            if (mp_is_complex(x)) {
-                MPNumber im_z;
-                mp_imaginary_component(x, &im_z);
-                mp_divide_integer(&im_z, y, &im_z);
-                mp_set_from_complex(z, &im_z, z);
-            }
-            return;
-        }
     }
 
+    mp_normalize(z);
+
 L210:
     /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
     mperr("*** INTEGER OVERFLOW IN MP_DIVIDE_INTEGER, B TOO LARGE ***");
@@ -772,6 +772,23 @@ L210:
 }
 
 
+void
+mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z)
+{
+    if (mp_is_complex(x)) {
+        MPNumber re_z, im_z;
+
+        mp_real_component(x, &re_z);
+        mp_imaginary_component(x, &im_z);
+        mp_divide_integer_real(&re_z, y, &re_z);
+        mp_divide_integer_real(&im_z, y, &im_z);
+        mp_set_from_complex(&re_z, &im_z, z);
+    }
+    else
+        mp_divide_integer_real(x, y, z);
+}
+
+
 bool
 mp_is_integer(const MPNumber *x)
 {
@@ -835,7 +852,7 @@ mp_is_natural(const MPNumber *x)
 bool
 mp_is_complex(const MPNumber *x)
 {
-    return false;//x->im_sign != 0;
+    return x->im_sign != 0;
 }
 
 
@@ -998,7 +1015,8 @@ mp_epowy_real(const MPNumber *x, MPNumber *z)
         return;
 
     rz = mp_cast_to_float(z);
-    if ((r__1 = rz - exp(rx), fabs(r__1)) < rz * 0.01f)
+    r__1 = rz - exp(rx);
+    if (fabs(r__1) < rz * 0.01f)
         return;
 
     /*  THE FOLLOWING MESSAGE MAY INDICATE THAT
@@ -1072,7 +1090,7 @@ mp_gcd(int64_t *k, int64_t *l)
 bool
 mp_is_zero(const MPNumber *x)
 {
-    return x->sign == 0; // && x->im_sign == 0;
+    return x->sign == 0 && x->im_sign == 0;
 }
 
 
@@ -1361,6 +1379,11 @@ mp_multiply_real(const MPNumber *x, const MPNumber *y, MPNumber *z)
         }
     }
 
+    /* Clear complex part */
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);    
+
     /* NORMALIZE AND ROUND RESULT */
     // FIXME: Use stack variable because of mp_normalize brokeness
     for (i = 0; i < MP_SIZE; i++)
@@ -1394,7 +1417,7 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
         mp_multiply_real(&real_x, &im_y, &t1);
         mp_multiply_real(&im_x, &real_y, &t2);
         mp_add(&t1, &t2, &im_z);
-        
+
         mp_set_from_complex(&real_z, &im_z, z);
     }
     else {
@@ -1403,10 +1426,11 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
 }
 
 
-void
-mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
+static void
+mp_multiply_integer_real(const MPNumber *x, int64_t y, MPNumber *z)
 {
     int c, i;
+    MPNumber x_copy;
 
     /* x*0 = 0*y = 0 */
     if (mp_is_zero(x) || y == 0) {
@@ -1415,35 +1439,26 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
     }
 
     /* x*1 = x, x*-1 = -x */
-    // FIXME: Why is this not working?
+    // FIXME: Why is this not working? mp_ext is using this function to do a normalization
     /*if (y == 1 || y == -1) {
-        mp_set_from_mp(x, z);
         if (y < 0)
-            mp_invert_sign(z, z);
-        return;
-    }*/
-
-    /* If multiplying by base then can optimise */
-    // FIXME: Very unlikely and doesn't support complex numbers
-    /*if (y % MP_BASE == 0) {
-        mp_set_from_mp(x, z);
-        if (y < 0) {
-            z->sign = -z->sign;
-            z->exponent += -y / MP_BASE;
-        }
+            mp_invert_sign(x, z);
         else
-            z->exponent += y / MP_BASE;
+            mp_set_from_mp(x, z);
         return;
     }*/
 
-    //FIXME: breaks:  mp_set_from_integer(0, z);
+    /* Copy x as z may also refer to x */
+    mp_set_from_mp(x, &x_copy);
+    mp_set_from_integer(0, z);
+
     if (y < 0) {
         y = -y;
-        z->sign = -x->sign;
+        z->sign = -x_copy.sign;
     }
     else
-        z->sign = x->sign;
-    z->exponent = x->exponent + 4;
+        z->sign = x_copy.sign;
+    z->exponent = x_copy.exponent + 4;
 
     /* FORM PRODUCT IN ACCUMULATOR */
     c = 0;
@@ -1454,7 +1469,7 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
 
     /* Computing MAX */
     if (y >= max(MP_BASE << 3, 32767 / MP_BASE)) {
-        int j1, j2;
+        int64_t j1, j2;
 
         /* HERE J IS TOO LARGE FOR SINGLE-PRECISION MULTIPLICATION */
         j1 = y / MP_BASE;
@@ -1462,13 +1477,13 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
 
         /* FORM PRODUCT */
         for (i = MP_T + 3; i >= 0; i--) {
-            int c1, c2, is, ix, t;
+            int64_t c1, c2, is, ix, t;
 
             c1 = c / MP_BASE;
             c2 = c - MP_BASE * c1;
             ix = 0;
             if (i > 3)
-                ix = x->fraction[i - 4];
+                ix = x_copy.fraction[i - 4];
 
             t = j2 * ix + c2;
             is = t / MP_BASE;
@@ -1478,10 +1493,10 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
     }
     else
     {
-        int ri = 0;
+        int64_t ri = 0;
 
         for (i = MP_T + 3; i >= 4; i--) {
-            ri = y * x->fraction[i - 4] + c;
+            ri = y * x_copy.fraction[i - 4] + c;
             c = ri / MP_BASE;
             z->fraction[i] = ri - MP_BASE * c;
         }
@@ -1505,7 +1520,7 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
 
     /* HAVE TO SHIFT RIGHT HERE AS CARRY OFF END */
     while (c != 0) {
-        int t;
+        int64_t t;
 
         for (i = MP_T + 3; i >= 1; i--)
             z->fraction[i] = z->fraction[i - 1];
@@ -1521,14 +1536,26 @@ mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
         return;
     }
 
+    z->im_sign = 0;
+    z->im_exponent = 0;
+    memset(z->im_fraction, 0, sizeof(int) * MP_SIZE);    
     mp_normalize(z);
+}
+
 
+void
+mp_multiply_integer(const MPNumber *x, int64_t y, MPNumber *z)
+{
     if (mp_is_complex(x)) {
-        MPNumber im_z;
+        MPNumber re_z, im_z;
+        mp_real_component(x, &re_z);
         mp_imaginary_component(x, &im_z);
-        mp_multiply_integer(&im_z, y, &im_z);
-        mp_set_from_complex(z, &im_z, z);
+        mp_multiply_integer_real(&re_z, y, &re_z);
+        mp_multiply_integer_real(&im_z, y, &im_z);
+        mp_set_from_complex(&re_z, &im_z, z);
     }
+    else
+        mp_multiply_integer_real(x, y, z);
 }
 
 
@@ -1558,7 +1585,7 @@ mp_invert_sign(const MPNumber *x, MPNumber *z)
 {
     mp_set_from_mp(x, z);
     z->sign = -z->sign;
-    //z->im_sign = -z->im_sign;
+    z->im_sign = -z->im_sign;
 }
 
 
@@ -1811,20 +1838,18 @@ mp_root(const MPNumber *x, int64_t n, MPNumber *z)
 void
 mp_sqrt(const MPNumber *x, MPNumber *z)
 {
-    if (x->sign < 0) {
+    if (mp_is_zero(x))
+        mp_set_from_integer(0, z);
+    else if (x->sign < 0) {
         mperr(_("Square root is undefined for negative values"));
         mp_set_from_integer(0, z);
     }
-    else if (mp_is_zero(x))
-        mp_set_from_integer(0, z);
     else {
-        int i;
         MPNumber t;
 
         mp_root(x, -2, &t);
-        i = t.fraction[0]; // ?
         mp_multiply(x, &t, z);
-        mp_ext(i, z->fraction[0], z);
+        mp_ext(t.fraction[0], z->fraction[0], z);
     }
 }
 
@@ -1917,6 +1942,12 @@ mp_xpowy_integer(const MPNumber *x, int64_t n, MPNumber *z)
         mp_set_from_integer(0, z);
         return;
     }
+  
+    /* x^1 = x */
+    if (n == 1) {
+        mp_set_from_mp(x, z);
+        return;
+    }
 
     if (n < 0) {
         mp_reciprocal(x, &t);
diff --git a/src/mp.h b/src/mp.h
index de9ccf6..64a8664 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -56,13 +56,13 @@
 typedef struct
 {
    /* Sign (+1, -1) or 0 for the value zero */
-   int sign; //, im_sign;
+   int sign, im_sign;
 
    /* Exponent (to base MP_BASE) */
-   int exponent; //, im_exponent;
+   int exponent, im_exponent;
 
    /* Normalized fraction */
-   int fraction[MP_SIZE]; //, im_fraction[MP_SIZE];
+   int fraction[MP_SIZE], im_fraction[MP_SIZE];
 } MPNumber;
 
 typedef enum
diff --git a/src/unittest.c b/src/unittest.c
index 71bee9c..161b4af 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -507,6 +507,31 @@ test_equations()
     options.angle_units = MP_GRADIANS;
     test("sin 100", "1", 0);
 
+    /* Complex numbers */
+    options.angle_units = MP_DEGREES;
+    test("i", "i", 0);
+    test("â??i", "â??i", 0);
+    test("2i", "2i", 0);
+    test("1+i", "1+i", 0);  
+    test("i+1", "1+i", 0);
+    test("1â??i", "1â??i", 0);  
+    test("iâ??1", "â??1+i", 0);
+    test("iÃ?i", "â??1", 0);
+    test("i÷i", "1", 0);
+    test("1÷i", "â??i", 0);
+    test("|i|", "1", 0);
+    test("|3+4i|", "5", 0);
+    test("arg 0", "", PARSER_ERR_MP);  
+    test("arg 1", "0", 0);
+    test("arg (1+i)", "45", 0);
+    test("arg i", "90", 0);
+    test("arg â??1", "180", 0);
+    test("arg â??i", "270", 0);
+    test("iâ?»Â¹", "â??i", 0);
+    //test("â??â??1", "i", 0);
+    //test("i^0.5", "i", 0);
+
+    /* Boolean */
     test("0 and 0", "0", 0);
     test("1 and 0", "0", 0);
     test("0 and 1", "0", 0);
@@ -718,7 +743,7 @@ test_mp()
 
 void
 unittest()
-{
+{    
     test_mp();
     test_numbers();
     test_conversions();



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