[gcalctool] More preparation for complex numbers



commit 63588195fee5916196777e2c0f117eeb0303ca99
Author: Robert Ancell <robert ancell gmail com>
Date:   Tue Nov 10 12:58:43 2009 +1100

    More preparation for complex numbers

 src/calctool.c         |    6 +-
 src/mp-convert.c       |  129 +++++++++++++---------
 src/mp-internal.h      |    2 +-
 src/mp-trigonometric.c |    1 +
 src/mp.c               |  288 +++++++++++++++++++++++++-----------------------
 5 files changed, 236 insertions(+), 190 deletions(-)
---
diff --git a/src/calctool.c b/src/calctool.c
index 5238e1a..ce3a653 100644
--- a/src/calctool.c
+++ b/src/calctool.c
@@ -55,7 +55,11 @@ solve(const char *equation)
     options.angle_units = MP_DEGREES;
 
     error = mp_equation_parse(equation, &options, &result, NULL);
-    if(error != 0) {
+    if(error == PARSER_ERR_MP) {
+        fprintf(stderr, "Error: %s\n", mp_get_error());
+        exit(1);
+    }
+    else if(error != 0) {
         fprintf(stderr, "Error: %s\n", mp_error_code_to_string(error));
         exit(1);
     }
diff --git a/src/mp-convert.c b/src/mp-convert.c
index 558a88c..8584999 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -36,18 +36,16 @@ mp_set_from_mp(const MPNumber *x, MPNumber *z)
 void
 mp_set_from_float(float rx, MPNumber *z)
 {
-    int i, k, i2, ib, ie, tp;
-    float rb, rj;
-
-    i2 = MP_T + 4;
+    int i, k, ib, ie, tp;
+    float rj;
 
     memset(z, 0, sizeof(MPNumber));
 
     /* CHECK SIGN */
-    if (rx < (float) 0.0) {
+    if (rx < 0.0f) {
         z->sign = -1;
         rj = -(double)(rx);
-    } else if (rx > (float) 0.0) {
+    } else if (rx > 0.0f) {
         z->sign = 1;
         rj = rx;
     } else {
@@ -56,28 +54,25 @@ mp_set_from_float(float rx, MPNumber *z)
         return;
     }
 
-    ie = 0;
-
     /* INCREASE IE AND DIVIDE RJ BY 16. */
-    while (rj >= (float)1.0) {
+    ie = 0;
+    while (rj >= 1.0f) {
         ++ie;
-        rj *= (float) 0.0625;
+        rj *= 0.0625f;
     }
-
-    while (rj < (float).0625) {
+    while (rj < 0.0625f) {
         --ie;
-        rj *= (float)16.0;
+        rj *= 16.0f;
     }
 
     /*  NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
      *  SET EXPONENT TO 0
      */
     z->exponent = 0;
-    rb = (float) MP_BASE;
 
     /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
-    for (i = 0; i < i2; i++) {
-        rj = rb * rj;
+    for (i = 0; i < MP_T + 4; i++) {
+        rj *= (float) MP_BASE;
         z->fraction[i] = (int) rj;
         rj -= (float) z->fraction[i];
     }
@@ -108,26 +103,22 @@ mp_set_from_float(float rx, MPNumber *z)
             tp = 1;
         }
     }
-
-    return;
 }
 
 
 void
 mp_set_from_double(double dx, MPNumber *z)
 {
-    int i, k, i2, ib, ie, tp;
-    double db, dj;
-
-    i2 = MP_T + 4;
+    int i, k, ib, ie, tp;
+    double dj;
 
     memset(z, 0, sizeof(MPNumber));
 
     /* CHECK SIGN */
-    if (dx < 0.)  {
+    if (dx < 0.0)  {
         z->sign = -1;
         dj = -dx;
-    } else if (dx > 0.)  {
+    } else if (dx > 0.0)  {
         z->sign = 1;
         dj = dx;
     } else {
@@ -140,18 +131,16 @@ mp_set_from_double(double dx, MPNumber *z)
       dj *= 1.0/16.0;
 
     for ( ; dj < 1.0/16.0; ie--)
-      dj *= 16.;
+      dj *= 16.0;
 
     /*  NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
      *  SET EXPONENT TO 0
      */
     z->exponent = 0;
 
-    db = (double) MP_BASE;
-
     /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
-    for (i = 0; i < i2; i++) {
-        dj = db * dj;
+    for (i = 0; i < MP_T + 4; i++) {
+        dj *= (double) MP_BASE;
         z->fraction[i] = (int) dj;
         dj -= (double) z->fraction[i];
     }
@@ -182,8 +171,6 @@ mp_set_from_double(double dx, MPNumber *z)
             tp = 1;
         }
     }
-
-    return;
 }
 
 
@@ -217,7 +204,7 @@ mp_set_from_integer(int x, MPNumber *z)
 void
 mp_set_from_fraction(int i, int j, MPNumber *z)
 {
-    mpgcd(&i, &j);
+    mp_gcd(&i, &j);
 
     if (j == 0) {
         mperr("*** J == 0 IN CALL TO MP_SET_FROM_FRACTION ***\n");
@@ -351,14 +338,13 @@ float
 mp_cast_to_float(const MPNumber *x)
 {
     int i;
-    float rb, rz = 0.0;
+    float rz = 0.0;
 
     if (mp_is_zero(x))
         return 0.0;
 
-    rb = (float) MP_BASE;
     for (i = 0; i < MP_T; i++) {
-        rz = rb * rz + (float)x->fraction[i];
+        rz = (float) MP_BASE * rz + (float)x->fraction[i];
 
         /* CHECK IF FULL SINGLE-PRECISION ACCURACY ATTAINED */
         if (rz + 1.0f <= rz)
@@ -366,7 +352,7 @@ mp_cast_to_float(const MPNumber *x)
     }
 
     /* NOW ALLOW FOR EXPONENT */
-    rz *= mppow_ri(rb, x->exponent - i - 1);
+    rz *= mppow_ri((float) MP_BASE, x->exponent - i - 1);
 
     /* CHECK REASONABLENESS OF RESULT */
     /* LHS SHOULD BE <= 0.5, BUT ALLOW FOR SOME ERROR IN ALOG */
@@ -412,14 +398,13 @@ double
 mp_cast_to_double(const MPNumber *x)
 {
     int i, tm = 0;
-    double d__1, db, dz2, ret_val = 0.0;
+    double d__1, dz2, ret_val = 0.0;
 
     if (mp_is_zero(x))
         return 0.0;
 
-    db = (double) MP_BASE;
     for (i = 0; i < MP_T; i++) {
-        ret_val = db * ret_val + (double) x->fraction[i];
+        ret_val = (double) MP_BASE * ret_val + (double) x->fraction[i];
         tm = i;
 
         /* CHECK IF FULL DOUBLE-PRECISION ACCURACY ATTAINED */
@@ -433,7 +418,7 @@ mp_cast_to_double(const MPNumber *x)
     }
 
     /* NOW ALLOW FOR EXPONENT */
-    ret_val *= mppow_di(db, x->exponent - tm - 1);
+    ret_val *= mppow_di((double) MP_BASE, x->exponent - tm - 1);
 
     /* CHECK REASONABLENESS OF RESULT. */
     /* LHS SHOULD BE .LE. 0.5 BUT ALLOW FOR SOME ERROR IN DLOG */
@@ -455,15 +440,12 @@ mp_cast_to_double(const MPNumber *x)
 }
 
 
-void
-mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, char *buffer, int buffer_length)
+static void
+mp_cast_to_string_real(const MPNumber *x, int base, int accuracy, int trim_zeroes, int force_sign, GString *string)
 {
     static char digits[] = "0123456789ABCDEF";
-    MPNumber number, integer_component, fractional_component, MPbase, temp;
+    MPNumber number, integer_component, fractional_component, temp;
     int i, last_non_zero;
-    GString *string;
-
-    string = g_string_sized_new(buffer_length);
 
     if (mp_is_negative(x))
         mp_abs(x, &number);
@@ -471,8 +453,8 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, ch
         mp_set_from_mp(x, &number);
 
     /* Add rounding factor */
-    mp_set_from_integer(base, &MPbase);
-    mp_xpowy_integer(&MPbase, -(accuracy+1), &temp);
+    mp_set_from_integer(base, &temp);
+    mp_xpowy_integer(&temp, -(accuracy+1), &temp);
     mp_multiply_integer(&temp, base, &temp);
     mp_divide_integer(&temp, 2, &temp);
     mp_add(&number, &temp, &number);
@@ -522,9 +504,13 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, ch
     if (trim_zeroes || accuracy == 0)
         g_string_truncate(string, last_non_zero);
 
-    /* Remove negative sign if the number was rounded down to zero */
-    if (mp_is_negative(x) && strcmp(string->str, "0") != 0)
-        g_string_prepend(string, "â??");
+    /* Add sign on non-zero values */
+    if (strcmp(string->str, "0") != 0) {
+        if (mp_is_negative(x))
+            g_string_prepend(string, "â??");
+        else if (force_sign)
+            g_string_prepend(string, "+");
+    }
 
     switch(base)
     {
@@ -541,6 +527,47 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, ch
         g_string_append(string, "â??â??");
         break;
     }
+}
+
+
+void
+mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, char *buffer, int buffer_length)
+{
+    MPNumber x_real, x_im;
+    GString *string;
+    
+    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, base, accuracy, trim_zeroes, FALSE, string);
+    if (mp_is_complex(x)) {
+        GString *s;
+        gboolean force_sign = TRUE;
+        
+        if (strcmp(string->str, "0") == 0) {
+            g_string_assign(string, "");
+            force_sign = FALSE;
+        }
+
+        s = g_string_sized_new(buffer_length);
+        mp_cast_to_string_real(&x_im, 10, accuracy, trim_zeroes, force_sign, s);
+        if (strcmp(s->str, "1") == 0) {
+            g_string_append(string, "i");
+        }
+        else if (strcmp(s->str, "+1") == 0) {
+            g_string_append(string, "+i");
+        }
+        else if (strcmp(s->str, "â??1") == 0) {
+            g_string_append(string, "â??i");
+        }
+        else {
+            g_string_append(string, s->str);
+            g_string_append(string, "i");
+        }
+        g_string_free(s, TRUE);
+    }
 
     // FIXME: Check for truncation
     strncpy(buffer, string->str, buffer_length);
diff --git a/src/mp-internal.h b/src/mp-internal.h
index de3eb34..9552630 100644
--- a/src/mp-internal.h
+++ b/src/mp-internal.h
@@ -39,7 +39,7 @@
 #define MP_T 55
 
 void mperr(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void mpgcd(int *, int *);
+void mp_gcd(int *, int *);
 void mp_normalize(MPNumber *);
 
 #endif /* MP_INTERNAL_H */
diff --git a/src/mp-trigonometric.c b/src/mp-trigonometric.c
index 018f66c..5e278d9 100644
--- a/src/mp-trigonometric.c
+++ b/src/mp-trigonometric.c
@@ -276,6 +276,7 @@ mp_tan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
     if (mp_is_zero(&cos_x)) {
         /* Translators: Error displayed when tangent value is undefined */
         mperr(_("Tangent not defined for angles that are multiples of Ï?â??2 (180°) from Ï?â??4 (90°)"));
+        mp_set_from_integer(0, z);
         return;
     }
 
diff --git a/src/mp.c b/src/mp.c
index 9219843..92e8f40 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -67,7 +67,7 @@ void mp_clear_error()
  *  CAN BE.  X IS AN MP NUMBER, I AND J ARE INTEGERS.
  */
 static void
-mpext(int i, int j, MPNumber *x)
+mp_ext(int i, int j, MPNumber *x)
 {
     int q, s;
 
@@ -164,14 +164,16 @@ mp_arg(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 }
 
 
-void mp_conjugate(const MPNumber *x, MPNumber *z)
+void
+mp_conjugate(const MPNumber *x, MPNumber *z)
 {
     //mp_set_from_mp(x, z);
     //z->im_sign = -z->im_sign;
 }
 
 
-void mp_real_component(const MPNumber *x, MPNumber *z)
+void
+mp_real_component(const MPNumber *x, MPNumber *z)
 {
     mp_set_from_mp(x, z);
     //z->im_sign = 0;
@@ -180,7 +182,8 @@ void mp_real_component(const MPNumber *x, MPNumber *z)
 }
 
 
-void mp_imaginary_component(const MPNumber *x, MPNumber *z)
+void
+mp_imaginary_component(const MPNumber *x, MPNumber *z)
 {
     mp_set_from_integer(0, z);
     //mp_set_from_mp(x, z);
@@ -194,9 +197,9 @@ void mp_imaginary_component(const MPNumber *x, MPNumber *z)
 
 
 static void
-mp_add_component(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(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)
 {
     int sign_prod, i, c;
     int exp_diff, med;
@@ -370,9 +373,9 @@ mp_add(const MPNumber *x, const MPNumber *y, MPNumber *z)
     else if (mp_is_zero(y))
         mp_set_from_mp(x, z);
     else {
-        mp_add_component(x->sign, x->exponent, x->fraction,
-                         y->sign, y->exponent, y->fraction,
-                         &z->sign, &z->exponent, z->fraction);
+        mp_add_real(x->sign, x->exponent, x->fraction,
+                    y->sign, y->exponent, y->fraction,
+                    &z->sign, &z->exponent, z->fraction);
         mp_normalize(z);
     }
 }
@@ -408,9 +411,9 @@ mp_subtract(const MPNumber *x, const MPNumber *y, MPNumber *z)
     else if (mp_is_zero(y))
         mp_set_from_mp(x, z);
     else {
-        mp_add_component(x->sign, x->exponent, x->fraction,
-                         -y->sign, y->exponent, y->fraction,
-                         &z->sign, &z->exponent, z->fraction);
+        mp_add_real(x->sign, x->exponent, x->fraction,
+                    -y->sign, y->exponent, y->fraction,
+                    &z->sign, &z->exponent, z->fraction);
         mp_normalize(z);
     }
 }
@@ -544,7 +547,7 @@ mp_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
 
     /* MULTIPLY BY X */
     mp_multiply(x, &t, z);
-    mpext(i, z->fraction[0], z);
+    mp_ext(i, z->fraction[0], z);
 
     z->exponent += ie;
 }
@@ -574,7 +577,8 @@ mp_divide_integer(const MPNumber *x, int y, MPNumber *z)
     /* Division by -1 or 1 just changes sign */
     if (y == 1 || y == -1) {
         mp_set_from_mp(x, z);
-        z->sign *= y;
+        if (y < 0)
+            mp_invert_sign(z, z);
         return;
     }
 
@@ -704,6 +708,13 @@ mp_divide_integer(const MPNumber *x, int y, MPNumber *z)
         ++k;
         if (k > i2) {
             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;
         }
     }
@@ -846,15 +857,15 @@ mp_exp(const MPNumber *x, MPNumber *z)
 }
 
 
-void
-mp_epowy(const MPNumber *x, MPNumber *z)
+static void
+mp_epowy_real(const MPNumber *x, MPNumber *z)
 {
     float r__1;
     int i, ix, xs, tss;
     float rx, rz, rlb;
     MPNumber t1, t2;
 
-    /* x^0 = 1 */
+    /* e^0 = 1 */
     if (mp_is_zero(x)) {
         mp_set_from_integer(1, z);
         return;
@@ -935,12 +946,35 @@ mp_epowy(const MPNumber *x, MPNumber *z)
 }
 
 
+void
+mp_epowy(const MPNumber *x, MPNumber *z)
+{
+    /* e^0 = 1 */
+    if (mp_is_zero(x)) {
+        mp_set_from_integer(1, z);
+        return;
+    }
+
+    if (mp_is_complex(x)) {
+        MPNumber x_real, r, theta;
+        
+        mp_real_component(x, &x_real);
+        mp_imaginary_component(x, &theta);
+
+        mp_epowy_real(&x_real, &r);
+        mp_set_from_polar(&r, MP_RADIANS, &theta, z);
+    }
+    else
+        mp_epowy_real(x, z);
+}
+
+
 /*  RETURNS K = K/GCD AND L = L/GCD, WHERE GCD IS THE
  *  GREATEST COMMON DIVISOR OF K AND L.
  *  SAVE INPUT PARAMETERS IN LOCAL VARIABLES
  */
 void
-mpgcd(int *k, int *l)
+mp_gcd(int *k, int *l)
 {
     int i, j;
 
@@ -982,9 +1016,7 @@ mp_is_zero(const MPNumber *x)
 int
 mp_is_negative(const MPNumber *x)
 {
-    MPNumber zero;
-    mp_set_from_integer(0, &zero);
-    return mp_is_less_than(x, &zero);
+    return x->sign < 0;
 }
 
 
@@ -1015,7 +1047,7 @@ mp_is_less_equal(const MPNumber *x, const MPNumber *y)
  *  EXP1(-Y) = X, THEN REVERSES SIGN OF Y.
  */
 static void
-mplns(const MPNumber *x, MPNumber *z)
+mp_lns(const MPNumber *x, MPNumber *z)
 {
     int t, it0;
     MPNumber t1, t2, t3;
@@ -1068,44 +1100,30 @@ mplns(const MPNumber *x, MPNumber *z)
 
     /* CHECK THAT NEWTON ITERATION WAS CONVERGING AS EXPECTED */
     if (t3.sign != 0 && t3.exponent << 1 > it0 - MP_T) {
-        mperr("*** ERROR OCCURRED IN MPLNS, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
+        mperr("*** ERROR OCCURRED IN MP_LNS, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
     }
 
     z->sign = -z->sign;
 }
 
 
-void
-mp_ln(const MPNumber *x, MPNumber *z)
+static void
+mp_ln_real(const MPNumber *x, MPNumber *z)
 {
     int e, k;
     float rx, rlx;
     MPNumber t1, t2;
 
-    /* ln(-x) complex */
-    if (x->sign <= 0) {
-        /* Translators: Error displayed attempted to take logarithm of negative value */
-        mperr(_("Logarithm of negative values is undefined"));
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    mp_abs(x, &t1);
-
     /* LOOP TO GET APPROXIMATE LN(X) USING SINGLE-PRECISION */
+    mp_set_from_mp(x, &t1);
     mp_set_from_integer(0, z);
-    k = 0;
-    while(1)
+    for(k = 0; k < 10; k++)
     {
+        /* COMPUTE FINAL CORRECTION ACCURATELY USING MP_LNS */
         mp_add_integer(&t1, -1, &t2);
-
-        /* COMPUTE FINAL CORRECTION ACCURATELY USING MPLNS */
         if (mp_is_zero(&t2) || t2.exponent + 1 <= 0) {
-            mplns(&t2, &t2);
+            mp_lns(&t2, &t2);
             mp_add(z, &t2, z);
-
-            mp_arg(x, MP_RADIANS, &t1);
-            mp_set_from_complex(z, &t1, z);
             return;
         }
 
@@ -1113,8 +1131,6 @@ mp_ln(const MPNumber *x, MPNumber *z)
         e = t1.exponent;
         t1.exponent = 0;
         rx = mp_cast_to_float(&t1);
-
-        /* RESTORE EXPONENT AND COMPUTE SINGLE-PRECISION LOG */
         t1.exponent = e;
         rlx = log(rx) + (float)e * log((float)MP_BASE);
         mp_set_from_float(-(double)rlx, &t2);
@@ -1125,14 +1141,44 @@ mp_ln(const MPNumber *x, MPNumber *z)
 
         /* COMPUTE RESIDUAL WHOSE LOG IS STILL TO BE FOUND */
         mp_multiply(&t1, &t2, &t1);
+    }
 
-        /* MAKE SURE NOT LOOPING INDEFINITELY */
-        ++k;
-        if (k >= 10) {
-            mperr("*** ERROR IN MP_LN, ITERATION NOT CONVERGING ***");
-            return;
-        }
+    mperr("*** ERROR IN MP_LN, ITERATION NOT CONVERGING ***");
+}
+
+
+void
+mp_ln(const MPNumber *x, MPNumber *z)
+{
+    /* ln(0) undefined */
+    if (mp_is_zero(x)) {
+        /* Translators: Error displayed when attempting to take logarithm of zero */
+        mperr(_("Logarithm of zero is undefined"));
+        mp_set_from_integer(0, z);
+        return;
+    }
+
+    /* ln(-x) complex */
+    // TEMP: Remove when supporting complex numbers
+    if (mp_is_negative(x)) {
+        /* Translators: Error displayed attempted to take logarithm of negative value */
+        mperr(_("Logarithm of negative values is undefined"));
+        mp_set_from_integer(0, z);
+        return;
+    }
+
+    if (mp_is_complex(x) || mp_is_negative(x)) {
+        MPNumber r, theta, z_real;
+
+        /* ln(re^iθ) = e^(ln(r)+iθ) */
+        mp_abs(x, &r);
+        mp_arg(x, MP_RADIANS, &theta);
+
+        mp_ln_real(&r, &z_real);
+        mp_set_from_complex(&z_real, &theta, z);
     }
+    else
+        mp_ln_real(x, z);
 }
 
 
@@ -1140,6 +1186,14 @@ void
 mp_logarithm(int n, const MPNumber *x, MPNumber *z)
 {
     MPNumber t1, t2;
+    
+    /* log(0) undefined */
+    if (mp_is_zero(x)) {
+        /* Translators: Error displayed when attempting to take logarithm of zero */
+        mperr(_("Logarithm of zero is undefined"));
+        mp_set_from_integer(0, z);
+        return;
+    }
 
     /* logn(x) = ln(x) / ln(n) */
     mp_set_from_integer(n, &t1);
@@ -1157,7 +1211,7 @@ mp_is_less_than(const MPNumber *x, const MPNumber *y)
 
 
 static void
-mp_multiply_internal(const MPNumber *x, const MPNumber *y, MPNumber *z)
+mp_multiply_real(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
     int c, i, j, xi;
     MPNumber r;
@@ -1253,86 +1307,34 @@ mp_multiply_internal(const MPNumber *x, const MPNumber *y, MPNumber *z)
 void
 mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
-    MPNumber real_x, real_y, im_x, im_y, t1, t2;
-
     /* x*0 = 0*y = 0 */
     if (mp_is_zero(x) || mp_is_zero(y)) {
         mp_set_from_integer(0, 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);
-    
     /* (a+bi)(c+di) = (ac-bd)+(ad+bc)i */
-    mp_multiply_internal(&real_x, &real_y, &t1);
-    mp_multiply_internal(&im_x, &im_y, &t2);
-    mp_subtract(&t1, &t2, z);
+    if (mp_is_complex(x) || mp_is_complex(y)) {
+        MPNumber real_x, real_y, im_x, im_y, t1, t2, real_z, im_z;
+
+        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_multiply_internal(&real_x, &im_y, &t1);
-    mp_multiply_internal(&im_x, &real_y, &t2);
-    mp_add(&t1, &t2, &t1);
-    //t1.im_sign = t1.sign;
-    //t1.im_exponent = t1.exponent;
-    //memcpy(t1.im_fraction, t1.fraction, sizeof(int) * MP_SIZE);
-    t1.sign = t1.exponent = 0;
-    memset(t1.fraction, 0, sizeof(int) * MP_SIZE);
+        mp_multiply_real(&real_x, &real_y, &t1);
+        mp_multiply_real(&im_x, &im_y, &t2);
+        mp_subtract(&t1, &t2, &real_z);
     
-    mp_add(z, &t1, z);
-}
-
-
-void
-mp_multiply_new(const MPNumber *x, const MPNumber *y, MPNumber *z)
-{
-    int i, j, offset, y_length;
-    int fraction[MP_SIZE*2];
-
-    /* x*0 or 0*y or 0*0 = 0 */
-    if (mp_is_zero(x) || mp_is_zero(y)) {
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    /* Calculate length of each fraction */
-    y_length = MP_SIZE;
-    while (y_length > 0 && y->fraction[y_length - 1] == 0)
-        y_length--;
-
-    /* Multiply together */
-    memset(fraction, 0, sizeof(fraction));
-    for (i = MP_SIZE - 1; i >= 0; i--) {
-        if (x->fraction[i] == 0)
-            continue;
-        for (j = y_length - 1; j >= 0; j--) {
-            int pos = i + j + 1;
-
-            fraction[pos] += x->fraction[i] * y->fraction[j];
-            fraction[pos-1] += fraction[pos] / MP_BASE;
-            fraction[pos] = fraction[pos] % MP_BASE;
-        }
+        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);
     }
-
-    offset = 0;
-    for (i = 0; i < MP_SIZE && fraction[offset] == 0; i++)
-        offset++;
-    z->sign = x->sign * y->sign;
-    z->exponent = x->exponent + y->exponent - offset;
-    for (i = 0; i < MP_SIZE; i++) {
-        if (i + offset >= MP_SIZE*2)
-            z->fraction[i] = 0;
-        else
-            z->fraction[i] = fraction[i + offset];
+    else {
+        mp_multiply_real(x, y, z);
     }
-
-    /*for (i = MP_SIZE + offset; i < MP_SIZE * 2; i++) {
-        if (fraction[i] != 0) {
-            printf("truncated\n");
-            break;
-        }
-    }*/
 }
 
 
@@ -1455,6 +1457,13 @@ mp_multiply_integer(const MPNumber *x, int y, MPNumber *z)
         z->fraction[0] = ri - MP_BASE * c;
         z->exponent++;
     }
+    
+    if (mp_is_complex(x)) {
+        MPNumber im_z;
+        mp_imaginary_component(x, &im_z);
+        mp_multiply_integer(&im_z, y, &im_z);
+        mp_set_from_complex(z, &im_z, z);
+    }
 }
 
 
@@ -1473,7 +1482,7 @@ mp_multiply_fraction(const MPNumber *x, int numerator, int denominator, MPNumber
     }
 
     /* Reduce to lowest terms */
-    mpgcd(&numerator, &denominator);
+    mp_gcd(&numerator, &denominator);
     mp_divide_integer(x, denominator, z);
     mp_multiply_integer(z, numerator, z);
 }
@@ -1552,7 +1561,7 @@ mp_pwr(const MPNumber *x, const MPNumber *y, MPNumber *z)
 
 
 static void
-mp_reciprocal_internal(const MPNumber *x, MPNumber *z)
+mp_reciprocal_real(const MPNumber *x, MPNumber *z)
 {
     MPNumber t1, t2;
     int it0, t;
@@ -1608,25 +1617,24 @@ mp_reciprocal_internal(const MPNumber *x, MPNumber *z)
 
 void
 mp_reciprocal(const MPNumber *x, MPNumber *z)
-{
-    MPNumber real_x, im_x;
-    
-    mp_real_component(x, &real_x);
-    mp_imaginary_component(x, &im_x);
-    
-    if (mp_is_zero(&im_x))
-        mp_reciprocal_internal(&real_x, z);
-    else {
+{    
+    if (mp_is_complex(x)) {
         MPNumber t1, t2;
-        
+        MPNumber real_x, im_x;
+
+        mp_real_component(x, &real_x);
+        mp_imaginary_component(x, &im_x);
+
         /* 1/(a+bi) = (a-bi)/(a+bi)(a-bi) = (a-bi)/(a²+b²) */
         mp_multiply(&real_x, &real_x, &t1);
         mp_multiply(&im_x, &im_x, &t2);
         mp_add(&t1, &t2, &t1);
-        mp_reciprocal_internal(&t1, z);
+        mp_reciprocal_real(&t1, z);
         mp_conjugate(x, &t1);
         mp_multiply(&t1, z, z);
     }
+    else
+        mp_reciprocal_real(x, z);
 }
 
 
@@ -1738,8 +1746,10 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
 void
 mp_sqrt(const MPNumber *x, MPNumber *z)
 {
-    if (x->sign < 0)
+    if (x->sign < 0) {
         mperr(_("Square root is not defined for negative values"));
+        mp_set_from_integer(0, z);
+    }
     else if (mp_is_zero(x))
         mp_set_from_integer(0, z);
     else {
@@ -1749,7 +1759,7 @@ mp_sqrt(const MPNumber *x, MPNumber *z)
         mp_root(x, -2, &t);
         i = t.fraction[0]; // ?
         mp_multiply(x, &t, z);
-        mpext(i, z->fraction[0], z);
+        mp_ext(i, z->fraction[0], z);
     }
 }
 
@@ -1767,6 +1777,7 @@ mp_factorial(const MPNumber *x, MPNumber *z)
     if (!mp_is_natural(x)) {
         /* Translators: Error displayed when attempted take the factorial of a fractional number */
         mperr(_("Factorial only defined for natural numbers"));
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -1786,6 +1797,7 @@ mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     if (!mp_is_integer(x) || !mp_is_integer(y)) {
         /* Translators: Error displayed when attemping to do a modulus division on non-integer numbers */
         mperr(_("Modulus division only defined for integers"));
+        mp_set_from_integer(0, z);
     }
 
     mp_divide(x, y, &t1);
@@ -1825,6 +1837,7 @@ mp_xpowy_integer(const MPNumber *x, int n, MPNumber *z)
     if (mp_is_zero(x) && n < 0) {
         /* Translators: Error displayed when attempted to raise 0 to a negative exponent */
         mperr(_("The power of zero is not defined for a negative exponent"));
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -1848,6 +1861,7 @@ mp_xpowy_integer(const MPNumber *x, int n, MPNumber *z)
         mp_multiply(z, &t, z);
 }
 
+
 GList*
 mp_factorize(const MPNumber *x)
 {



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