[gcalctool/gcalctool-newui2] Tidy up



commit b19aa3358a94f70e34712cbda508f67f38581026
Author: Robert Ancell <robert ancell gmail com>
Date:   Mon Jul 13 11:41:02 2009 +1000

    Tidy up

 src/mp-binary.c        |    2 +-
 src/mp-convert.c       |   11 +-
 src/mp-equation.h      |    1 +
 src/mp-internal.h      |    2 -
 src/mp-trigonometric.c |  552 +++++++++++++++++++-----------------------------
 src/mp.c               |  458 +++++++++++++++++++---------------------
 src/mp.h               |   59 +++---
 7 files changed, 479 insertions(+), 606 deletions(-)
---
diff --git a/src/mp-binary.c b/src/mp-binary.c
index 740c86b..e3499c0 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -68,7 +68,7 @@ mp_is_overflow (const MPNumber *x, int wordlen)
 {
     MPNumber tmp1, tmp2;
     mp_set_from_integer(2, &tmp1);
-    mp_pwr_integer(&tmp1, wordlen, &tmp2);
+    mp_xpowy_integer(&tmp1, wordlen, &tmp2);
     return mp_is_greater_than (&tmp2, x);
 }
 
diff --git a/src/mp-convert.c b/src/mp-convert.c
index 875400a..db51dc0 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -217,8 +217,10 @@ mp_set_from_integer(int ix, MPNumber *z)
 {
     memset(z, 0, sizeof(MPNumber));
 
-    if (ix == 0)
+    if (ix == 0) {
+        z->exponent = 1;
         return;
+    }
 
     if (ix < 0) {
         ix = -ix;
@@ -230,9 +232,6 @@ mp_set_from_integer(int ix, MPNumber *z)
     /* SET EXPONENT TO T */
     z->exponent = MP_T;
 
-    /* CLEAR FRACTION */
-    memset(z->fraction, 0, (MP_T-1)*sizeof(int));
-
     /* INSERT IX */
     z->fraction[MP_T - 1] = ix;
 
@@ -488,7 +487,7 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, ch
    
     /* Add rounding factor */
     mp_set_from_integer(base, &MPbase);
-    mp_pwr_integer(&MPbase, -(accuracy+1), &temp);
+    mp_xpowy_integer(&MPbase, -(accuracy+1), &temp);
     mp_multiply_integer(&temp, base, &temp);
     mp_divide_integer(&temp, 2, &temp);
     mp_add(&number, &temp, &number);
@@ -729,7 +728,7 @@ mp_set_from_string(const char *str, MPNumber *z)
     if (multiplier != 0) {
         MPNumber t;
         mp_set_from_integer(10, &t);
-        mp_pwr_integer(&t, multiplier, &t);
+        mp_xpowy_integer(&t, multiplier, &t);
         mp_multiply(z, &t, z);
     }
  
diff --git a/src/mp-equation.h b/src/mp-equation.h
index a5203ce..41f9d9c 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -2,6 +2,7 @@
 /*  $Header$
  *
  *  Copyright (C) 2004-2008 Sami Pietila
+ *  Copyright (c) 2008-2009 Robert Ancell
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/src/mp-internal.h b/src/mp-internal.h
index 1de26c6..d47695b 100644
--- a/src/mp-internal.h
+++ b/src/mp-internal.h
@@ -45,7 +45,5 @@ void mperr(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void mpgcd(int *, int *);
 void mpmul2(const MPNumber *, int, MPNumber *, int);
 void mp_normalize(MPNumber *, int trunc);
-void mpexp1(const MPNumber *, MPNumber *);
-void mpmulq(const MPNumber *, int, int, MPNumber *);
 
 #endif /* MP_INTERNAL_H */
diff --git a/src/mp-trigonometric.c b/src/mp-trigonometric.c
index c46f2c4..29e4ed2 100644
--- a/src/mp-trigonometric.c
+++ b/src/mp-trigonometric.c
@@ -32,144 +32,15 @@
  *      +1 IF X  >  I,
  *       0 IF X == I,
  *      -1 IF X  <  I
- *  DIMENSION OF R IN COMMON AT LEAST 2T+6
- *  CHECK LEGALITY OF B, T, M AND MXR
  */
 static int
 mp_compare_mp_to_int(const MPNumber *x, int i)
 {
-    MPNumber t;
-   
-    /* CONVERT I TO MULTIPLE-PRECISION AND COMPARE */
+    MPNumber t;   
     mp_set_from_integer(i, &t);
     return mp_compare_mp_to_mp(x, &t);
 }
 
-/*  COMPUTES Z = SIN(X) IF DO_SIN != 0, Z = COS(X) IF DO_SIN == 0,
- *  USING TAYLOR SERIES.   ASSUMES ABS(X) <= 1.
- *  X AND Y ARE MP NUMBERS, IS AN INTEGER.
- *  TIME IS O(M(T)T/LOG(T)).   THIS COULD BE REDUCED TO
- *  O(SQRT(T)M(T)) AS IN MPEXP1, BUT NOT WORTHWHILE UNLESS
- *  T IS VERY LARGE.  ASYMPTOTICALLY FASTER METHODS ARE
- *  DESCRIBED IN THE REFERENCES GIVEN IN COMMENTS
- *  TO MP_ATAN AND MPPIGL.
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 3T+8
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static void
-mpsin1(const MPNumber *x, MPNumber *z, int do_sin)
-{
-    int i, b2;
-    MPNumber t1, t2;
-
-    /* SIN(0) = 0, COS(0) = 1 */
-    if (x->sign == 0) {
-        if (do_sin == 0)
-            mp_set_from_integer(1, z);
-        else
-            mp_set_from_integer(0, z);
-        return;
-    }
-
-    b2 = max(MP_BASE, 64) << 1;
-    mp_multiply(x, x, &t2);
-    if (mp_compare_mp_to_int(&t2, 1) > 0) {
-        mperr("*** ABS(X) > 1 IN CALL TO MPSIN1 ***");
-    }
-
-    if (do_sin == 0)
-        mp_set_from_integer(1, &t1);
-    else
-        mp_set_from_mp(x, &t1);
-
-    i = 1;
-    if (do_sin != 0) {
-        mp_set_from_mp(&t1, z);
-        i = 2;
-    }
-    else
-        mp_set_from_integer(0, z);
-
-    /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
-    for (; ; i += 2) {
-        if (MP_T + t1.exponent <= 0)
-            break;
-
-        /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
-         *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
-         */
-        mp_multiply(&t2, &t1, &t1);
-        if (i > b2) {
-            mp_divide_integer(&t1, -i, &t1);
-            mp_divide_integer(&t1, i + 1, &t1);
-        } else {
-            mp_divide_integer(&t1, -i * (i + 1), &t1);
-        }
-        mp_add(&t1, z, z);
-
-        if (t1.sign == 0)
-            break;
-    }
-
-    if (do_sin == 0)
-        mp_add_integer(z, 1, z);
-}
-
-/*  COMPUTES MP Z = ARCTAN(1/N), ASSUMING INTEGER N > 1.
- *  USES SERIES ARCTAN(X) = X - X**3/3 + X**5/5 - ...
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE
- *  AT LEAST 2T+6
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static void
-mp_atan1N(int n, MPNumber *z)
-{
-    int i, b2, id;
-    MPNumber t2;
-
-    if (n <= 1) {
-        mperr("*** N <= 1 IN CALL TO MP_ATAN1N ***");
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    /* SET SUM TO X = 1/N */
-    mp_set_from_fraction(1, n, z);
-
-    /* SET ADDITIVE TERM TO X */
-    mp_set_from_mp(z, &t2);
-
-    /* ASSUME AT LEAST 16-BIT WORD. */
-    b2 = max(MP_BASE, 64);
-    if (n < b2)
-        id = b2 * 7 * b2 / (n * n);
-    else
-        id = 0;
-
-    /* MAIN LOOP.  FIRST REDUCE T IF POSSIBLE */
-    for (i = 1; ; i += 2) {
-        if (MP_T + 2 + t2.exponent - z->exponent <= 1)
-            break;
-
-        /*  IF (I+2)*N**2 IS NOT REPRESENTABLE AS AN INTEGER THE DIVISION
-         *  FOLLOWING HAS TO BE PERFORMED IN SEVERAL STEPS.
-         */
-        if (i >= id) {
-            mp_multiply_fraction(&t2, -i, i + 2, &t2);
-            mp_divide_integer(&t2, n, &t2);
-            mp_divide_integer(&t2, n, &t2);
-        }
-        else {
-            mp_multiply_fraction(&t2, -i, (i + 2)*n*n, &t2);
-        }
-
-        /* ADD TO SUM */
-        mp_add(&t2, z, z);
-        if (t2.sign == 0)
-            break;
-    }
-}
-
 
 /* Convert x to radians */
 static void
@@ -197,6 +68,14 @@ convert_to_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
     }
 }
 
+
+void
+mp_get_pi(MPNumber *z)
+{
+    mp_set_from_string("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", z);
+}
+
+
 static void
 convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
@@ -222,28 +101,63 @@ convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
     }
 }
 
-/*  SETS MP Z = PI TO THE AVAILABLE PRECISION.
- *  USES PI/4 = 4.ARCTAN(1/5) - ARCTAN(1/239).
- *  TIME IS O(T**2).
- *  DIMENSION OF R MUST BE AT LEAST 3T+8
- *  CHECK LEGALITY OF B, T, M AND MXR
+
+/*  COMPUTES Z = SIN(X) IF DO_SIN != 0, Z = COS(X) IF DO_SIN == 0,
+ *  USING TAYLOR SERIES.   ASSUMES ABS(X) <= 1.
  */
-void
-mp_get_pi(MPNumber *z)
+static void
+mpsin1(const MPNumber *x, MPNumber *z, int do_sin)
 {
-    float prec;
-    MPNumber t;
+    int i, b2;
+    MPNumber t1, t2;
+
+    /* sin(0) = 0, cos(0) = 1 */
+    if (x->sign == 0) {
+        if (do_sin == 0)
+            mp_set_from_integer(1, z);
+        else
+            mp_set_from_integer(0, z);
+        return;
+    }
 
-    mp_atan1N(5, &t);
-    mp_multiply_integer(&t, 4, &t);
-    mp_atan1N(239, z);
-    mp_subtract(&t, z, z);
-    mp_multiply_integer(z, 4, z);
+    mp_multiply(x, x, &t2);
+    if (mp_compare_mp_to_int(&t2, 1) > 0) {
+        mperr("*** ABS(X) > 1 IN CALL TO MPSIN1 ***");
+    }
+
+    if (do_sin == 0) {
+        mp_set_from_integer(1, &t1);
+        mp_set_from_integer(0, z);
+        i = 1;
+    } else {
+        mp_set_from_mp(x, &t1);
+        mp_set_from_mp(&t1, z);
+        i = 2;
+    }
+
+    /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
+    b2 = max(MP_BASE, 64) << 1;
+    do {
+        if (MP_T + t1.exponent <= 0)
+            break;
 
-    /* FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL */
-    prec = fabs(mp_cast_to_float(z) - 3.1416);
-    if (prec >= 0.01)
-        mperr("*** ERROR OCCURRED IN MP_GET_PI, RESULT INCORRECT ***");
+        /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
+         *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
+         */
+        mp_multiply(&t2, &t1, &t1);
+        if (i > b2) {
+            mp_divide_integer(&t1, -i, &t1);
+            mp_divide_integer(&t1, i + 1, &t1);
+        } else {
+            mp_divide_integer(&t1, -i * (i + 1), &t1);
+        }
+        mp_add(&t1, z, z);
+        
+        i += 2;
+    } while (t1.sign != 0);
+
+    if (do_sin == 0)
+        mp_add_integer(z, 1, z);
 }
 
 
@@ -258,73 +172,69 @@ mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     int ie, xs;
     float rx = 0.0;
-    MPNumber t1, t2;
+    MPNumber x_radians;
 
-    convert_to_radians(x, unit, &t1);
-    
-    if (t1.sign == 0) {
+    /* sin(0) = 0 */
+    if (x->sign == 0) {
         mp_set_from_integer(0, z);
         return;
     }
 
-    xs = t1.sign;
-    ie = abs(t1.exponent);
+    convert_to_radians(x, unit, &x_radians);
+
+    xs = x_radians.sign;
+    ie = abs(x_radians.exponent);
     if (ie <= 2)
-        rx = mp_cast_to_float(&t1);
+        rx = mp_cast_to_float(&x_radians);
 
-    mp_abs(&t1, &t1);
+    mp_abs(&x_radians, &x_radians);
 
     /* USE MPSIN1 IF ABS(X) <= 1 */
-    if (mp_compare_mp_to_int(&t1, 1) <= 0)
+    if (mp_compare_mp_to_int(&x_radians, 1) <= 0)
     {
-        mpsin1(&t1, z, 1);
+        mpsin1(&x_radians, z, 1);
     }
-    /*  FIND ABS(X) MODULO 2PI (IT WOULD SAVE TIME IF PI WERE
-     *  PRECOMPUTED AND SAVED IN COMMON).
-     *  FOR INCREASED ACCURACY COMPUTE PI/4 USING MP_ATAN1N
-     */
+    /* FIND ABS(X) MODULO 2PI */
     else {
-        mp_atan1N(5, &t2);
-        mp_multiply_integer(&t2, 4, &t2);
-        mp_atan1N(239, z);
-        mp_subtract(&t2, z, z);
-        mp_divide(&t1, z, &t1);
-        mp_divide_integer(&t1, 8, &t1);
-        mp_fractional_component(&t1, &t1);
+        mp_get_pi(z);
+        mp_divide_integer(z, 4, z);
+        mp_divide(&x_radians, z, &x_radians);
+        mp_divide_integer(&x_radians, 8, &x_radians);
+        mp_fractional_component(&x_radians, &x_radians);
 
         /* SUBTRACT 1/2, SAVE SIGN AND TAKE ABS */
-        mp_add_fraction(&t1, -1, 2, &t1);
-        xs = -xs * t1.sign;
+        mp_add_fraction(&x_radians, -1, 2, &x_radians);
+        xs = -xs * x_radians.sign;
         if (xs == 0) {
             mp_set_from_integer(0, z);
             return;
         }
 
-        t1.sign = 1;
-        mp_multiply_integer(&t1, 4, &t1);
+        x_radians.sign = 1;
+        mp_multiply_integer(&x_radians, 4, &x_radians);
 
         /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
-        if (t1.exponent > 0)
-            mp_add_integer(&t1, -2, &t1);
+        if (x_radians.exponent > 0)
+            mp_add_integer(&x_radians, -2, &x_radians);
 
-        if (t1.sign == 0) {
+        if (x_radians.sign == 0) {
             mp_set_from_integer(0, z);
             return;
         }        
 
-        t1.sign = 1;
-        mp_multiply_integer(&t1, 2, &t1);
+        x_radians.sign = 1;
+        mp_multiply_integer(&x_radians, 2, &x_radians);
 
         /*  NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
          *  POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
          */
-        if (t1.exponent > 0) {
-            mp_add_integer(&t1, -2, &t1);
-            mp_multiply(&t1, z, &t1);
-            mpsin1(&t1, z, 0);
+        if (x_radians.exponent > 0) {
+            mp_add_integer(&x_radians, -2, &x_radians);
+            mp_multiply(&x_radians, z, &x_radians);
+            mpsin1(&x_radians, z, 0);
         } else {
-            mp_multiply(&t1, z, &t1);
-            mpsin1(&t1, z, 1);
+            mp_multiply(&x_radians, z, &x_radians);
+            mpsin1(&x_radians, z, 1);
         }
     }
 
@@ -348,9 +258,7 @@ mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 void
 mp_cos(const MPNumber *xi, MPAngleUnit unit, MPNumber *z)
 {
-    MPNumber t;
-
-    /* COS(0) = 1 */    
+    /* cos(0) = 1 */    
     if (xi->sign == 0) {
         mp_set_from_integer(1, z);
         return;
@@ -358,15 +266,14 @@ mp_cos(const MPNumber *xi, MPAngleUnit unit, MPNumber *z)
 
     convert_to_radians(xi, unit, z);
 
-    /* SEE IF ABS(X) <= 1 */
+    /* Use power series if -1 >= x >= 1 */
     mp_abs(z, z);
     if (mp_compare_mp_to_int(z, 1) <= 0) {
-        /* HERE ABS(X) <= 1 SO USE POWER SERIES */
         mpsin1(z, z, 0);
     } else {
-        /*  HERE ABS(X) > 1 SO USE COS(X) = SIN(PI/2 - ABS(X)),
-         *  COMPUTING PI/2 WITH ONE GUARD DIGIT.
-         */
+        MPNumber t;
+
+        /* cos(x) = sin(Ï?/2 - |x|) */
         mp_get_pi(&t);
         mp_divide_integer(&t, 2, &t);
         mp_subtract(&t, z, z);
@@ -380,14 +287,16 @@ mp_tan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber cos_x, sin_x;
 
-    mp_sin(x, unit, &sin_x);
+    /* Check for undefined values */
     mp_cos(x, unit, &cos_x);
-    /* Check if COS(x) == 0 */
     if (mp_is_zero(&cos_x)) {
         /* Translators: Error displayed when tangent value is undefined */
         mperr(_("Tangent is infinite"));
         return;
     }
+    
+    /* tan(x) = sin(x) / cos(x) */
+    mp_sin(x, unit, &sin_x);
     mp_divide(&sin_x, &cos_x, z);
 }
 
@@ -404,6 +313,7 @@ mp_asin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber t1, t2;
 
+    /* asin(0) = 0 */
     if (x->sign == 0) {
         mp_set_from_integer(0, z);
         return;
@@ -452,32 +362,32 @@ mp_asin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 void
 mp_acos(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
-    MPNumber MP1, MP2;
-    MPNumber MPn1, MPpi, MPy;
+    MPNumber t1, t2;
+    MPNumber MPn1, pi, MPy;
 
-    mp_get_pi(&MPpi);
-    mp_set_from_integer(1, &MP1);
+    mp_get_pi(&pi);
+    mp_set_from_integer(1, &t1);
     mp_set_from_integer(-1, &MPn1);
 
-    if (mp_is_greater_than(x, &MP1) || mp_is_less_than(x, &MPn1)) {
+    if (mp_is_greater_than(x, &t1) || mp_is_less_than(x, &MPn1)) {
         mperr("Error");
         mp_set_from_integer(0, z);
     } else if (x->sign == 0) {
-        mp_divide_integer(&MPpi, 2, z);
-    } else if (mp_is_equal(x, &MP1)) {
+        mp_divide_integer(&pi, 2, z);
+    } else if (mp_is_equal(x, &t1)) {
         mp_set_from_integer(0, z);
     } else if (mp_is_equal(x, &MPn1)) {
-        mp_set_from_mp(&MPpi, z);
+        mp_set_from_mp(&pi, z);
     } else { 
-        mp_multiply(x, x, &MP2);
-        mp_subtract(&MP1, &MP2, &MP2);
-        mp_sqrt(&MP2, &MP2);
-        mp_divide(&MP2, x, &MP2);
-        mp_atan(&MP2, MP_RADIANS, &MPy);
+        mp_multiply(x, x, &t2);
+        mp_subtract(&t1, &t2, &t2);
+        mp_sqrt(&t2, &t2);
+        mp_divide(&t2, x, &t2);
+        mp_atan(&t2, MP_RADIANS, &MPy);
         if (x->sign > 0) {
             mp_set_from_mp(&MPy, z);
         } else {
-            mp_add(&MPy, &MPpi, z);
+            mp_add(&MPy, &pi, z);
         }
     }
     
@@ -487,7 +397,7 @@ mp_acos(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 
 /*  RETURNS Z = ARCTAN(X) FOR MP X AND Z, USING AN O(T.M(T)) METHOD
  *  WHICH COULD EASILY BE MODIFIED TO AN O(SQRT(T)M(T))
- *  METHOD (AS IN MPEXP1). Z IS IN THE RANGE -PI/2 TO +PI/2.
+ *  METHOD (AS IN MPEXP). Z IS IN THE RANGE -PI/2 TO +PI/2.
  *  FOR AN ASYMPTOTICALLY FASTER METHOD, SEE - FAST MULTIPLE-
  *  PRECISION EVALUATION OF ELEMENTARY FUNCTIONS
  *  (BY R. P. BRENT), J. ACM 23 (1976), 242-251,
@@ -560,91 +470,59 @@ mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 }
 
 
-/*  MP precision hyperbolic arc cosine.
- *
- *  1. If (x < 1) then report DOMAIN error and return 0.
- *
- *  2. acosh(x) = log(x + sqrt(x^2 - 1))
- */
 void
-mp_acosh(const MPNumber *x, MPNumber *z)
+mp_sinh(const MPNumber *x, MPNumber *z)
 {
-    MPNumber MP1;
+    MPNumber abs_x;
 
-    mp_set_from_integer(1, &MP1);
-    if (mp_is_less_than(x, &MP1)) {
-        mperr("Error");
+    /* sinh(0) = 0 */
+    if (x->sign == 0) {
         mp_set_from_integer(0, z);
-    } else {
-        mp_multiply(x, x, &MP1);
-        mp_add_integer(&MP1, -1, &MP1);
-        mp_sqrt(&MP1, &MP1);
-        mp_add(x, &MP1, &MP1);
-        mp_ln(&MP1, z);
+        return;
     }
-}
-
-
-/*  MP precision hyperbolic arc sine.
- *
- *  1. asinh(x) = log(x + sqrt(x^2 + 1))
- */
-void
-mp_asinh(const MPNumber *x, MPNumber *z)
-{
-    MPNumber MP1;
-
-    mp_multiply(x, x, &MP1);
-    mp_add_integer(&MP1, 1, &MP1);
-    mp_sqrt(&MP1, &MP1);
-    mp_add(x, &MP1, &MP1);
-    mp_ln(&MP1, z);
-}
 
+    /* WORK WITH ABS(X) */
+    mp_abs(x, &abs_x);
 
-/*  MP precision hyperbolic arc tangent.
- *
- *  1. If (x <= -1 or x >= 1) then report a DOMAIN error and return 0.
- *
- *  2. atanh(x) = 0.5 * log((1 + x) / (1 - x))
- */
-void
-mp_atanh(const MPNumber *x, MPNumber *z)
-{
-    MPNumber MP1, MP2;
-    MPNumber MP3, MPn1;
-
-    mp_set_from_integer(1, &MP1);
-    mp_set_from_integer(-1, &MPn1);
+    /* If |x| < 1 USE MPEXP TO AVOID CANCELLATION, otherwise IF TOO LARGE MP_EPOWY GIVES ERROR MESSAGE */
+    if (abs_x.exponent <= 0) {
+        MPNumber exp_x, a, b;
+        
+        /* ((e^|x| + 1) * (e^|x| - 1)) / e^|x| */
+        // FIXME: Solves to e^|x| - e^-|x|, why not lower branch always? */
+        mp_epowy(&abs_x, &exp_x);
+        mp_add_integer(&exp_x, 1, &a);
+        mp_add_integer(&exp_x, -1, &b);
+        mp_multiply(&a, &b, z);
+        mp_divide(z, &exp_x, z);
+    }
+    else {
+        MPNumber exp_x;
 
-    if (mp_is_greater_equal(x, &MP1) || mp_is_less_equal(x, &MPn1)) {
-        mperr("Error");
-        mp_set_from_integer(0, z);
-    } else {
-        mp_add(&MP1, x, &MP2);
-        mp_subtract(&MP1, x, &MP3);
-        mp_divide(&MP2, &MP3, &MP3);
-        mp_ln(&MP3, &MP3);
-        mp_set_from_string("0.5", &MP1);
-        mp_multiply(&MP1, &MP3, z);
+        /* e^|x| - e^-|x| */
+        mp_epowy(&abs_x, &exp_x);
+        mp_reciprocal(&exp_x, z);
+        mp_subtract(&exp_x, z, z);
     }
+
+    /* DIVIDE BY TWO AND RESTORE SIGN */
+    mp_divide_integer(z, 2, z);
+    mp_multiply_integer(z, x->sign, z);
 }
 
 
-/*  RETURNS Z = COSH(X) FOR MP NUMBERS X AND Z, X NOT TOO LARGE.
- *  USES MP_EPOWY, DIMENSION OF R IN COMMON AT LEAST 5T+12
- */
 void
 mp_cosh(const MPNumber *x, MPNumber *z)
 {
     MPNumber t;
 
-    /* COSH(0) == 1 */    
+    /* cosh(0) = 1 */    
     if (x->sign == 0) {
-      mp_set_from_integer(1, z);
-      return;
+        mp_set_from_integer(1, z);
+        return;
     }
 
+    /* cosh(x) = (e^x + e^-x) / 2 */
     mp_abs(x, &t);
     mp_epowy(&t, &t);
     mp_reciprocal(&t, z);
@@ -653,91 +531,103 @@ mp_cosh(const MPNumber *x, MPNumber *z)
 }
 
 
-/*  RETURNS Z = SINH(X) FOR MP NUMBERS X AND Z, X NOT TOO LARGE.
- *  METHOD IS TO USE MP_EPOWY OR MPEXP1, SPACE = 5T+12
- *  SAVE SIGN OF X AND CHECK FOR ZERO, SINH(0) = 0
- */
-void
-mp_sinh(const MPNumber *x, MPNumber *z)
-{
-    int xs;
-    MPNumber t1, t2;
-
-    xs = x->sign;
-    if (xs == 0) {
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    /* WORK WITH ABS(X) */
-    mp_abs(x, &t2);
-
-    /* HERE ABS(X) < 1 SO USE MPEXP1 TO AVOID CANCELLATION */
-    if (t2.exponent <= 0) {
-        mpexp1(&t2, &t1);
-        mp_add_integer(&t1, 2, &t2);
-        mp_multiply(&t2, &t1, z);
-        mp_add_integer(&t1, 1, &t2);
-        mp_divide(z, &t2, z);
-    }
-    /*  HERE ABS(X) >= 1, IF TOO LARGE MP_EPOWY GIVES ERROR MESSAGE
-     *  INCREASE M TO AVOID OVERFLOW IF SINH(X) REPRESENTABLE
-     */
-    else {
-        mp_epowy(&t2, &t2);
-        mp_reciprocal(&t2, z);
-        mp_subtract(&t2, z, z);
-    }
-
-    /* DIVIDE BY TWO AND RESTORE SIGN */
-    mp_divide_integer(z, xs << 1, z);
-}
-
-
-/*  RETURNS Z = TANH(X) FOR MP NUMBERS X AND Z,
- *  USING MP_EPOWY OR MPEXP1, SPACE = 5T+12
- */
 void
 mp_tanh(const MPNumber *x, MPNumber *z)
 {
     float r__1;
-    int xs;
     MPNumber t;
 
-    /* TANH(0) = 0 */    
+    /* tanh(0) = 0 */    
     if (x->sign == 0) {
         mp_set_from_integer(0, z);
         return;
     }
 
-    /* SAVE SIGN AND WORK WITH ABS(X) */
-    xs = x->sign;
     mp_abs(x, &t);
 
     /* SEE IF ABS(X) SO LARGE THAT RESULT IS +-1 */
     r__1 = (float) MP_T * 0.5 * log((float) MP_BASE);
     mp_set_from_float(r__1, z);
     if (mp_compare_mp_to_mp(&t, z) > 0) {
-        /* HERE ABS(X) IS VERY LARGE */
-        mp_set_from_integer(xs, z);
+        mp_set_from_integer(x->sign, z);
         return;
     }
 
-    /* HERE ABS(X) NOT SO LARGE */
+    /* If |x| >= 1/2 use ?, otherwise use ? to avoid cancellation */
+    /* |tanh(x)| = (e^|2x| - 1) / (e^|2x| + 1) */
     mp_multiply_integer(&t, 2, &t);
     if (t.exponent > 0) {
-        /* HERE ABS(X) >= 1/2 SO USE MP_EPOWY */
         mp_epowy(&t, &t);
         mp_add_integer(&t, -1, z);
         mp_add_integer(&t, 1, &t);
         mp_divide(z, &t, z);
     } else {
-        /* HERE ABS(X) < 1/2, SO USE MPEXP1 TO AVOID CANCELLATION */
-        mpexp1(&t, &t);
-        mp_add_integer(&t, 2, z);
+        mp_epowy(&t, &t);
+        mp_add_integer(&t, 1, z);
         mp_divide(&t, z, z);
     }
 
-    /* RESTORE SIGN */
-    z->sign = xs * z->sign;
+    /* Restore sign */
+    z->sign = x->sign * z->sign;
+}
+
+
+void
+mp_asinh(const MPNumber *x, MPNumber *z)
+{
+    MPNumber t;
+
+    /* asinh(x) = ln(x + sqrt(x^2 + 1)) */
+    mp_multiply(x, x, &t);
+    mp_add_integer(&t, 1, &t);
+    mp_sqrt(&t, &t);
+    mp_add(x, &t, &t);
+    mp_ln(&t, z);
+}
+
+
+void
+mp_acosh(const MPNumber *x, MPNumber *z)
+{
+    MPNumber t;
+
+    /* Check x >= 1 */
+    mp_set_from_integer(1, &t);
+    if (mp_is_less_than(x, &t)) {
+        mperr("Error");
+        mp_set_from_integer(0, z);
+        return;
+    }
+    
+    /* acosh(x) = ln(x + sqrt(x^2 - 1)) */
+    mp_multiply(x, x, &t);
+    mp_add_integer(&t, -1, &t);
+    mp_sqrt(&t, &t);
+    mp_add(x, &t, &t);
+    mp_ln(&t, z);
+}
+
+
+void
+mp_atanh(const MPNumber *x, MPNumber *z)
+{
+    MPNumber one, minus_one, n, d;
+
+    /* Check -1 <= x <= 1 */
+    mp_set_from_integer(1, &one);
+    mp_set_from_integer(-1, &minus_one);
+    if (mp_is_greater_equal(x, &one) || mp_is_less_equal(x, &minus_one)) {
+        mperr("Error");
+        mp_set_from_integer(0, z);
+        return;
+    }
+    
+    /* atanh(x) = 0.5 * ln((1 + x) / (1 - x)) */
+    mp_add_integer(x, 1, &n);
+    mp_set_from_mp(x, &d);
+    mp_invert_sign(&d, &d);
+    mp_add_integer(&d, 1, &d);
+    mp_divide(&n, &d, z);
+    mp_ln(z, z);
+    mp_divide_integer(z, 2, z);
 }
diff --git a/src/mp.c b/src/mp.c
index 94e8e74..9400f3e 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -33,6 +33,22 @@
 // FIXME: Re-add overflow and underflow detection
 
 
+/*  THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
+ *  AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
+ */
+void
+mperr(const char *format, ...)
+{
+    char text[MAXLINE];
+    va_list args;
+    
+    va_start(args, format);
+    vsnprintf(text, MAXLINE, format, args);
+    va_end(args);
+    doerr(text);
+}
+
+
 /*  ROUTINE CALLED BY MP_DIVIDE AND MP_SQRT TO ENSURE THAT
  *  RESULTS ARE REPRESENTED EXACTLY IN T-2 DIGITS IF THEY
  *  CAN BE.  X IS AN MP NUMBER, I AND J ARE INTEGERS.
@@ -77,7 +93,6 @@ mp_get_eulers(MPNumber *z)
 }
 
 
-/* SETS Y = ABS(X) FOR MP NUMBERS X AND Y */
 void
 mp_abs(const MPNumber *x, MPNumber *z)
 {
@@ -294,14 +309,6 @@ mp_add(const MPNumber *x, const MPNumber *y, MPNumber *z)
 }
 
 
-/*  ADDS MULTIPLE-PRECISION X TO INTEGER Y
- *  GIVING MULTIPLE-PRECISION Z.
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE
- *  AT LEAST 2T+6 (BUT Z(1) MAY BE R(T+5)).
- *  DIMENSION R(6) BECAUSE RALPH COMPILER ON UNIVAC 1100 COMPUTERS
- *  OBJECTS TO DIMENSION R(1).
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
 void
 mp_add_integer(const MPNumber *x, int y, MPNumber *z)
 {
@@ -311,10 +318,6 @@ mp_add_integer(const MPNumber *x, int y, MPNumber *z)
 }
 
 
-/*  ADDS THE RATIONAL NUMBER I/J TO MP NUMBER X, MP RESULT IN Y
- *  DIMENSION OF R MUST BE AT LEAST 2T+6
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
 void
 mp_add_fraction(const MPNumber *x, int i, int j, MPNumber *y)
 {
@@ -324,67 +327,61 @@ mp_add_fraction(const MPNumber *x, int i, int j, MPNumber *y)
 }
 
 
-/*  FOR MP X AND Y, RETURNS FRACTIONAL PART OF X IN Y,
- *  I.E., Y = X - INTEGER PART OF X (TRUNCATED TOWARDS 0).
- */
 void
 mp_fractional_component(const MPNumber *x, MPNumber *z)
 {
-    /* RETURN 0 IF X = 0
-       OR IF EXPONENT SO LARGE THAT NO FRACTIONAL PART */    
-    if (x->sign == 0 || x->exponent >= MP_T) {
+    int i, shift;
+
+    /* Fractional component of zero is 0 */
+    if (x->sign == 0) {
         mp_set_from_integer(0, z);
         return;
     }
 
-    /* IF EXPONENT NOT POSITIVE CAN RETURN X */
+    /* All fractional */
     if (x->exponent <= 0) {
         mp_set_from_mp(x, z);
         return;
     }
-
-    /* MOVE FRACTIONAL PART OF X TO ACCUMULATOR */
+    
+    /* Shift fractional component */
+    shift = x->exponent;
+    for (i = shift; i < MP_SIZE && x->fraction[i] == 0; i++)
+        shift++;
     z->sign = x->sign;
-    z->exponent = x->exponent;
-    memset(z->fraction, 0, z->exponent*sizeof(int));
-    if (x != z)
-        memcpy(z->fraction + z->exponent, x->fraction + x->exponent,
-               (MP_T - x->exponent)*sizeof(int));
-    memset(z->fraction + MP_T, 0, 4*sizeof(int));
-
-    /* NORMALIZE RESULT AND RETURN */
-    mp_normalize(z, 1);
+    z->exponent = x->exponent - shift;
+    for (i = 0; i < MP_SIZE; i++) {
+        if (i + shift >= MP_SIZE)
+            z->fraction[i] = 0;
+        else
+            z->fraction[i] = x->fraction[i + shift];
+    }
+    if (z->fraction[0] == 0)
+        z->sign = 0;
 }
 
-/* RETURNS Y = INTEGER PART OF X (TRUNCATED TOWARDS 0), FOR MP X AND Y.
- * USE IF Y TOO LARGE TO BE REPRESENTABLE AS A SINGLE-PRECISION INTEGER. 
- * (ELSE COULD USE MPCMI).
- * CHECK LEGALITY OF B, T, M AND MXR
- */
+
 void
 mp_integer_component(const MPNumber *x, MPNumber *z)
 {
     int i;
-
-    mp_set_from_mp(x, z);
-    if (z->sign == 0)
-        return;
-
-    /* IF EXPONENT LARGE ENOUGH RETURN Y = X */
-    if (z->exponent >= MP_T) {
+    
+    /* Integer component of zero = 0 */
+    if (x->sign == 0) {
+        mp_set_from_mp(x, z);
         return;
     }
 
-    /* IF EXPONENT SMALL ENOUGH RETURN ZERO */
-    if (z->exponent <= 0) {
+    /* If all fractional then no integer component */
+    if (x->exponent <= 0) {
         mp_set_from_integer(0, z);
         return;
     }
 
-    /* SET FRACTION TO ZERO */
-    for (i = z->exponent; i < MP_T; i++) {
+    /* Clear fraction */
+    mp_set_from_mp(x, z);    
+    for (i = z->exponent; i < MP_SIZE; i++)
         z->fraction[i] = 0;
-    }
 }
 
 
@@ -636,6 +633,7 @@ mp_is_integer(const MPNumber *x)
 {
     MPNumber MPtt, MP0, MP1;
 
+    /* This fix is required for 1/3 repiprocal not being detected as an integer */
     /* Multiplication and division by 10000 is used to get around a 
      * limitation to the "fix" for Sun bugtraq bug #4006391 in the 
      * mp_integer_component() routine in mp.c, when the exponent is less than 1.
@@ -644,8 +642,26 @@ mp_is_integer(const MPNumber *x)
     mp_multiply(x, &MPtt, &MP0);
     mp_divide(&MP0, &MPtt, &MP0);
     mp_integer_component(&MP0, &MP1);
-
     return mp_is_equal(&MP0, &MP1);
+
+    /* Correct way to check for integer */
+    /*int i;
+    
+    // Zero is an integer
+    if (x->sign == 0)
+        return 1;
+
+    // Fractional
+    if (x->exponent <= 0)
+        return 0;
+
+    // Look for fractional components
+    for (i = x->exponent; i < MP_SIZE; i++) {
+        if (x->fraction[i] != 0)
+            return 0;
+    }
+    
+    return 1;*/
 }
 
 
@@ -656,7 +672,6 @@ mp_is_natural(const MPNumber *x)
 }
 
 
-/* RETURNS LOGICAL VALUE OF (X == Y) FOR MP X AND Y. */
 int
 mp_is_equal(const MPNumber *x, const MPNumber *y)
 {
@@ -664,25 +679,85 @@ mp_is_equal(const MPNumber *x, const MPNumber *y)
 }
 
 
-/*  THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
- *  AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
+/*  Return e^x for |x| < 1 USING AN O(SQRT(T).M(T)) ALGORITHM
+ *  DESCRIBED IN - R. P. BRENT, THE COMPLEXITY OF MULTIPLE-
+ *  PRECISION ARITHMETIC (IN COMPLEXITY OF COMPUTATIONAL PROBLEM
+ *  SOLVING, UNIV. OF QUEENSLAND PRESS, BRISBANE, 1976, 126-165).
+ *  ASYMPTOTICALLY FASTER METHODS EXIST, BUT ARE NOT USEFUL
+ *  UNLESS T IS VERY LARGE. SEE COMMENTS TO MP_ATAN AND MPPIGL.
  */
-void
-mperr(const char *format, ...)
+static void
+mpexp(const MPNumber *x, MPNumber *z)
 {
-    char text[MAXLINE];
-    va_list args;
+    int i, q, ib, ic;
+    float rlb;
+    MPNumber t1, t2;
+
+    /* e^0 = 1 */
+    if (x->sign == 0) {
+        mp_set_from_integer(1, z);
+        return;
+    }
+
+    /* CHECK THAT ABS(X) < 1 */
+    if (x->exponent > 0) {
+        mperr("*** ABS(X) NOT LESS THAN 1 IN CALL TO MPEXP ***");
+        mp_set_from_integer(0, z);
+        return;
+    }
+
+    mp_set_from_mp(x, &t1);
+    rlb = log((float)MP_BASE);
+
+    /* COMPUTE APPROXIMATELY OPTIMAL Q (AND DIVIDE X BY 2**Q) */
+    q = (int)(sqrt((float)MP_T * 0.48f * rlb) + (float) x->exponent * 1.44f * rlb);
+
+    /* HALVE Q TIMES */
+    if (q > 0) {
+        ib = MP_BASE << 2;
+        ic = 1;
+        for (i = 1; i <= q; ++i) {
+            ic <<= 1;
+            if (ic < ib && ic != MP_BASE && i < q)
+                continue;
+            mp_divide_integer(&t1, ic, &t1);
+            ic = 1;
+        }
+    }
+
+    if (t1.sign == 0) {
+        mp_set_from_integer(0, z);
+        return;
+    }
+    mp_set_from_mp(&t1, z);
+    mp_set_from_mp(&t1, &t2);
+
+    /* SUM SERIES, REDUCING T WHERE POSSIBLE */
+    for (i = 2; ; i++)  {
+        if (MP_T + t2.exponent - z->exponent <= 0)
+            break;
+
+        mp_multiply(&t1, &t2, &t2);
+        mp_divide_integer(&t2, i, &t2);
+
+        mp_add(&t2, z, z);
+        if (t2.sign == 0)
+            break;
+    }
+
+    /* APPLY (X+1)**2 - 1 = X(2 + X) FOR Q ITERATIONS */
+    for (i = 1; i <= q; ++i) {
+        mp_add_integer(z, 2, &t1);
+        mp_multiply(&t1, z, z);
+    }
     
-    va_start(args, format);
-    vsnprintf(text, MAXLINE, format, args);
-    va_end(args);
-    doerr(text);
+    mp_add_integer(z, 1, z);
 }
 
 
 /*  RETURNS Z = EXP(X) FOR MP X AND Z.
  *  EXP OF INTEGER AND FRACTIONAL PARTS OF X ARE COMPUTED
- *  SEPARATELY.  SEE ALSO COMMENTS IN MPEXP1.
+ *  SEPARATELY.  SEE ALSO COMMENTS IN MPEXP.
  *  TIME IS O(SQRT(T)M(T)).
  *  DIMENSION OF R MUST BE AT LEAST 4T+10 IN CALLING PROGRAM
  *  CHECK LEGALITY OF B, T, M AND MXR
@@ -695,17 +770,15 @@ mp_epowy(const MPNumber *x, MPNumber *z)
     float rx, rz, rlb;
     MPNumber t1, t2;
 
-    /* CHECK FOR X == 0 */
+    /* x^0 = 1 */
     if (x->sign == 0)  {
         mp_set_from_integer(1, z);
         return;
     }
 
-    /* CHECK IF ABS(X) < 1 */
+    /* If |x| < 1 use mpexp */
     if (x->exponent <= 0) {
-        /* USE MPEXP1 HERE */
-        mpexp1(x, z);
-        mp_add_integer(z, 1, z);
+        mpexp(x, z);
         return;
     }
 
@@ -734,8 +807,7 @@ mp_epowy(const MPNumber *x, MPNumber *z)
 
     /* ATTACH SIGN TO FRACTIONAL PART AND COMPUTE EXP OF IT */
     t2.sign *= xs;
-    mpexp1(&t2, z);
-    mp_add_integer(z, 1, z);
+    mpexp(&t2, z);
 
     /*  COMPUTE E-2 OR 1/E USING TWO EXTRA DIGITS IN CASE ABS(X) LARGE
      *  (BUT ONLY ONE EXTRA DIGIT IF T < 4)
@@ -763,7 +835,7 @@ mp_epowy(const MPNumber *x, MPNumber *z)
     /* RAISE E OR 1/E TO POWER IX */
     if (xs > 0)
         mp_add_integer(&t2, 2, &t2);
-    mp_pwr_integer(&t2, ix, &t2);
+    mp_xpowy_integer(&t2, ix, &t2);
 
     /* MULTIPLY EXPS OF INTEGER AND FRACTIONAL PARTS */
     mp_multiply(z, &t2, z);
@@ -797,86 +869,6 @@ mp_epowy(const MPNumber *x, MPNumber *z)
 }
 
 
-/*  ASSUMES THAT X AND Y ARE MP NUMBERS,  -1 < X < 1.
- *  RETURNS Y = EXP(X) - 1 USING AN O(SQRT(T).M(T)) ALGORITHM
- *  DESCRIBED IN - R. P. BRENT, THE COMPLEXITY OF MULTIPLE-
- *  PRECISION ARITHMETIC (IN COMPLEXITY OF COMPUTATIONAL PROBLEM
- *  SOLVING, UNIV. OF QUEENSLAND PRESS, BRISBANE, 1976, 126-165).
- *  ASYMPTOTICALLY FASTER METHODS EXIST, BUT ARE NOT USEFUL
- *  UNLESS T IS VERY LARGE. SEE COMMENTS TO MP_ATAN AND MPPIGL.
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 3T+8
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mpexp1(const MPNumber *x, MPNumber *z)
-{
-    int i, q, ib, ic;
-    float rlb;
-    MPNumber t1, t2;
-
-    /* CHECK FOR X = 0 */
-    if (x->sign == 0) {
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    /* CHECK THAT ABS(X) < 1 */
-    if (x->exponent > 0) {
-        mperr("*** ABS(X) NOT LESS THAN 1 IN CALL TO MPEXP1 ***");
-        mp_set_from_integer(0, z);
-        return;
-    }
-
-    mp_set_from_mp(x, &t1);
-    rlb = log((float)MP_BASE);
-
-    /* COMPUTE APPROXIMATELY OPTIMAL Q (AND DIVIDE X BY 2**Q) */
-    q = (int)(sqrt((float)MP_T * 0.48f * rlb) + (float) x->exponent * 1.44f * rlb);
-
-    /* HALVE Q TIMES */
-    if (q > 0) {
-        ib = MP_BASE << 2;
-        ic = 1;
-        for (i = 1; i <= q; ++i) {
-            ic <<= 1;
-            if (ic < ib && ic != MP_BASE && i < q)
-                continue;
-            mp_divide_integer(&t1, ic, &t1);
-            ic = 1;
-        }
-    }
-
-    if (t1.sign == 0) {
-        mp_set_from_integer(0, z);
-        return;
-    }
-    mp_set_from_mp(&t1, z);
-    mp_set_from_mp(&t1, &t2);
-
-    /* SUM SERIES, REDUCING T WHERE POSSIBLE */
-    for (i = 2; ; i++)  {
-        if (MP_T + t2.exponent - z->exponent <= 0)
-            break;
-
-        mp_multiply(&t1, &t2, &t2);
-        mp_divide_integer(&t2, i, &t2);
-
-        mp_add(&t2, z, z);
-        if (t2.sign == 0)
-            break;
-    }
-
-    if (q <= 0)
-        return;
-
-    /* APPLY (X+1)**2 - 1 = X(2 + X) FOR Q ITERATIONS */
-    for (i = 1; i <= q; ++i) {
-        mp_add_integer(z, 2, &t1);
-        mp_multiply(&t1, z, 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
@@ -958,8 +950,7 @@ mp_is_less_equal(const MPNumber *x, const MPNumber *y)
  *  CONDITION ABS(X) < 1/B, ERROR OTHERWISE.
  *  USES NEWTONS METHOD TO SOLVE THE EQUATION
  *  EXP1(-Y) = X, THEN REVERSES SIGN OF Y.
- *  (HERE EXP1(Y) = EXP(Y) - 1 IS COMPUTED USING MPEXP1).
- *  TIME IS O(SQRT(T).M(T)) AS FOR MPEXP1, SPACE = 5T+12.
+ *  TIME IS O(SQRT(T).M(T)) AS FOR MPEXP, SPACE = 5T+12.
  *  CHECK LEGALITY OF B, T, M AND MXR
  */
 static void
@@ -968,14 +959,14 @@ mplns(const MPNumber *x, MPNumber *z)
     int t, it0;
     MPNumber t1, t2, t3;
     
-    /* CHECK FOR X = 0 EXACTLY */
+    /* ln(1) = 0 */
     if (x->sign == 0)  {
         mp_set_from_integer(0, z);
         return;
     }
 
     /* CHECK THAT ABS(X) < 1/B */
-    if (x->exponent + 1 > 0) {
+    if (x->exponent >= 0) {
         mperr("*** ABS(X) >= 1/B IN CALL TO MPLNS ***");
         mp_set_from_integer(0, z);
         return;
@@ -1001,7 +992,8 @@ mplns(const MPNumber *x, MPNumber *z)
         {
             int ts2, ts3;
             
-            mpexp1(z, &t3);
+            mp_epowy(z, &t3);
+            mp_add_integer(&t3, -1, &t3);
             mp_multiply(&t2, &t3, &t1);
             mp_add(&t3, &t1, &t3);
             mp_add(&t2, &t3, &t3);
@@ -1039,7 +1031,7 @@ mplns(const MPNumber *x, MPNumber *z)
  *  FOR SMALL INTEGER X, MPLNI IS FASTER.
  *  ASYMPTOTICALLY FASTER METHODS EXIST (EG THE GAUSS-SALAMIN
  *  METHOD, SEE MPLNGS), BUT ARE NOT USEFUL UNLESS T IS LARGE.
- *  SEE COMMENTS TO MP_ATAN, MPEXP1 AND MPPIGL.
+ *  SEE COMMENTS TO MP_ATAN, MPEXP AND MPPIGL.
  *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 6T+14.
  *  CHECK LEGALITY OF B, T, M AND MXR
  */
@@ -1501,95 +1493,34 @@ mp_normalize(MPNumber *x, int trunc)
 }
 
 
-/*  RETURNS Y = X**N, FOR MP X AND Y, INTEGER N, WITH 0**0 = 1.
- *  R MUST BE DIMENSIONED AT LEAST 4T+10 IN CALLING PROGRAM
- *  (2T+6 IS ENOUGH IF N NONNEGATIVE).
- */
-void
-mp_pwr_integer(const MPNumber *x, int n, MPNumber *z)
-{
-    int n2, ns;
-    MPNumber t;
-   
-    n2 = n;
-    if (n2 < 0) {
-        /* N < 0 */
-        n2 = -n2;
-        if (x->sign == 0) {
-            mperr("*** ATTEMPT TO RAISE ZERO TO NEGATIVE POWER IN CALL TO SUBROUTINE MP_PWR_INTEGER ***");
-            mp_set_from_integer(0, z);
-            return;
-        }
-    } else if (n2 == 0) {
-        /* N == 0, RETURN Y = 1. */
-        mp_set_from_integer(1, z);
-        return;
-    } else {
-        /* N > 0 */
-        if (x->sign == 0) {
-            mp_set_from_integer(0, z);
-            return;
-        }
-    }
-
-    /* MOVE X */
-    mp_set_from_mp(x, z);
-
-    /* IF N < 0 FORM RECIPROCAL */
-    if (n < 0)
-        mp_reciprocal(z, z);
-    mp_set_from_mp(z, &t);
-
-    /* SET PRODUCT TERM TO ONE */
-    mp_set_from_integer(1, z);
-
-    /* MAIN LOOP, LOOK AT BITS OF N2 FROM RIGHT */
-    while(1) {
-        ns = n2;
-        n2 /= 2;
-        if (n2 << 1 != ns)
-            mp_multiply(z, &t, z);
-        if (n2 <= 0)
-            return;
-        
-        mp_multiply(&t, &t, &t);
-    }
-}
-
-
-/*  RETURNS Z = X**Y FOR MP NUMBERS X, Y AND Z, WHERE X IS
- *  POSITIVE (X == 0 ALLOWED IF Y > 0).  SLOWER THAN
- *  MP_PWR_INTEGER AND MPQPWR, SO USE THEM IF POSSIBLE.
- *  DIMENSION OF R IN COMMON AT LEAST 7T+16
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
+static void
 mp_pwr(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
     MPNumber t;
 
+    /* (-x)^y imaginary */
     if (x->sign < 0) {
         mperr(_("Negative X and non-integer Y not supported"));
         mp_set_from_integer(0, z);
+        return;
     }
-    else if (x->sign == 0) 
-    {
-        /* HERE X IS ZERO, RETURN ZERO IF Y POSITIVE, OTHERWISE ERROR */
-        if (y->sign <= 0) {
-            mperr("*** X ZERO AND Y NONPOSITIVE IN CALL TO MP_PWR ***");
-        }
+
+    /* 0^-y illegal */
+    if (x->sign == 0 && y->sign < 0) {
+        mperr("*** X ZERO AND Y NONPOSITIVE IN CALL TO MP_PWR ***");
         mp_set_from_integer(0, z);
+        return;
     }
-    else {
-        /*  USUAL CASE HERE, X POSITIVE
-         *  USE MPLN AND MP_EPOWY TO COMPUTE POWER
-         */
-        mp_ln(x, &t);
-        mp_multiply(y, &t, z);
-
-        /* IF X**Y IS TOO LARGE, MP_EPOWY WILL PRINT ERROR MESSAGE */
-        mp_epowy(z, z);
+    
+    /* 0^0 = 1 */
+    if (x->sign == 0 && y->sign == 0) {
+        mp_set_from_integer(1, z);
+        return;
     }
+
+    mp_ln(x, &t);
+    mp_multiply(y, &t, z);
+    mp_epowy(z, z);
 }
 
 
@@ -1723,7 +1654,7 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
         return;
     }
     
-    if (x->sign < 0  &&  np % 2 == 0) {
+    if (x->sign < 0 && np % 2 == 0) {
         mperr("*** X NEGATIVE AND N EVEN IN CALL TO MP_ROOT ***");
         mp_set_from_integer(0, z);
         return;
@@ -1766,7 +1697,7 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
         while(1) {
             int ts2, ts3;
 
-            mp_pwr_integer(&t1, np, &t2);
+            mp_xpowy_integer(&t1, np, &t2);
             mp_multiply(x, &t2, &t2);
             mp_add_integer(&t2, -1, &t2);
             mp_multiply(&t1, &t2, &t2);
@@ -1801,7 +1732,7 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
     }
 
     if (n >= 0) {
-        mp_pwr_integer(&t1, n - 1, &t1);
+        mp_xpowy_integer(&t1, n - 1, &t1);
         mp_multiply(x, &t1, z);
         return;
     }
@@ -1889,11 +1820,12 @@ mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     return 0;
 }
 
+
 void
 mp_xpowy(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
     if (mp_is_integer(y)) {
-        mp_pwr_integer(x, mp_cast_to_int(y), z);
+        mp_xpowy_integer(x, mp_cast_to_int(y), z);
     } else {
         MPNumber reciprocal;
         mp_reciprocal(y, &reciprocal);
@@ -1903,3 +1835,55 @@ mp_xpowy(const MPNumber *x, const MPNumber *y, MPNumber *z)
             mp_pwr(x, y, z);
     }
 }
+
+
+void
+mp_xpowy_integer(const MPNumber *x, int n, MPNumber *z)
+{
+    int n2, ns;
+    MPNumber t;
+   
+    n2 = n;
+    if (n2 < 0) {
+        /* N < 0 */
+        n2 = -n2;
+        if (x->sign == 0) {
+            mperr("*** ATTEMPT TO RAISE ZERO TO NEGATIVE POWER IN CALL TO SUBROUTINE mp_xpowy_integer ***");
+            mp_set_from_integer(0, z);
+            return;
+        }
+    } else if (n2 == 0) {
+        /* N == 0, RETURN Y = 1. */
+        mp_set_from_integer(1, z);
+        return;
+    } else {
+        /* N > 0 */
+        if (x->sign == 0) {
+            mp_set_from_integer(0, z);
+            return;
+        }
+    }
+
+    /* MOVE X */
+    mp_set_from_mp(x, z);
+
+    /* IF N < 0 FORM RECIPROCAL */
+    if (n < 0)
+        mp_reciprocal(z, z);
+    mp_set_from_mp(z, &t);
+
+    /* SET PRODUCT TERM TO ONE */
+    mp_set_from_integer(1, z);
+
+    /* MAIN LOOP, LOOK AT BITS OF N2 FROM RIGHT */
+    while(1) {
+        ns = n2;
+        n2 /= 2;
+        if (n2 << 1 != ns)
+            mp_multiply(z, &t, z);
+        if (n2 <= 0)
+            return;
+        
+        mp_multiply(&t, &t, &t);
+    }
+}
diff --git a/src/mp.h b/src/mp.h
index a58a432..1cede21 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -2,6 +2,7 @@
 /*  $Header$
  *
  *  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ *  Copyright (c) 2008-2009 Robert Ancell
  *           
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -43,28 +44,31 @@
 /* Size of the multiple precision values */
 #define MP_SIZE 1000
 
+/* Base for numbers */
+#define MP_BASE 10000
+
 /* Object for a high precision floating point number representation
  * 
- * x = sign * (MP.b^(exponent-1) + MP.b^(exponent-2) + ...)
+ * x = sign * (MP_BASE^(exponent-1) + MP_BASE^(exponent-2) + ...)
  */
 typedef struct
 {
    /* Sign (+1, -1) or 0 for the value zero */
    int sign;
 
-   /* Exponent (to base MP.b) */
+   /* Exponent (to base MP_BASE) */
    int exponent;
 
    /* Normalized fraction */
    int fraction[MP_SIZE];
 } MPNumber;
 
-typedef enum { MP_RADIANS, MP_DEGREES, MP_GRADIANS } MPAngleUnit;
-
-/* Initialise the MP state.  Must be called only once and before any other MP function
- * 'accuracy' is the requested accuracy required.
- */
-void   mp_init(int accuracy);
+typedef enum
+{
+    MP_RADIANS,
+    MP_DEGREES,
+    MP_GRADIANS
+} MPAngleUnit;
 
 /* Returns:
  *  0 if x == y
@@ -142,10 +146,10 @@ void   mp_fractional_component(const MPNumber *x, MPNumber *z);
 /* Sets z = integer part of x */
 void   mp_integer_component(const MPNumber *x, MPNumber *z);
 
-/* Sets z = ln(x) */
+/* Sets z = ln x */
 void   mp_ln(const MPNumber *x, MPNumber *z);
 
-/* Sets z = log_n(x) */
+/* Sets z = log_n x */
 void   mp_logarithm(int n, const MPNumber *x, MPNumber *z);
 
 /* Sets z = Ï? */
@@ -154,12 +158,6 @@ void   mp_get_pi(MPNumber *z);
 /* Sets z = e */
 void   mp_get_eulers(MPNumber *z);
 
-/* Sets z = x^y */
-void   mp_pwr(const MPNumber *x, const MPNumber *y, MPNumber *z);
-
-/* Sets z = x^y */
-void   mp_pwr_integer(const MPNumber *x, int y, MPNumber *z);
-
 /* Sets z = nâ??x */
 void   mp_root(const MPNumber *x, int n, MPNumber *z);
 
@@ -169,12 +167,15 @@ void   mp_sqrt(const MPNumber *x, MPNumber *z);
 /* Sets z = x! */
 void   mp_factorial(const MPNumber *x, MPNumber *z);
 
-/* Sets z = x modulo y */
+/* Sets z = x mod y */
 int    mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z);
 
 /* Sets z = x^y */
 void   mp_xpowy(const MPNumber *x, const MPNumber *y, MPNumber *z);
 
+/* Sets z = x^y */
+void   mp_xpowy_integer(const MPNumber *x, int y, MPNumber *z);
+
 /* Sets z = e^x */
 void   mp_epowy(const MPNumber *x, MPNumber *z);
 
@@ -217,40 +218,40 @@ int    mp_cast_to_int(const MPNumber *x);
  */
 void   mp_cast_to_string(const MPNumber *x, int base, int max_digits, int trim_zeroes, char *buffer, int buffer_length);
 
-/* Sets z = sin(x) */
+/* Sets z = sin x */
 void   mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = cos(x) */
+/* Sets z = cos x */
 void   mp_cos(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = tan(x) */
+/* Sets z = tan x */
 void   mp_tan(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = asin(x) */
+/* Sets z = sin�¹ x */
 void   mp_asin(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = acos(x) */
+/* Sets z = cos�¹ x */
 void   mp_acos(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = atan(x) */
+/* Sets z = tan�¹ x */
 void   mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
 
-/* Sets z = sinh(x) */
+/* Sets z = sinh x */
 void   mp_sinh(const MPNumber *x, MPNumber *z);
 
-/* Sets z = cosh(x) */
+/* Sets z = cosh x */
 void   mp_cosh(const MPNumber *x, MPNumber *z);
 
-/* Sets z = tanh(x) */
+/* Sets z = tanh x */
 void   mp_tanh(const MPNumber *x, MPNumber *z);
 
-/* Sets z = asinh(x) */
+/* Sets z = sinh�¹ x */
 void   mp_asinh(const MPNumber *x, MPNumber *z);
 
-/* Sets z = acosh(x) */
+/* Sets z = cosh�¹ x */
 void   mp_acosh(const MPNumber *x, MPNumber *z);
 
-/* Sets z = atanh(x) */
+/* Sets z = tanh�¹ x */
 void   mp_atanh(const MPNumber *x, MPNumber *z);
 
 /* Returns true if x is cannot be represented in a binary word of length 'wordlen' */



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