[gcalctool] Tidy up MP code, removing global variables etc



commit 481b6e1dacaa0009d6352556c190bb0d331e52a3
Author: Robert Ancell <robert ancell gmail com>
Date:   Mon Jul 13 12:51:26 2009 +1000

    Tidy up MP code, removing global variables etc

 src/calctool.c           |    1 -
 src/display.c            |    5 +-
 src/financial.c          |    8 +-
 src/gtk.c                |   11 +-
 src/mp-binary.c          |    2 +-
 src/mp-convert.c         |  233 +++++++----
 src/mp-equation-parser.y |   14 +-
 src/mp-internal.h        |   23 +-
 src/mp-trigonometric.c   |  630 ++++++++++----------------
 src/mp.c                 | 1139 ++++++++++++++++------------------------------
 src/mp.h                 |   67 ++--
 11 files changed, 850 insertions(+), 1283 deletions(-)
---
diff --git a/src/calctool.c b/src/calctool.c
index 1516758..948c5c9 100644
--- a/src/calctool.c
+++ b/src/calctool.c
@@ -202,7 +202,6 @@ init_state(void)
     int acc, i;
 
     acc              = MAX_DIGITS + 12;     /* MP internal accuracy. */
-    mp_init(acc);
 
     v->error         = FALSE;  /* No calculator error initially. */
     v->radix         = get_radix();    /* Locale specific radix string. */
diff --git a/src/display.c b/src/display.c
index 2290cb6..583a949 100644
--- a/src/display.c
+++ b/src/display.c
@@ -711,9 +711,8 @@ make_eng_sci(GCDisplay *display, char *target, int target_len, const MPNumber *M
     mp_set_from_mp(&MPval, &MPmant);
 
     mp_set_from_integer(basevals[base], &MP1base);
-    mp_pwr_integer(&MP1base, 3, &MP3base);
-
-    mp_pwr_integer(&MP1base, 10, &MP10base);
+    mp_xpowy_integer(&MP1base, 3, &MP3base);
+    mp_xpowy_integer(&MP1base, 10, &MP10base);
 
     mp_set_from_integer(1, &MP1);
     mp_divide(&MP1, &MP10base, &MPatmp);
diff --git a/src/financial.c b/src/financial.c
index 17c6689..1058666 100644
--- a/src/financial.c
+++ b/src/financial.c
@@ -98,7 +98,7 @@ calc_fv(MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
     MPNumber MP1, MP2, MP3, MP4;
   
     mp_add_integer(pint, 1, &MP1);
-    mp_pwr(&MP1, n, &MP2);
+    mp_xpowy(&MP1, n, &MP2);
     mp_add_integer(&MP2, -1, &MP3);
     mp_multiply(pmt, &MP3, &MP4);
     mp_divide(&MP4, pint, t);
@@ -138,7 +138,7 @@ calc_pmt(MPNumber *t, MPNumber *prin, MPNumber *pint, MPNumber *n)
 
     mp_add_integer(pint, 1, &MP1);
     mp_multiply_integer(n, -1, &MP2);
-    mp_pwr(&MP1, &MP2, &MP3);
+    mp_xpowy(&MP1, &MP2, &MP3);
     mp_multiply_integer(&MP3, -1, &MP4);
     mp_add_integer(&MP4, 1, &MP1);
     mp_divide(pint, &MP1, &MP2);
@@ -161,7 +161,7 @@ calc_pv(MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
 
     mp_add_integer(pint, 1, &MP1);
     mp_multiply_integer(n, -1, &MP2);
-    mp_pwr(&MP1, &MP2, &MP3);
+    mp_xpowy(&MP1, &MP2, &MP3);
     mp_multiply_integer(&MP3, -1, &MP4);
     mp_add_integer(&MP4, 1, &MP1);
     mp_divide(&MP1, pint, &MP2);
@@ -185,7 +185,7 @@ calc_rate(MPNumber *t, MPNumber *fv, MPNumber *pv, MPNumber *n)
     mp_divide(fv, pv, &MP1);
     mp_set_from_integer(1, &MP2);
     mp_divide(&MP2, n, &MP3);
-    mp_pwr(&MP1, &MP3, &MP4);
+    mp_xpowy(&MP1, &MP3, &MP4);
     mp_add_integer(&MP4, -1, t);
 }
 
diff --git a/src/gtk.c b/src/gtk.c
index 107e505..49176e6 100644
--- a/src/gtk.c
+++ b/src/gtk.c
@@ -553,12 +553,21 @@ typedef enum {
     POPUP_CENTERED   /* Center popup within baseframe */
 } PopupLocation;
 
+#include <sys/time.h>
+
 static void load_ui(GtkBuilder *ui, const gchar *filename)
 {
     GError *error = NULL;
     GtkWidget *dialog;
+    struct timeval start, stop;
 
+    gettimeofday(&start, NULL);
     gtk_builder_add_from_file(ui, filename, &error);
+    gettimeofday(&stop, NULL);
+    if (start.tv_usec > stop.tv_usec)
+        printf("t=%lu.%-6lu\n", stop.tv_sec - start.tv_sec - 1, 1000000 + stop.tv_usec - start.tv_usec);
+    else
+        printf("t=%lu.%-6lu\n", stop.tv_sec - start.tv_sec, stop.tv_usec - start.tv_usec);
     if (error == NULL)
         return;
         
@@ -569,7 +578,7 @@ static void load_ui(GtkBuilder *ui, const gchar *filename)
                                     N_("Error loading user interface"));
     gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
                                              /* Translators: Description in UI error dialog when unable to load the UI files. %s is replaced with the error message provided by GTK+ */
-                                             N_("A required file is missing, please check your installation.\n\n%s"), error->message);
+                                             N_("A required file is missing or damaged, please check your installation.\n\n%s"), error->message);
     gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
     
     gtk_dialog_run(GTK_DIALOG(dialog));
diff --git a/src/mp-binary.c b/src/mp-binary.c
index e9b10b7..b97fc98 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -66,7 +66,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 4a3512e..d09473c 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -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
@@ -31,17 +32,10 @@
  *  SEE IF X AND Y HAVE THE SAME ADDRESS (THEY OFTEN DO)
  */
 void
-mp_set_from_mp(const MPNumber *x, MPNumber *y)
+mp_set_from_mp(const MPNumber *x, MPNumber *z)
 {
-    /* HERE X AND Y MUST HAVE THE SAME ADDRESS */    
-    if (x == y)
-        return;
-
-    /* NO NEED TO COPY X[1],X[2],... IF X[0] == 0 */
-    if (x->sign == 0)
-        y->sign = 0;
-    else
-        memcpy (y, x, (MP.t + 2) * sizeof(int));
+    if (z != x)
+        memcpy(z, x, sizeof(MPNumber));
 }
 
 /*  CONVERTS SINGLE-PRECISION NUMBER RX TO MULTIPLE-PRECISION Z.
@@ -55,8 +49,9 @@ mp_set_from_float(float rx, MPNumber *z)
     int i, k, i2, ib, ie, tp;
     float rb, rj;
     
-    mpchk();
-    i2 = MP.t + 4;
+    i2 = MP_T + 4;
+    
+    memset(z, 0, sizeof(MPNumber));
 
     /* CHECK SIGN */
     if (rx < (float) 0.0) {
@@ -67,7 +62,7 @@ mp_set_from_float(float rx, MPNumber *z)
         rj = rx;
     } else {
         /* IF RX = 0E0 RETURN 0 */
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -88,7 +83,7 @@ mp_set_from_float(float rx, MPNumber *z)
      *  SET EXPONENT TO 0
      */
     z->exponent = 0;
-    rb = (float) MP.b;
+    rb = (float) MP_BASE;
 
     /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
     for (i = 0; i < i2; i++) {
@@ -101,7 +96,7 @@ mp_set_from_float(float rx, MPNumber *z)
     mp_normalize(z, 0);
 
     /* Computing MAX */
-    ib = max(MP.b * 7 * MP.b, 32767) / 16;
+    ib = max(MP_BASE * 7 * MP_BASE, 32767) / 16;
     tp = 1;
 
     /* NOW MULTIPLY BY 16**IE */
@@ -109,7 +104,7 @@ mp_set_from_float(float rx, MPNumber *z)
         k = -ie;
         for (i = 1; i <= k; ++i) {
             tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < k)
+            if (tp <= ib && tp != MP_BASE && i < k)
                 continue;
             mp_divide_integer(z, tp, z);
             tp = 1;
@@ -117,7 +112,7 @@ mp_set_from_float(float rx, MPNumber *z)
     } else if (ie > 0)  {
         for (i = 1; i <= ie; ++i) {
             tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < ie)
+            if (tp <= ib && tp != MP_BASE && i < ie)
                 continue;
             mp_multiply_integer(z, tp, z);
             tp = 1;
@@ -146,8 +141,9 @@ mp_set_from_double(double dx, MPNumber *z)
     int i, k, i2, ib, ie, tp;
     double db, dj;
 
-    mpchk();
-    i2 = MP.t + 4;
+    i2 = MP_T + 4;
+
+    memset(z, 0, sizeof(MPNumber));
 
     /* CHECK SIGN */
     if (dx < 0.)  {
@@ -157,7 +153,7 @@ mp_set_from_double(double dx, MPNumber *z)
         z->sign = 1;
         dj = dx;
     } else {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     } 
 
@@ -173,7 +169,7 @@ mp_set_from_double(double dx, MPNumber *z)
      */
     z->exponent = 0;
 
-    db = (double) MP.b;
+    db = (double) MP_BASE;
 
     /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
     for (i = 0; i < i2; i++) {
@@ -186,7 +182,7 @@ mp_set_from_double(double dx, MPNumber *z)
     mp_normalize(z, 0);
 
     /* Computing MAX */
-    ib = max(MP.b * 7 * MP.b, 32767) / 16;
+    ib = max(MP_BASE * 7 * MP_BASE, 32767) / 16;
     tp = 1;
 
     /* NOW MULTIPLY BY 16**IE */
@@ -194,7 +190,7 @@ mp_set_from_double(double dx, MPNumber *z)
         k = -ie;
         for (i = 1; i <= k; ++i) {
             tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < k)
+            if (tp <= ib && tp != MP_BASE && i < k)
                 continue;
             mp_divide_integer(z, tp, z);
             tp = 1;
@@ -202,7 +198,7 @@ mp_set_from_double(double dx, MPNumber *z)
     } else if (ie > 0) {
         for (i = 1; i <= ie; ++i) {
             tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < ie)
+            if (tp <= ib && tp != MP_BASE && i < ie)
                 continue;
             mp_multiply_integer(z, tp, z);
             tp = 1;
@@ -219,10 +215,10 @@ mp_set_from_double(double dx, MPNumber *z)
 void
 mp_set_from_integer(int ix, MPNumber *z)
 {
-    mpchk();
+    memset(z, 0, sizeof(MPNumber));
 
     if (ix == 0) {
-        z->sign = 0;
+        z->exponent = 1;
         return;
     }
 
@@ -234,13 +230,10 @@ mp_set_from_integer(int ix, MPNumber *z)
         z->sign = 1;
 
     /* SET EXPONENT TO T */
-    z->exponent = MP.t;
-
-    /* CLEAR FRACTION */
-    memset(z->fraction, 0, (MP.t-1)*sizeof(int));
+    z->exponent = MP_T;
 
     /* INSERT IX */
-    z->fraction[MP.t - 1] = ix;
+    z->fraction[MP_T - 1] = ix;
 
     /* NORMALIZE BY CALLING MPMUL2 */
     mpmul2(z, 1, z, 1);
@@ -248,23 +241,24 @@ mp_set_from_integer(int ix, MPNumber *z)
 
 /* CONVERTS THE RATIONAL NUMBER I/J TO MULTIPLE PRECISION Q. */
 void
-mp_set_from_fraction(int i, int j, MPNumber *q)
+mp_set_from_fraction(int i, int j, MPNumber *z)
 {
     mpgcd(&i, &j);
 
     if (j == 0) {
-      mperr("*** J == 0 IN CALL TO MP_SET_FROM_FRACTION ***\n");
-      q->sign = 0;
-      return;
+        mperr("*** J == 0 IN CALL TO MP_SET_FROM_FRACTION ***\n");
+        mp_set_from_integer(0, z);
+        return;
     }
 
     if (j < 0) {
-      i = -i;
-      j = -j;
+        i = -i;
+        j = -j;
     }
 
-    mp_set_from_integer(i, q);
-    if (j != 1) mp_divide_integer(q, j, q);
+    mp_set_from_integer(i, z);
+    if (j != 1)
+        mp_divide_integer(z, j, z);
 }
 
 /*  CONVERTS MULTIPLE-PRECISION X TO INTEGER, AND
@@ -291,8 +285,8 @@ mp_cast_to_int(const MPNumber *x)
     for (i = 0; i < x2; i++) {
         int izs;
         izs = ret_val;
-        ret_val = MP.b * ret_val;
-        if (i < MP.t)
+        ret_val = MP_BASE * ret_val;
+        if (i < MP_T)
             ret_val += x->fraction[i];
 
         /* CHECK FOR SIGNS OF INTEGER OVERFLOW */
@@ -307,11 +301,11 @@ mp_cast_to_int(const MPNumber *x)
     for (i = x2 - 1; i >= 0; i--) {
         int j1, kx;
         
-        j1 = j / MP.b;
+        j1 = j / MP_BASE;
         kx = 0;
-        if (i < MP.t)
+        if (i < MP_T)
             kx = x->fraction[i];
-        if (kx != j - MP.b * j1)
+        if (kx != j - MP_BASE * j1)
             return 0;
         j = j1;
     }
@@ -366,12 +360,11 @@ mp_cast_to_float(const MPNumber *x)
     int i;
     float rb, rz = 0.0;
     
-    mpchk();
     if (x->sign == 0)
         return 0.0;
 
-    rb = (float) MP.b;
-    for (i = 0; i < MP.t; i++) {
+    rb = (float) MP_BASE;
+    for (i = 0; i < MP_T; i++) {
         rz = rb * rz + (float)x->fraction[i];
 
         /* CHECK IF FULL SINGLE-PRECISION ACCURACY ATTAINED */
@@ -385,7 +378,7 @@ mp_cast_to_float(const MPNumber *x)
     /* CHECK REASONABLENESS OF RESULT */
     /* LHS SHOULD BE <= 0.5, BUT ALLOW FOR SOME ERROR IN ALOG */
     if (rz <= (float)0. ||
-        fabs((float) x->exponent - (log(rz) / log((float) MP.b) + (float).5)) > (float).6) {
+        fabs((float) x->exponent - (log(rz) / log((float) MP_BASE) + (float).5)) > (float).6) {
         /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
          *  TRY USING MPCMRE INSTEAD.
          */
@@ -433,12 +426,11 @@ mp_cast_to_double(const MPNumber *x)
     int i, tm = 0;
     double d__1, db, dz2, ret_val = 0.0;
 
-    mpchk();
     if (x->sign == 0)
         return 0.0;
 
-    db = (double) MP.b;
-    for (i = 0; i < MP.t; i++) {
+    db = (double) MP_BASE;
+    for (i = 0; i < MP_T; i++) {
         ret_val = db * ret_val + (double) x->fraction[i];
         tm = i;
 
@@ -459,7 +451,7 @@ mp_cast_to_double(const MPNumber *x)
     /* LHS SHOULD BE .LE. 0.5 BUT ALLOW FOR SOME ERROR IN DLOG */
     if (ret_val <= 0. ||
         ((d__1 = (double) ((float) x->exponent) - (log(ret_val) / log((double)
-                ((float) MP.b)) + .5), abs(d__1)) > .6)) {
+                ((float) MP_BASE)) + .5), abs(d__1)) > .6)) {
         /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
          *  TRY USING MPCMDE INSTEAD.
          */
@@ -495,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);
@@ -556,20 +548,69 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, int trim_zeroes, ch
 
 
 static int
-char_val(char chr, int base)
+char_val(char **c, int base)
 {
-    int value;
-    if (chr >= '0' && chr <= '9') {
-        value = chr - '0';
-    } else if (chr >= 'a' && chr <= 'f') {
-        value = chr - 'a' + 10;
-    } else if (chr >= 'A' && chr <= 'F') {
-        value = chr - 'A' + 10;
+    int i, j, value, offset;
+    const char *digits[][10] = {{"Ù ", "Ù¡", "Ù¢", "Ù£", "Ù¤", "Ù¥", "Ù¦", "Ù§", "Ù¨", "Ù©"},
+                                {"Û°", "Û±", "Û²", "Û³", "Û´", "Ûµ", "Û¶", "Û·", "Û¸", "Û¹"},
+                                {"ß?", "ß?", "ß?", "ß?", "ß?", "ß?", "ß?", "ß?", "ß?", "ß?"},
+                                {"०", "१", "२", "३", "४", "५", "६", "७", "८", "९"},
+                                {"০", "১", "২", "৩", "৪", "৫", "৬", "৭", "৮", "৯"},
+                                {"੦", "੧", "੨", "੩", "੪", "੫", "੬", "੭", "੮", "੯"},
+                                {"૦", "૧", "૨", "૩", "૪", "૫", "૬", "૭", "૮", "૯"},
+                                {"à­¦", "à­§", "à­¨", "à­©", "à­ª", "à­«", "à­¬", "à­­", "à­®", "à­¯"},
+                                {"௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯"},
+                                {"౦", "౧", "౨", "౩", "౪", "౫", "౬", "౭", "౮", "౯"},
+                                {"೦", "೧", "೨", "೩", "೪", "೫", "೬", "೭", "೮", "೯"},
+                                {"൦", "൧", "൨", "൩", "൪", "൫", "൬", "൭", "൮", "൯"},
+                                {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"},
+                                {"à»?", "à»?", "à»?", "à»?", "à»?", "à»?", "à»?", "à»?", "à»?", "à»?"},
+                                {"༠", "༡", "༢", "༣", "༤", "༥", "༦", "༧", "༨", "༩"},
+                                {"á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??"},
+                                {"á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??", "á??"},
+                                {"á? ", "á?¡", "á?¢", "á?£", "á?¤", "á?¥", "á?¦", "á?§", "á?¨", "á?©"},
+                                {"á ?", "á ?", "á ?", "á ?", "á ?", "á ?", "á ?", "á ?", "á ?", "á ?"},
+                                {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"},
+                                {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"},
+                                {"á­?", "á­?", "á­?", "á­?", "á­?", "á­?", "á­?", "á­?", "á­?", "á­?"},
+                                {"᮰", "᮱", "᮲", "᮳", "᮴", "᮵", "᮶", "᮷", "᮸", "᮹"},
+                                {"á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?"},
+                                {"á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?", "á±?"},
+                                {"ê? ", "ê?¡", "ê?¢", "ê?£", "ê?¤", "ê?¥", "ê?¦", "ê?§", "ê?¨", "ê?©"},
+                                {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"},
+                                {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"},
+                                {"ê©?", "ê©?", "ê©?", "ê©?", "ê©?", "ê©?", "ê©?", "ê©?", "ê©?", "ê©?"},
+                                {"ð?? ", "ð??¡", "ð??¢", "ð??£", "ð??¤", "ð??¥", "ð??¦", "ð??§", "ð??¨", "ð??©"},
+                                {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
+
+    if (**c >= '0' && **c <= '9') {
+        value = **c - '0';
+        offset = 1;
+    } else if (**c >= 'a' && **c <= 'f') {
+        value = **c - 'a' + 10;
+        offset = 1;
+    } else if (**c >= 'A' && **c <= 'F') {
+        value = **c - 'A' + 10;
+        offset = 1;
     } else {
-        return -1;
+        for (i = 0; digits[i][0]; i++) {
+            for (j = 0; j < 10; j++) {
+                if (strncmp(*c, digits[i][j], strlen(digits[i][j])) == 0)
+                    break;
+            }
+            if (j != 10)
+                break;
+        }
+        if (digits[i][0] == NULL)
+            return -1;
+        value = j;
+        offset = strlen(digits[i][j]);
     }
     if (value >= base)
        return -1;
+    
+    *c += offset;
+
     return value;
 }
 
@@ -578,19 +619,37 @@ char_val(char chr, int base)
 void
 mp_set_from_string(const char *str, int base, MPNumber *z)
 {
-    int i, negate = 0;
+    int i, negate = 0, multiplier = 0;
     const char *c, *end;
-    const char *fractions[] = {"½", "â??", "â??", "¼", "¾", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
-    int numerators[]        = { 1,   1,   2,   1,   3,   1,   2,   3,   4,   1,   5,   1,   3,   5,   7};
-    int denominators[]      = { 2,   3,   3,   4,   4,   5,   5,   5,   5,   6,   6,   8,   8,   8,   8};
+    gboolean has_fraction = FALSE;
+    
+    const char *base_suffixes[] = {"â??", "â??", "â??â??", NULL};
+    int base_values[]           = {2, 8, 16, 10};
+    const char *fractions[]     = {"½", "â??", "â??", "¼", "¾", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
+    int numerators[]            = { 1,   1,   2,   1,   3,   1,   2,   3,   4,   1,   5,   1,   3,   5,   7};
+    int denominators[]          = { 2,   3,   3,   4,   4,   5,   5,   5,   5,   6,   6,   8,   8,   8,   8};
+    const char *si_suffixes[]   = {"T", "G", "M", "k", "d", "c", "m", "u", "µ", "n", "p", "f", NULL};
+    int si_multipliers[]        = { 12,   9,   6,   3,  -1,  -2,  -3,  -6,  -6,  -9, -12, -15};
     
+    /* Find the base */
     end = str;
     while (*end != '\0')
         end++;
+    if (base < 0) {
+        for (i = 0; base_suffixes[i] != NULL; i++) {
+            if (end - strlen(base_suffixes[i]) < str)
+                continue;
+            if (strcmp(end - strlen(base_suffixes[i]), base_suffixes[i]) == 0)
+                break;
+        }
+        base = base_values[i];
+    }
 
-    /* Check if this is a negative number */
+    /* Check if this has a sign */
     c = str;
-    if (*c == '-') {
+    if (*c == '+') {
+        c++;
+    } else if (*c == '-') {
         negate = 1;
         c++;
     } else if (strncmp(c, "â??", strlen("â??")) == 0) {
@@ -600,13 +659,12 @@ mp_set_from_string(const char *str, int base, MPNumber *z)
 
     /* Convert integer part */
     mp_set_from_integer(0, z);
-    while ((i = char_val(*c, base)) >= 0) {
+    while ((i = char_val((char **)&c, base)) >= 0) {
         mp_multiply_integer(z, base, z);
         mp_add_integer(z, i, z);
-        c++;
     }
     
-    /* Look for fraction characters */
+    /* Look for fraction characters, e.g. â?? */
     for (i = 0; fractions[i] != NULL; i++) {
         if (end - strlen(fractions[i]) < str)
             continue;
@@ -618,20 +676,32 @@ mp_set_from_string(const char *str, int base, MPNumber *z)
         mp_set_from_fraction(numerators[i], denominators[i], &fraction);
         mp_add(z, &fraction, z);
     }
+    
+    if (*c == '.') {
+        has_fraction = TRUE;
+        c++;
+    } else {
+        for (i = 0; si_suffixes[i] != NULL; i++) {
+            if (strncmp(c, si_suffixes[i], strlen(si_suffixes[i])) == 0)
+                break;
+        }
+        if (si_suffixes[i] != NULL) {
+            has_fraction = TRUE;
+            multiplier = si_multipliers[i];
+            c += strlen(si_suffixes[i]);
+        }
+    }
    
     /* Convert fractional part */
-    if (*c == '.') {
+    if (has_fraction) {
         MPNumber numerator, denominator;
-       
-        c++;
 
         mp_set_from_integer(0, &numerator);
         mp_set_from_integer(1, &denominator);
-        while ((i = char_val(*c, base)) >= 0) {
+        while ((i = char_val((char **)&c, base)) >= 0) {
             mp_multiply_integer(&denominator, base, &denominator);
             mp_multiply_integer(&numerator, base, &numerator);
             mp_add_integer(&numerator, i, &numerator);
-            c++;
         }
         mp_divide(&numerator, &denominator, &numerator);
         mp_add(z, &numerator, z);
@@ -657,7 +727,7 @@ mp_set_from_string(const char *str, int base, MPNumber *z)
 
         /* Get magnitude */
         mp_set_from_integer(0, &MPexponent);
-        while ((i = char_val(*c, base)) >= 0) {
+        while ((i = char_val((char **)&c, base)) >= 0) {
             mp_multiply_integer(&MPexponent, base, &MPexponent);
             mp_add_integer(&MPexponent, i, &MPexponent);
             c++;
@@ -667,13 +737,20 @@ mp_set_from_string(const char *str, int base, MPNumber *z)
         }
 
         mp_set_from_integer(base, &MPbase);       
-        mp_pwr(&MPbase, &MPexponent, &temp);
+        mp_xpowy(&MPbase, &MPexponent, &temp);
         mp_multiply(z, &temp, z);
     }
    
     if (c != end) {
        // FIXME: Error decoding
     }
+    
+    if (multiplier != 0) {
+        MPNumber t;
+        mp_set_from_integer(10, &t);
+        mp_xpowy_integer(&t, multiplier, &t);
+        mp_multiply(z, &t, z);
+    }
  
     if (negate == 1)
         mp_invert_sign(z, z);
diff --git a/src/mp-equation-parser.y b/src/mp-equation-parser.y
index e14b8c7..7fe28bd 100644
--- a/src/mp-equation-parser.y
+++ b/src/mp-equation-parser.y
@@ -202,7 +202,7 @@ term:
 | tABS exp tABS {mp_abs(&$2, &$$);}
 | 'e' '^' term {mp_epowy(&$3, &$$);} 
 | term '!' {mp_factorial(&$1, &$$);}
-| term tSUPNUM {mp_pwr_integer(&$1, $2, &$$);}
+| term tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
 | term '%' {mp_divide_integer(&$1, 100, &$$);}
 | tNOT term %prec LNEG {
     if (!mp_is_natural(&$2)) {
@@ -233,18 +233,18 @@ func:
 | tSIN term %prec HIGH {mp_sin(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
 | tCOS term %prec HIGH {mp_cos(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
 | tTAN term %prec HIGH {mp_tan(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tSIN tSUPNUM term %prec HIGH {MPNumber t; mp_sin(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_pwr_integer(&t, $2, &$$);}
-| tCOS tSUPNUM term %prec HIGH {MPNumber t; mp_cos(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_pwr_integer(&t, $2, &$$);}
-| tTAN tSUPNUM term %prec HIGH {MPNumber t; mp_tan(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_pwr_integer(&t, $2, &$$);}
+| tSIN tSUPNUM term %prec HIGH {MPNumber t; mp_sin(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
+| tCOS tSUPNUM term %prec HIGH {MPNumber t; mp_cos(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
+| tTAN tSUPNUM term %prec HIGH {MPNumber t; mp_tan(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
 | tASIN term %prec HIGH {mp_asin(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
 | tACOS term %prec HIGH {mp_acos(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
 | tATAN term %prec HIGH {mp_atan(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
 | tSINH term %prec HIGH {mp_sinh(&$2, &$$);}
 | tCOSH term %prec HIGH {mp_cosh(&$2, &$$);}
 | tTANH term %prec HIGH {mp_tanh(&$2, &$$);}
-| tSINH tSUPNUM term %prec HIGH {MPNumber t; mp_sinh(&$3, &t); mp_pwr_integer(&t, $2, &$$);}
-| tCOSH tSUPNUM term %prec HIGH {MPNumber t; mp_cosh(&$3, &t); mp_pwr_integer(&t, $2, &$$);}
-| tTANH tSUPNUM term %prec HIGH {MPNumber t; mp_tanh(&$3, &t); mp_pwr_integer(&t, $2, &$$);}
+| tSINH tSUPNUM term %prec HIGH {MPNumber t; mp_sinh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
+| tCOSH tSUPNUM term %prec HIGH {MPNumber t; mp_cosh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
+| tTANH tSUPNUM term %prec HIGH {MPNumber t; mp_tanh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
 | tASINH term %prec HIGH {mp_asinh(&$2, &$$);}
 | tACOSH term %prec HIGH {mp_acosh(&$2, &$$);}
 | tATANH term %prec HIGH {mp_atanh(&$2, &$$);}
diff --git a/src/mp-internal.h b/src/mp-internal.h
index 2fc231a..d47695b 100644
--- a/src/mp-internal.h
+++ b/src/mp-internal.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
@@ -32,25 +33,17 @@
 #define min(a, b)   ((a) <= (b) ? (a) : (b))
 #define max(a, b)   ((a) >= (b) ? (a) : (b))
 
-/* Evil global variables that must be removed */
-struct {
-    /* Base */
-    int b;
-
-    /* Number of digits */
-    // This number is temporarily changed across calls to add/subtract/multiply/divide - it should be passed to those calls
-    int t;
-
-    /* Min/max exponent value */
-    int m;
-} MP;
+//2E0 BELOW ENSURES AT LEAST ONE GUARD DIGIT
+//MP.t = (int) ((float) (accuracy) * log((float)10.) / log((float) MP_BASE) + (float) 2.0);
+//if (MP.t > MP_SIZE) {
+//    mperr("MP_SIZE TOO SMALL IN CALL TO MPSET, INCREASE MP_SIZE AND DIMENSIONS OF MP ARRAYS TO AT LEAST %d ***", MP.t);
+//    MP.t = MP_SIZE;
+//}
+#define MP_T 55
 
 void mperr(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void mpchk();
 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 ddfaaf7..ac46df7 100644
--- a/src/mp-trigonometric.c
+++ b/src/mp-trigonometric.c
@@ -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
@@ -31,161 +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;
-   
-    mpchk();
-
-    /* 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;
-
-    mpchk();
-
-    /* SIN(0) = 0, COS(0) = 1 */
-    if (x->sign == 0) {
-        z->sign = 0;
-        if (do_sin == 0)
-            mp_set_from_integer(1, z);
-        return;
-    }
-
-    b2 = max(MP.b, 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);
-
-    z->sign = 0;
-    i = 1;
-    if (do_sin != 0) {
-        mp_set_from_mp(&t1, z);
-        i = 2;
-    }
-
-    /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
-    for (; ; i+= 2) {
-        int t, ts;
-        
-        t = MP.t + t1.exponent + 2;
-        if (t <= 2)
-            break;
-        t = min(t, MP.t);
-
-        /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
-         *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
-         */
-        ts = MP.t;
-        MP.t = t;
-        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.t = ts;
-        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;
-
-    mpchk();
-    if (n <= 1) {
-        mperr("*** N <= 1 IN CALL TO MP_ATAN1N ***");
-        z->sign = 0;
-        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.b, 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) {
-        int t, ts;
-
-        t = MP.t + 2 + t2.exponent - z->exponent;
-        if (t <= 1)
-            break;
-        t = min(t, MP.t);
-
-        /*  IF (I+2)*N**2 IS NOT REPRESENTABLE AS AN INTEGER THE DIVISION
-         *  FOLLOWING HAS TO BE PERFORMED IN SEVERAL STEPS.
-         */
-        ts = MP.t;
-        MP.t = t;
-        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);
-        }
-        MP.t = ts;
-
-        /* ADD TO SUM */
-        mp_add(&t2, z, z);
-        if (t2.sign == 0)
-            break;
-    }
-}
-
 
 /* Convert x to radians */
 static void
@@ -213,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", 10, z);
+}
+
+
 static void
 convert_from_radians(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
@@ -238,30 +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_multiply(x, x, &t2);
+    if (mp_compare_mp_to_int(&t2, 1) > 0) {
+        mperr("*** ABS(X) > 1 IN CALL TO MPSIN1 ***");
+    }
 
-    mpchk();
+    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;
+    }
 
-    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);
+    /* 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);
 }
 
 
@@ -276,75 +172,69 @@ mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     int ie, xs;
     float rx = 0.0;
-    MPNumber t1, t2;
+    MPNumber x_radians;
 
-    mpchk();
-    
-    convert_to_radians(x, unit, &t1);
-    
-    if (t1.sign == 0) {
-        z->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) {
-            z->sign = 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) {
-            z->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);
         }
     }
 
@@ -368,28 +258,22 @@ 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;
     }
 
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
-
     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);
@@ -403,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);
 }
 
@@ -427,9 +313,9 @@ mp_asin(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 {
     MPNumber t1, t2;
 
-    mpchk();
+    /* asin(0) = 0 */
     if (x->sign == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -476,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");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
     } else if (x->sign == 0) {
-        mp_divide_integer(&MPpi, 2, z);
-    } else if (mp_is_equal(x, &MP1)) {
-        z->sign = 0;
+        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);
         }
     }
     
@@ -511,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,
@@ -526,9 +412,8 @@ mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
     float rx = 0.0;
     MPNumber t1, t2;
 
-    mpchk();
     if (x->sign == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -540,7 +425,7 @@ mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
     q = 1;
     while (t2.exponent >= 0)
     {
-        if (t2.exponent == 0 && (t2.fraction[0] + 1) << 1 <= MP.b)
+        if (t2.exponent == 0 && (t2.fraction[0] + 1) << 1 <= MP_BASE)
             break;
 
         q <<= 1;
@@ -557,18 +442,11 @@ mp_atan(const MPNumber *x, MPAngleUnit unit, MPNumber *z)
 
     /* SERIES LOOP.  REDUCE T IF POSSIBLE. */
     for (i = 1; ; i += 2) {
-        int t, ts;
-        
-        t = MP.t + 2 + t2.exponent;
-        if (t <= 1)
+        if (MP_T + 2 + t2.exponent <= 1)
             break;
-        t = min(t, MP.t);
         
-        ts = MP.t;
-        MP.t = t;
         mp_multiply(&t2, &t1, &t2);
         mp_multiply_fraction(&t2, -i, i + 2, &t2);
-        MP.t = ts;
 
         mp_add(z, &t2, z);
         if (t2.sign == 0)
@@ -592,208 +470,164 @@ 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");
-        z->sign = 0;
-    } 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", 10, &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;
     }
 
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
+    /* cosh(x) = (e^x + e^-x) / 2 */
     mp_abs(x, &t);
-
-    /*  IF ABS(X) TOO LARGE MP_EPOWY WILL PRINT ERROR MESSAGE
-     *  INCREASE M TO AVOID OVERFLOW WHEN COSH(X) REPRESENTABLE
-     */
-    MP.m += 2;
     mp_epowy(&t, &t);
     mp_reciprocal(&t, z);
     mp_add(&t, z, z);
-
-    /*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, mp_divide_integer WILL
-     *  ACT ACCORDINGLY.
-     */
-    MP.m += -2;
     mp_divide_integer(z, 2, 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) {
-        z->sign = 0;
-        return;
-    }
-
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
-
-    /* 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.m += 2;
-        mp_epowy(&t2, &t2);
-        mp_reciprocal(&t2, z);
-        mp_subtract(&t2, z, z);
-
-        /*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, mp_divide_integer AT
-         *  STATEMENT 30 WILL ACT ACCORDINGLY.
-         */
-        MP.m += -2;
-    }
-
-    /* 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) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
-
-    /* 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.b);
+    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 5689ddb..9400f3e 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -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
@@ -28,90 +29,23 @@
 #include "mp-internal.h"
 #include "calctool.h" // FIXME: Required for doerr() and MAXLINE
 
-// FIXME: MP.t and MP.m modified inside functions, needs to be fixed to be thread safe
 
-/*  SETS X TO THE LARGEST POSSIBLE POSITIVE MP NUMBER
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static void
-mpmaxr(MPNumber *x)
-{
-    int i, it;
-
-    mpchk();
-    it = MP.b - 1;
-
-    /* SET FRACTION DIGITS TO B-1 */
-    for (i = 0; i < MP.t; i++)
-        x->fraction[i] = it;
-
-    /* SET SIGN AND EXPONENT */
-    x->sign = 1;
-    x->exponent = MP.m;
-}
-
-
-/*  CALLED ON MULTIPLE-PRECISION OVERFLOW, IE WHEN THE
- *  EXPONENT OF MP NUMBER X WOULD EXCEED M.
- *  AT PRESENT EXECUTION IS TERMINATED WITH AN ERROR MESSAGE
- *  AFTER CALLING MPMAXR(X), BUT IT WOULD BE POSSIBLE TO RETURN,
- *  POSSIBLY UPDATING A COUNTER AND TERMINATING EXECUTION AFTER
- *  A PRESET NUMBER OF OVERFLOWS.  ACTION COULD EASILY BE DETERMINED
- *  BY A FLAG IN LABELLED COMMON.
- *  M MAY HAVE BEEN OVERWRITTEN, SO CHECK B, T, M ETC.
- */
-static void
-mpovfl(MPNumber *x, const char *error)
-{
-    fprintf(stderr, "%s\n", error);
-    
-    mpchk();
-
-    /* SET X TO LARGEST POSSIBLE POSITIVE NUMBER */
-    mpmaxr(x);
-
-    /* TERMINATE EXECUTION BY CALLING MPERR */
-    mperr("*** CALL TO MPOVFL, MP OVERFLOW OCCURRED ***");
-}
+// FIXME: Re-add overflow and underflow detection
 
 
-/*  CALLED ON MULTIPLE-PRECISION UNDERFLOW, IE WHEN THE
- *  EXPONENT OF MP NUMBER X WOULD BE LESS THAN -M.
- *  SINCE M MAY HAVE BEEN OVERWRITTEN, CHECK B, T, M ETC.
+/*  THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
+ *  AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
  */
-static void
-mpunfl(MPNumber *x)
-{
-    mpchk();
-
-    /*  THE UNDERFLOWING NUMBER IS SET TO ZERO
-     *  AN ALTERNATIVE WOULD BE TO CALL MPMINR (X) AND RETURN,
-     *  POSSIBLY UPDATING A COUNTER AND TERMINATING EXECUTION
-     *  AFTER A PRESET NUMBER OF UNDERFLOWS.  ACTION COULD EASILY
-     *  BE DETERMINED BY A FLAG IN LABELLED COMMON.
-     */
-    x->sign = 0;
-}
-
-
-static int
-pow_ii(int x, int n)
+void
+mperr(const char *format, ...)
 {
-    int p = 1;
+    char text[MAXLINE];
+    va_list args;
     
-    if (n <= 0)
-        return 1;
-
-    for (;;) { 
-        if (n & 01)
-            p *= x;
-        if (n >>= 1)
-            x *= x;
-        else
-            break;
-    }
-
-    return p;
+    va_start(args, format);
+    vsnprintf(text, MAXLINE, format, args);
+    va_end(args);
+    doerr(text);
 }
 
 
@@ -124,132 +58,41 @@ mpext(int i, int j, MPNumber *x)
 {
     int q, s;
 
-    if (x->sign == 0 || MP.t <= 2 || i == 0)
+    if (x->sign == 0 || MP_T <= 2 || i == 0)
         return;
 
     /* COMPUTE MAXIMUM POSSIBLE ERROR IN THE LAST PLACE */
     q = (j + 1) / i + 1;
-    s = MP.b * x->fraction[MP.t - 2] + x->fraction[MP.t - 1];
+    s = MP_BASE * x->fraction[MP_T - 2] + x->fraction[MP_T - 1];
 
     /* SET LAST TWO DIGITS TO ZERO */    
     if (s <= q) {
-        x->fraction[MP.t - 2] = 0;
-        x->fraction[MP.t - 1] = 0;
+        x->fraction[MP_T - 2] = 0;
+        x->fraction[MP_T - 1] = 0;
         return;
     }
 
-    if (s + q < MP.b * MP.b)
+    if (s + q < MP_BASE * MP_BASE)
         return;
 
     /* ROUND UP HERE */
-    x->fraction[MP.t - 2] = MP.b - 1;
-    x->fraction[MP.t - 1] = MP.b;
+    x->fraction[MP_T - 2] = MP_BASE - 1;
+    x->fraction[MP_T - 1] = MP_BASE;
 
     /* NORMALIZE X (LAST DIGIT B IS OK IN MP_MULTIPLY_INTEGER) */
     mp_multiply_integer(x, 1, x);
 }
 
 
-/*  SETS BASE (B) AND NUMBER OF DIGITS (T) TO GIVE THE
- *  EQUIVALENT OF AT LEAST IDECPL DECIMAL DIGITS.
- *  IDECPL SHOULD BE POSITIVE.
- *  ITMAX2 IS THE DIMENSION OF ARRAYS USED FOR MP NUMBERS,
- *  SO AN ERROR OCCURS IF THE COMPUTED T EXCEEDS ITMAX2 - 2.
- *  MPSET ALSO SETS
- *        MXR = MAXDR (DIMENSION OF R IN COMMON, >= T+4), AND
- *          M = (W-1)/4 (MAXIMUM ALLOWABLE EXPONENT),
- *  WHERE W IS THE LARGEST INTEGER OF THE FORM 2**K-1 WHICH IS
- *  REPRESENTABLE IN THE MACHINE, K <= 47
- *  THE COMPUTED B AND T SATISFY THE CONDITIONS 
- *  (T-1)*LN(B)/LN(10) >= IDECPL   AND   8*B*B-1 <= W .
- *  APPROXIMATELY MINIMAL T AND MAXIMAL B SATISFYING
- *  THESE CONDITIONS ARE CHOSEN.
- *  PARAMETERS IDECPL, ITMAX2 AND MAXDR ARE INTEGERS.
- *  BEWARE - MPSET WILL CAUSE AN INTEGER OVERFLOW TO OCCUR
- *  ******   IF WORDLENGTH IS LESS THAN 48 BITS.
- *           IF THIS IS NOT ALLOWABLE, CHANGE THE DETERMINATION
- *           OF W (DO 30 ... TO 30 W = WN) OR SET B, T, M,
- *           AND MXR WITHOUT CALLING MPSET.
- *  FIRST SET MXR
- */
 void
-mp_init(int accuracy)
+mp_get_eulers(MPNumber *z)
 {
-    int i, k, w, b;
-
-    /* DETERMINE LARGE REPRESENTABLE INTEGER W OF FORM 2**K - 1 */
-    /*  ON CYBER 76 HAVE TO FIND K <= 47, SO ONLY LOOP
-     *  47 TIMES AT MOST.  IF GENUINE INTEGER WORDLENGTH
-     *  EXCEEDS 47 BITS THIS RESTRICTION CAN BE RELAXED.
-     */
-    w = 0;
-    k = 0;
-    for (i = 1; i <= 47; ++i) {
-        int w2, wn;
-
-        /*  INTEGER OVERFLOW WILL EVENTUALLY OCCUR HERE
-         *  IF WORDLENGTH < 48 BITS
-         */
-        w2 = w + w;
-        wn = w2 + 1;
-
-        /*  APPARENTLY REDUNDANT TESTS MAY BE NECESSARY ON SOME
-         *  MACHINES, DEPENDING ON HOW INTEGER OVERFLOW IS HANDLED
-         */
-        if (wn <= w || wn <= w2 || wn <= 0)
-            break;
-        k = i;
-        w = wn;
-    }
-
-    /* SET MAXIMUM EXPONENT TO (W-1)/4 */
-    MP.m = w / 4;
-    if (accuracy <= 0) {
-        mperr("*** ACCURACY <= 0 IN CALL TO MPSET ***");
-        return;
-    }
-
-    /* B IS THE LARGEST POWER OF 2 SUCH THAT (8*B*B-1) <= W */
-    MP.b = pow_ii(2, (k - 3) / 2);
-
-    /* Make a multiple of 10 so fractions can be represented exactly */
-    b = 1;
-    while (MP.b % (10 * b) != MP.b)
-        b *= 10;
-    MP.b = b;
-
-    /* 2E0 BELOW ENSURES AT LEAST ONE GUARD DIGIT */
-    MP.t = (int) ((float) (accuracy) * log((float)10.) / log((float) MP.b) + 
-                  (float) 2.0);
-
-    /* SEE IF T TOO LARGE FOR DIMENSION STATEMENTS */
-    if (MP.t > MP_SIZE) {
-        mperr("MP_SIZE TOO SMALL IN CALL TO MPSET, INCREASE MP_SIZE AND DIMENSIONS OF MP ARRAYS TO AT LEAST %d ***", MP.t);
-        MP.t = MP_SIZE;
-    }
-    
-    /* CHECK LEGALITY OF B, T, M AND MXR (AT LEAST T+4) */
-    mpchk();
-}
-
-
-/*  CHECKS LEGALITY OF B, T, M AND MXR.
- *  THE CONDITION ON MXR (THE DIMENSION OF R IN COMMON) IS THAT
- *  MXR >= (I*T + J)
- */
-// FIXME: MP.t is changed around calls to add/subtract/multiply/divide - it should not be global
-void
-mpchk()
-{
-    /* CHECK LEGALITY OF T AND M */
-    if (MP.t <= 1)
-        mperr("*** T = %d ILLEGAL IN CALL TO MPCHK, PERHAPS NOT SET BEFORE CALL TO AN MP ROUTINE ***", MP.t);
-    if (MP.m <= MP.t)
-        mperr("*** M <= T IN CALL TO MPCHK, PERHAPS NOT SET BEFORE CALL TO AN MP ROUTINE ***");
+    MPNumber t;
+    mp_set_from_integer(1, &t);
+    mp_epowy(&t, z);
 }
 
 
-/* SETS Y = ABS(X) FOR MP NUMBERS X AND Y */
 void
 mp_abs(const MPNumber *x, MPNumber *z)
 {
@@ -268,24 +111,24 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
     
     /* CLEAR GUARD DIGITS TO RIGHT OF X DIGITS */
     for(i = 3; i >= med; i--)
-        r[MP.t + i] = 0;
+        r[MP_T + i] = 0;
 
     if (s >= 0) {
         /* HERE DO ADDITION, EXPONENT(Y) >= EXPONENT(X) */
-        for (i = MP.t + 3; i >= MP.t; i--)
+        for (i = MP_T + 3; i >= MP_T; i--)
             r[i] = x->fraction[i - med];
 
         c = 0;
         for (; i >= med; i--) {
             c = y->fraction[i] + x->fraction[i - med] + c;
             
-            if (c < MP.b) {
+            if (c < MP_BASE) {
                 /* NO CARRY GENERATED HERE */
                 r[i] = c;
                 c = 0;
             } else {
                 /* CARRY GENERATED HERE */
-                r[i] = c - MP.b;
+                r[i] = c - MP_BASE;
                 c = 1;
             }
         }
@@ -293,7 +136,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
         for (; i >= 0; i--)
         {
             c = y->fraction[i] + c;
-            if (c < MP.b) {
+            if (c < MP_BASE) {
                 r[i] = c;
                 i--;
                 
@@ -310,7 +153,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
         
         /* MUST SHIFT RIGHT HERE AS CARRY OFF END */
         if (c != 0) {
-            for (i = MP.t + 3; i > 0; i--)
+            for (i = MP_T + 3; i > 0; i--)
                 r[i] = r[i - 1];
             r[0] = 1;
             return 1;
@@ -320,7 +163,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
     }
 
     c = 0;
-    for (i = MP.t + med - 1; i >= MP.t; i--) {
+    for (i = MP_T + med - 1; i >= MP_T; i--) {
         /* HERE DO SUBTRACTION, ABS(Y) > ABS(X) */
         r[i] = c - x->fraction[i - med];
         c = 0;
@@ -328,7 +171,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
         /* BORROW GENERATED HERE */    
         if (r[i] < 0) {
             c = -1;
-            r[i] += MP.b;
+            r[i] += MP_BASE;
         }
     }
 
@@ -340,7 +183,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
             c = 0;
         } else {
             /* BORROW GENERATED HERE */            
-            r[i] = c + MP.b;
+            r[i] = c + MP_BASE;
             c = -1;
         }
     }
@@ -359,7 +202,7 @@ mp_add3(const MPNumber *x, const MPNumber *y, int *r, int s, int med)
             return 0;
         }
         
-        r[i] = c + MP.b;
+        r[i] = c + MP_BASE;
         c = -1;
     }
 
@@ -375,6 +218,8 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
     int exp_diff, med;
     int x_largest = 0;
     MPNumber zt; // Use stack variable because of mp_normalize brokeness
+    
+    memset(&zt, 0, sizeof(MPNumber));
 
     /* X = 0 OR NEGLIGIBLE, SO RESULT = +-Y */
     if (x->sign == 0) {
@@ -392,9 +237,8 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
     /* COMPARE SIGNS */
     sign_prod = y_sign * x->sign;
     if (abs(sign_prod) > 1) {
-        mpchk();
         mperr("*** SIGN NOT 0, +1 OR -1 IN MP_ADD2 CALL, POSSIBLE OVERWRITING PROBLEM ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -403,7 +247,7 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
     med = abs(exp_diff);
     if (exp_diff < 0) {
         /* HERE EXPONENT(Y)  >  EXPONENT(X) */
-        if (med > MP.t) {
+        if (med > MP_T) {
             /* 'y' so much larger than 'x' that 'x+-y = y'.  Warning: still true with rounding??  */
             mp_set_from_mp(y, z);
             z->sign = y_sign;
@@ -412,7 +256,7 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
         x_largest = 0;
     } else if (exp_diff > 0) {
         /* HERE EXPONENT(X)  >  EXPONENT(Y) */
-        if (med > MP.t) {
+        if (med > MP_T) {
             /* 'x' so much larger than 'y' that 'x+-y = x'.  Warning: still true with rounding??  */
             mp_set_from_mp(x, z);
             return;
@@ -423,7 +267,7 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
         if (sign_prod < 0) {
             /* Signs are not equal.  find out which mantissa is larger. */
             int j;
-            for (j = 0; j < MP.t; j++) {
+            for (j = 0; j < MP_T; j++) {
                 int i = x->fraction[j] - y->fraction[j];
                 if (i == 0)
                     continue;
@@ -435,8 +279,8 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
             }
             
             /* Both mantissas equal, so result is zero. */
-            if (j >= MP.t) {
-                z->sign = 0;
+            if (j >= MP_T) {
+                mp_set_from_integer(0, z);
                 return;
             }
         }
@@ -451,7 +295,7 @@ mp_add2(const MPNumber *x, const MPNumber *y, int y_sign, MPNumber *z)
         zt.exponent = y->exponent + mp_add3(x, y, zt.fraction, sign_prod, med);
     }
     mp_normalize(&zt, 0);
-    mp_set_from_mp(&zt, z);   
+    mp_set_from_mp(&zt, z);
 }
 
 
@@ -465,119 +309,81 @@ 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)
 {
     MPNumber t;
-    mpchk();
     mp_set_from_integer(y, &t);
     mp_add(x, &t, 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)
 {
     MPNumber t;
-    mpchk();
     mp_set_from_fraction(i, j, &t);
     mp_add(x, &t, 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 *y)
+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) {
-        y->sign = 0;
+    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, y);
+        mp_set_from_mp(x, z);
         return;
     }
-
-    /* MOVE FRACTIONAL PART OF X TO ACCUMULATOR */
-    y->sign = x->sign;
-    y->exponent = x->exponent;
-    memset(y->fraction, 0, y->exponent*sizeof(int));
-    if (x != y)
-        memcpy(y->fraction + y->exponent, x->fraction + x->exponent,
-               (MP.t - x->exponent)*sizeof(int));
-    memset(y->fraction + MP.t, 0, 4*sizeof(int));
-
-    /* NORMALIZE RESULT AND RETURN */
-    mp_normalize(y, 1);
+    
+    /* 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 - 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 *y)
+mp_integer_component(const MPNumber *x, MPNumber *z)
 {
     int i;
-
-    mpchk();
-    mp_set_from_mp(x, y);
-    if (y->sign == 0)
-        return;
-
-    /* IF EXPONENT LARGE ENOUGH RETURN Y = X */
-    if (y->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 (y->exponent <= 0) {
-        y->sign = 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 = y->exponent; i < MP.t; i++) {
-        y->fraction[i] = 0;
-    }
+    /* Clear fraction */
+    mp_set_from_mp(x, z);    
+    for (i = z->exponent; i < MP_SIZE; i++)
+        z->fraction[i] = 0;
 }
 
-/*  COMPARES MP NUMBER X WITH REAL NUMBER RI, RETURNING
- *      +1 IF X > RI,
- *       0 IF X == RI,
- *      -1 IF X < RI
- *  DIMENSION OF R IN COMMON AT LEAST 2T+6
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static int
-mp_compare_mp_to_float(const MPNumber *x, float ri)
-{
-    MPNumber t;
-    mpchk();
-
-    /* CONVERT RI TO MULTIPLE-PRECISION AND COMPARE */
-    mp_set_from_float(ri, &t);
-    return mp_compare_mp_to_mp(x, &t);
-}
 
 /*  COMPARES THE MULTIPLE-PRECISION NUMBERS X AND Y,
  *  RETURNING +1 IF X  >  Y,
@@ -608,7 +414,7 @@ mp_compare_mp_to_mp(const MPNumber *x, const MPNumber *y)
         /* ABS(X)  >  ABS(Y) */
         return x->sign;
     }
-    for (i = 0; i < MP.t; i++) {
+    for (i = 0; i < MP_T; i++) {
         i2 = x->fraction[i] - y->fraction[i];
         if (i2 < 0) {
             /* ABS(X)  <  ABS(Y) */
@@ -635,24 +441,19 @@ mp_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     int i, ie, iz3;
     MPNumber t;
 
-    mpchk();
-
-    /* CHECK FOR DIVISION BY ZERO */
+    /* x/0 */
     if (y->sign == 0) {
         mperr("*** ATTEMPTED DIVISION BY ZERO IN CALL TO MP_DIVIDE ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
-    /* CHECK FOR X = 0 */
+    /* 0/y = 0 */
     if (x->sign == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
-    /* INCREASE M TO AVOID OVERFLOW IN MP_RECIPROCAL */
-    MP.m += 2;
-
     /* FORM RECIPROCAL OF Y */
     mp_reciprocal(y, &t);
 
@@ -666,15 +467,7 @@ mp_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     iz3 = z->fraction[0];
     mpext(i, iz3, z);
 
-    /* RESTORE M, CORRECT EXPONENT AND RETURN */
-    MP.m += -2;
     z->exponent += ie;
-    
-    /* Check for overflow or underflow */
-    if (z->exponent < -MP.m)
-        mpunfl(z);
-    else if (z->exponent > MP.m)
-        mpovfl(z, "*** OVERFLOW OCCURRED IN MP_DIVIDE ***");
 }
 
 
@@ -690,7 +483,7 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
 
     if (iy == 0) {
         mperr("*** ATTEMPTED DIVISION BY ZERO IN CALL TO MP_DIVIDE_INTEGER ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -704,12 +497,7 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
     z->exponent = x->exponent;
 
     /* CHECK FOR DIVISION BY B */
-    if (iy == MP.b) {
-        if (x->exponent <= -MP.m)
-        {
-            mpunfl(z);
-            return;
-        }
+    if (iy == MP_BASE) {
         mp_set_from_mp(x, z);
         z->exponent--;
         return;
@@ -724,7 +512,7 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
     }
 
     c = 0;
-    i2 = MP.t + 4;
+    i2 = MP_T + 4;
     i = 0;
 
     /*  IF IY*B NOT REPRESENTABLE AS AN INTEGER HAVE TO SIMULATE
@@ -732,12 +520,12 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
      */
 
     /* Computing MAX */
-    b2 = max(MP.b << 3, 32767 / MP.b);
+    b2 = max(MP_BASE << 3, 32767 / MP_BASE);
     if (iy < b2) {
         /* LOOK FOR FIRST NONZERO DIGIT IN QUOTIENT */
         do {
-            c = MP.b * c;
-            if (i < MP.t)
+            c = MP_BASE * c;
+            if (i < MP_T)
                 c += x->fraction[i];
             i++;
             r1 = c / iy;
@@ -748,14 +536,14 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
         /* ADJUST EXPONENT AND GET T+4 DIGITS IN QUOTIENT */
         z->exponent += 1 - i;
         z->fraction[0] = r1;
-        c = MP.b * (c - iy * r1);
+        c = MP_BASE * (c - iy * r1);
         kh = 1;
-        if (i < MP.t) {
-            kh = MP.t + 1 - i;
+        if (i < MP_T) {
+            kh = MP_T + 1 - i;
             for (k = 1; k < kh; k++) {
                 c += x->fraction[i];
                 z->fraction[k] = c / iy;
-                c = MP.b * (c - iy * z->fraction[k]);
+                c = MP_BASE * (c - iy * z->fraction[k]);
                 i++;
             }
             if (c < 0)
@@ -764,7 +552,7 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
         
         for (k = kh; k < i2; k++) {
             z->fraction[k] = c / iy;
-            c = MP.b * (c - iy * z->fraction[k]);
+            c = MP_BASE * (c - iy * z->fraction[k]);
         }
         if (c < 0)
             goto L210;
@@ -776,15 +564,15 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
     }
     
     /* HERE NEED SIMULATED DOUBLE-PRECISION DIVISION */
-    j1 = iy / MP.b;
+    j1 = iy / MP_BASE;
 
     /* LOOK FOR FIRST NONZERO DIGIT */
     c2 = 0;
-    j2 = iy - j1 * MP.b;
+    j2 = iy - j1 * MP_BASE;
     do {
-        c = MP.b * c + c2;
+        c = MP_BASE * c + c2;
         i__1 = c - j1;
-        c2 = i < MP.t ? x->fraction[i] : 0;
+        c2 = i < MP_T ? x->fraction[i] : 0;
         i++;
     } while (i__1 < 0 || (i__1 == 0 && c2 < j2));
 
@@ -807,14 +595,14 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
             iq -= j1;
         }
 
-        iq = iq * MP.b - ir * j2;
+        iq = iq * MP_BASE - ir * j2;
         if (iq < 0) {
             /* HERE IQ NEGATIVE SO IR WAS TOO LARGE */
             ir--;
             iq += iy;
         }
 
-        if (i < MP.t)
+        if (i < MP_T)
             iq += x->fraction[i];
         i++;
         iqj = iq / iy;
@@ -835,9 +623,8 @@ mp_divide_integer(const MPNumber *x, int iy, MPNumber *z)
 
 L210:
     /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
-    mpchk();
     mperr("*** INTEGER OVERFLOW IN MP_DIVIDE_INTEGER, B TOO LARGE ***");
-    z->sign = 0;
+    mp_set_from_integer(0, z);
 }
 
 
@@ -846,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.
@@ -854,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;*/
 }
 
 
@@ -866,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)
 {
@@ -874,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
@@ -901,41 +766,26 @@ void
 mp_epowy(const MPNumber *x, MPNumber *z)
 {
     float r__1;
-    int i, ie, ix, ts, xs, tss;
+    int i, ix, xs, tss;
     float rx, rz, rlb;
     MPNumber t1, t2;
 
-    mpchk();
-
-    /* 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;
     }
 
     /*  SEE IF ABS(X) SO LARGE THAT EXP(X) WILL CERTAINLY OVERFLOW
      *  OR UNDERFLOW.  1.01 IS TO ALLOW FOR ERRORS IN ALOG.
      */
-    rlb = log((float) MP.b) * (float)1.01;
-    if (mp_compare_mp_to_float(x, -(double)((float) (MP.m + 1)) * rlb) < 0) {
-        /* UNDERFLOW SO CALL MPUNFL AND RETURN */
-        mpunfl(z);
-        return;
-    }
-
-    if (mp_compare_mp_to_float(x, (float) MP.m * rlb) > 0) {
-        /* OVERFLOW HERE */
-        mpovfl(z, "*** OVERFLOW IN SUBROUTINE MP_EPOWY ***");
-        return;
-    }
+    rlb = log((float)MP_BASE) * 1.01f;
 
     /* NOW SAFE TO CONVERT X TO REAL */
     rx = mp_cast_to_float(x);
@@ -947,9 +797,9 @@ mp_epowy(const MPNumber *x, MPNumber *z)
     /*  IF ABS(X) > M POSSIBLE THAT INT(X) OVERFLOWS,
      *  SO DIVIDE BY 32.
      */
-    if (fabs(rx) > (float) MP.m) {
+    /*if (fabs(rx) > (float)MP.m) {
         mp_divide_integer(&t2, 32, &t2);
-    }
+    }*/
 
     /* GET FRACTIONAL AND INTEGER PARTS OF ABS(X) */
     ix = mp_cast_to_int(&t2);
@@ -957,85 +807,58 @@ 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)
      */
-    if (MP.t < 4)
-        tss = MP.t + 1;
+    if (MP_T < 4)
+        tss = MP_T + 1;
     else
-        tss = MP.t + 2;
+        tss = MP_T + 2;
 
     /* LOOP FOR E COMPUTATION. DECREASE T IF POSSIBLE. */
     /* Computing MIN */
-    ts = MP.t;
-    MP.t = tss;
     mp_set_from_integer(xs, &t1);
-    MP.t = ts;
 
     t2.sign = 0;
     for (i = 2 ; ; i++) {
-        int t;
-        
-        t = min(tss, tss + 2 + t1.exponent);
-        if (t <= 2)
+        if (min(tss, tss + 2 + t1.exponent) <= 2)
             break;
         
-        ts = MP.t;
-        MP.t = t;
         mp_divide_integer(&t1, i * xs, &t1);
-        MP.t = ts;
-        
-        ts = MP.t;
-        MP.t = tss;
         mp_add(&t2, &t1, &t2);
-        MP.t = ts;
         if (t1.sign == 0)
             break;
     }
 
     /* RAISE E OR 1/E TO POWER IX */
-    ts = MP.t;
-    MP.t = tss;
     if (xs > 0)
         mp_add_integer(&t2, 2, &t2);
-    mp_pwr_integer(&t2, ix, &t2);
-    MP.t = ts;
+    mp_xpowy_integer(&t2, ix, &t2);
 
     /* MULTIPLY EXPS OF INTEGER AND FRACTIONAL PARTS */
     mp_multiply(z, &t2, z);
 
     /* MUST CORRECT RESULT IF DIVIDED BY 32 ABOVE. */
-    if (fabs(rx) > (float) MP.m && z->sign != 0) {
+    /*if (fabs(rx) > (float)MP.m && z->sign != 0) {
         for (i = 1; i <= 5; ++i) {
-            /* SAVE EXPONENT TO AVOID OVERFLOW IN MP_MULTIPLY */
+            // SAVE EXPONENT TO AVOID OVERFLOW IN MP_MULTIPLY
             ie = z->exponent;
             z->exponent = 0;
             mp_multiply(z, z, z);
             z->exponent += ie << 1;
-
-            /* CHECK FOR UNDERFLOW AND OVERFLOW */
-            if (z->exponent < -MP.m) {
-                mpunfl(z);
-                return;
-            }
-            if (z->exponent > MP.m) {
-                mpovfl(z, "*** OVERFLOW IN SUBROUTINE MP_EPOWY ***");
-                return;
-            }
         }
-    }
+    }*/
 
     /*  CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS ABS(X) LARGE
      *  (WHEN EXP MIGHT OVERFLOW OR UNDERFLOW)
      */
-    if (fabs(rx) > (float)10.0)
+    if (fabs(rx) > 10.0f)
         return;
 
     rz = mp_cast_to_float(z);
-    if ((r__1 = rz - exp(rx), fabs(r__1)) < rz * (float)0.01)
+    if ((r__1 = rz - exp(rx), fabs(r__1)) < rz * 0.01f)
         return;
 
     /*  THE FOLLOWING MESSAGE MAY INDICATE THAT
@@ -1046,96 +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 *y)
-{
-    int i, q, ib, ic;
-    float rlb;
-    MPNumber t1, t2;
-
-    mpchk();
-
-    /* CHECK FOR X = 0 */
-    if (x->sign == 0) {
-        y->sign = 0;
-        return;
-    }
-
-    /* CHECK THAT ABS(X) < 1 */
-    if (x->exponent > 0) {
-        mperr("*** ABS(X) NOT LESS THAN 1 IN CALL TO MPEXP1 ***");
-        y->sign = 0;
-        return;
-    }
-
-    mp_set_from_mp(x, &t1);
-    rlb = log((float) MP.b);
-
-    /* COMPUTE APPROXIMATELY OPTIMAL Q (AND DIVIDE X BY 2**Q) */
-    q = (int) (sqrt((float) MP.t * (float).48 * rlb) + (float) x->exponent * 
-              (float)1.44 * rlb);
-
-    /* HALVE Q TIMES */
-    if (q > 0) {
-        ib = MP.b << 2;
-        ic = 1;
-        for (i = 1; i <= q; ++i) {
-            ic <<= 1;
-            if (ic < ib && ic != MP.b && i < q)
-                continue;
-            mp_divide_integer(&t1, ic, &t1);
-            ic = 1;
-        }
-    }
-
-    if (t1.sign == 0) {
-        y->sign = 0;
-        return;
-    }
-    mp_set_from_mp(&t1, y);
-    mp_set_from_mp(&t1, &t2);
-
-    /* SUM SERIES, REDUCING T WHERE POSSIBLE */
-    for (i = 2; ; i++)  {
-        int t, ts;
-        
-        t = MP.t + 2 + t2.exponent - y->exponent;
-        if (t <= 2)
-            break;
-        t = min(t, MP.t);
-
-        ts = MP.t;
-        MP.t = t;
-        mp_multiply(&t1, &t2, &t2);
-        mp_divide_integer(&t2, i, &t2);
-        MP.t = ts;
-
-        mp_add(&t2, y, y);
-        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(y, 2, &t1);
-        mp_multiply(&t1, y, y);
-    }
-}
-
-
 /*  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
@@ -1217,28 +950,25 @@ 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
-mplns(const MPNumber *x, MPNumber *y)
+mplns(const MPNumber *x, MPNumber *z)
 {
     int t, it0;
     MPNumber t1, t2, t3;
     
-    mpchk();
-
-    /* CHECK FOR X = 0 EXACTLY */
+    /* ln(1) = 0 */
     if (x->sign == 0)  {
-        y->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 ***");
-        y->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -1250,27 +980,25 @@ mplns(const MPNumber *x, MPNumber *y)
     mp_add_fraction(&t1, 1, 2, &t1);
     mp_multiply(x, &t1, &t1);
     mp_add_integer(&t1, -1, &t1);
-    mp_multiply(x, &t1, y);
+    mp_multiply(x, &t1, z);
 
     /* START NEWTON ITERATION USING SMALL T, LATER INCREASE */
-    t = max(5, 13 - (MP.b << 1));
-    if (t <= MP.t)
+    t = max(5, 13 - (MP_BASE << 1));
+    if (t <= MP_T)
     {
         it0 = (t + 5) / 2;
 
         while(1)
         {
-            int ts, ts2, ts3;
+            int ts2, ts3;
             
-            ts = MP.t;
-            MP.t = t;
-            mpexp1(y, &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);
-            mp_subtract(y, &t3, y);
-            MP.t = ts;
-            if (t >= MP.t)
+            mp_subtract(z, &t3, z);
+            if (t >= MP_T)
                 break;
 
             /*  FOLLOWING LOOP COMPUTES NEXT VALUE OF T TO USE.
@@ -1278,7 +1006,7 @@ mplns(const MPNumber *x, MPNumber *y)
              *  WE CAN ALMOST DOUBLE T EACH TIME.
              */
             ts3 = t;
-            t = MP.t;
+            t = MP_T;
             do {
                 ts2 = t;
                 t = (t + it0) / 2;
@@ -1287,13 +1015,13 @@ mplns(const MPNumber *x, MPNumber *y)
         }
         
         /* CHECK THAT NEWTON ITERATION WAS CONVERGING AS EXPECTED */
-        if (t3.sign != 0 && t3.exponent << 1 > it0 - MP.t) {
+        if (t3.sign != 0 && t3.exponent << 1 > it0 - MP_T) {
             mperr("*** ERROR OCCURRED IN MPLNS, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
         }
     }
 
     /* REVERSE SIGN OF Y AND RETURN */
-    y->sign = -y->sign;
+    z->sign = -z->sign;
 }
 
 
@@ -1303,7 +1031,7 @@ mplns(const MPNumber *x, MPNumber *y)
  *  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
  */
@@ -1314,18 +1042,16 @@ mp_ln(const MPNumber *x, MPNumber *z)
     float rx, rlx;
     MPNumber t1, t2;
     
-    mpchk();
-
     /* CHECK THAT X IS POSITIVE */
     if (x->sign <= 0) {
         mperr("*** X NONPOSITIVE IN CALL TO MP_LN ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
     /* MOVE X TO LOCAL STORAGE */
     mp_set_from_mp(x, &t1);
-    z->sign = 0;
+    mp_set_from_integer(0, z);
     k = 0;
 
     /* LOOP TO GET APPROXIMATE LN(X) USING SINGLE-PRECISION */
@@ -1348,7 +1074,7 @@ mp_ln(const MPNumber *x, MPNumber *z)
 
         /* RESTORE EXPONENT AND COMPUTE SINGLE-PRECISION LOG */
         t1.exponent = e;
-        rlx = log(rx) + (float) e * log((float) MP.b);
+        rlx = log(rx) + (float)e * log((float)MP_BASE);
         mp_set_from_float(-(double)rlx, &t2);
 
         /* UPDATE Z AND COMPUTE ACCURATE EXP OF APPROXIMATE LOG */
@@ -1373,7 +1099,7 @@ mp_ln(const MPNumber *x, MPNumber *z)
  *  1. log10(x) = log10(e) * log(x)
  */
 void
-mp_logarithm(int n, MPNumber *x, MPNumber *z)
+mp_logarithm(int n, const MPNumber *x, MPNumber *z)
 {
     MPNumber t1, t2;
 
@@ -1411,9 +1137,10 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
     int c, i, j, i2, xi;
     MPNumber r;
 
-    mpchk();
-    i2 = MP.t + 4;
-
+    i2 = MP_T + 4;
+    
+    memset(&r, 0, sizeof(MPNumber));
+    
     /* FORM SIGN OF PRODUCT */
     z->sign = x->sign * y->sign;
     if (z->sign == 0)
@@ -1422,13 +1149,9 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
     /* FORM EXPONENT OF PRODUCT */
     z->exponent = x->exponent + y->exponent;
     
-    /* CLEAR ACCUMULATOR */
-    for (i = 0; i < i2; i++)
-        r.fraction[i] = 0;
-
     /* PERFORM MULTIPLICATION */
     c = 8;
-    for (i = 0; i < MP.t; i++) {
+    for (i = 0; i < MP_T; i++) {
         xi = x->fraction[i];
 
         /* FOR SPEED, PUT THE NUMBER WITH MANY ZEROS FIRST */
@@ -1436,16 +1159,16 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
             continue;
 
         /* Computing MIN */
-        for (j = 0; j < min(MP.t, i2 - i - 1); j++)
+        for (j = 0; j < min(MP_T, i2 - i - 1); j++)
             r.fraction[i+j+1] += xi * y->fraction[j];
         c--;
         if (c > 0)
             continue;
 
         /* CHECK FOR LEGAL BASE B DIGIT */
-        if (xi < 0 || xi >= MP.b) {
+        if (xi < 0 || xi >= MP_BASE) {
             mperr("*** ILLEGAL BASE B DIGIT IN CALL TO MP_MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
 
@@ -1456,24 +1179,24 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
             int ri = r.fraction[j] + c;
             if (ri < 0) {
                 mperr("*** INTEGER OVERFLOW IN MP_MULTIPLY, B TOO LARGE ***");
-                z->sign = 0;
+                mp_set_from_integer(0, z);
                 return;
             }
-            c = ri / MP.b;
-            r.fraction[j] = ri - MP.b * c;
+            c = ri / MP_BASE;
+            r.fraction[j] = ri - MP_BASE * c;
         }
         if (c != 0) {
             mperr("*** ILLEGAL BASE B DIGIT IN CALL TO MP_MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
         c = 8;
     }
 
     if (c != 8) {
-        if (xi < 0 || xi >= MP.b) {
+        if (xi < 0 || xi >= MP_BASE) {
             mperr("*** ILLEGAL BASE B DIGIT IN CALL TO MP_MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
     
@@ -1482,23 +1205,23 @@ mp_multiply(const MPNumber *x, const MPNumber *y, MPNumber *z)
             int ri = r.fraction[j] + c;
             if (ri < 0) {
                 mperr("*** INTEGER OVERFLOW IN MP_MULTIPLY, B TOO LARGE ***");
-                z->sign = 0;
+                mp_set_from_integer(0, z);
                 return;
             }
-            c = ri / MP.b;
-            r.fraction[j] = ri - MP.b * c;
+            c = ri / MP_BASE;
+            r.fraction[j] = ri - MP_BASE * c;
         }
         
         if (c != 0) {
             mperr("*** ILLEGAL BASE B DIGIT IN CALL TO MP_MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
     }
 
     /* NORMALIZE AND ROUND RESULT */
     // FIXME: Use stack variable because of mp_normalize brokeness
-    for (i = 0; i < i2; i++)
+    for (i = 0; i < MP_SIZE; i++)
         z->fraction[i] = r.fraction[i];
     mp_normalize(z, 0);
 }
@@ -1517,7 +1240,7 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
     
     z->sign = x->sign;
     if (z->sign == 0 || iy == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -1526,16 +1249,10 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
         z->sign = -z->sign;
 
         /* CHECK FOR MULTIPLICATION BY B */
-        if (iy == MP.b) {
-            if (x->exponent < MP.m) {
-                mp_set_from_mp(x, z);
-                z->sign = z->sign;
-                z->exponent = x->exponent + 1;
-            }
-            else {
-                mpchk();
-                mpovfl(z, "*** OVERFLOW OCCURRED IN MPMUL2 ***");
-            }
+        if (iy == MP_BASE) {
+            mp_set_from_mp(x, z);
+            z->sign = z->sign;
+            z->exponent = x->exponent + 1;
             return;
         }
     }
@@ -1545,48 +1262,47 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
 
     /* FORM PRODUCT IN ACCUMULATOR */
     c = 0;
-    t1 = MP.t + 1;
-    t3 = MP.t + 3;
-    t4 = MP.t + 4;
+    t1 = MP_T + 1;
+    t3 = MP_T + 3;
+    t4 = MP_T + 4;
 
     /*  IF IY*B NOT REPRESENTABLE AS AN INTEGER WE HAVE TO SIMULATE
      *  DOUBLE-PRECISION MULTIPLICATION.
      */
 
     /* Computing MAX */
-    if (iy >= max(MP.b << 3, 32767 / MP.b)) {
+    if (iy >= max(MP_BASE << 3, 32767 / MP_BASE)) {
         /* HERE J IS TOO LARGE FOR SINGLE-PRECISION MULTIPLICATION */
-        j1 = iy / MP.b;
-        j2 = iy - j1 * MP.b;
+        j1 = iy / MP_BASE;
+        j2 = iy - j1 * MP_BASE;
 
         /* FORM PRODUCT */
         for (ij = 1; ij <= t4; ++ij) {
-            c1 = c / MP.b;
-            c2 = c - MP.b * c1;
+            c1 = c / MP_BASE;
+            c2 = c - MP_BASE * c1;
             i = t1 - ij;
             ix = 0;
             if (i > 0)
                 ix = x->fraction[i - 1];
             ri = j2 * ix + c2;
-            is = ri / MP.b;
+            is = ri / MP_BASE;
             c = j1 * ix + c1 + is;
-            z->fraction[i + 3] = ri - MP.b * is;
+            z->fraction[i + 3] = ri - MP_BASE * is;
         }
     }
     else
     {
-        for (ij = 1; ij <= MP.t; ++ij) {
+        for (ij = 1; ij <= MP_T; ++ij) {
             i = t1 - ij;
             ri = iy * x->fraction[i - 1] + c;
-            c = ri / MP.b;
-            z->fraction[i + 3] = ri - MP.b * c;
+            c = ri / MP_BASE;
+            z->fraction[i + 3] = ri - MP_BASE * c;
         }
 
         /* CHECK FOR INTEGER OVERFLOW */
         if (ri < 0) {
-            mpchk();
             mperr("*** INTEGER OVERFLOW IN MPMUL2, B TOO LARGE ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
 
@@ -1594,8 +1310,8 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
         for (ij = 1; ij <= 4; ++ij) {
             i = 5 - ij;
             ri = c;
-            c = ri / MP.b;
-            z->fraction[i - 1] = ri - MP.b * c;
+            c = ri / MP_BASE;
+            z->fraction[i - 1] = ri - MP_BASE * c;
         }
     }
 
@@ -1609,9 +1325,8 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
         }
         
         if (c < 0) {
-            mpchk();
             mperr("*** INTEGER OVERFLOW IN MPMUL2, B TOO LARGE ***");
-            z->sign = 0;
+            mp_set_from_integer(0, z);
             return;
         }
         
@@ -1620,8 +1335,8 @@ mpmul2(const MPNumber *x, int iy, MPNumber *z, int trunc)
             z->fraction[i] = z->fraction[i - 1];
         }
         ri = c;
-        c = ri / MP.b;
-        z->fraction[0] = ri - MP.b * c;
+        c = ri / MP_BASE;
+        z->fraction[0] = ri - MP_BASE * c;
         z->exponent++;
     }
 }
@@ -1646,14 +1361,13 @@ mp_multiply_fraction(const MPNumber *x, int numerator, int denominator, MPNumber
     int is, js;
 
     if (denominator == 0) {
-        mpchk();
         mperr("*** ATTEMPTED DIVISION BY ZERO IN MP_MULTIPLY_FRACTION ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
     if (numerator == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -1683,7 +1397,7 @@ mp_invert_sign(const MPNumber *x, MPNumber *y)
  *  AND RETURNS MP RESULT IN Z.  INTEGER ARGUMENTS REG_EXP IS
  *  NOT PRESERVED. R*-ROUNDING IS USED IF TRUNC == 0
  */
-// FIXME: Is r->fraction large enough?  It seems to be in practise but it may be MP.t+4 instead of MP.t
+// FIXME: Is r->fraction large enough?  It seems to be in practise but it may be MP_T+4 instead of MP_T
 // FIXME: There is some sort of stack corruption/use of unitialised variables here.  Some functions are
 // using stack variables as x otherwise there are corruption errors. e.g. "Cos(45) - 1/Sqrt(2) = -0"
 // (try in scientific mode)
@@ -1699,18 +1413,18 @@ mp_normalize(MPNumber *x, int trunc)
     /* CHECK THAT SIGN = +-1 */
     if (abs(x->sign) > 1) {
         mperr("*** SIGN NOT 0, +1 OR -1 IN CALL TO MP_NORMALIZE, POSSIBLE OVERWRITING PROBLEM ***");
-        x->sign = 0;
+        mp_set_from_integer(0, x);
         return;
     }
 
-    i2 = MP.t + 4;
+    i2 = MP_T + 4;
 
     /* Normalize by shifting the fraction to the left */    
     if (x->fraction[0] == 0) {
         /* Find how many places to shift and detect 0 fraction */
         for (i = 1; i < i2 && x->fraction[i] == 0; i++);
         if (i == i2) {
-            x->sign = 0;
+            mp_set_from_integer(0, x);
             return;
         }
         
@@ -1727,12 +1441,12 @@ mp_normalize(MPNumber *x, int trunc)
         /*  SEE IF ROUNDING NECESSARY
          *  TREAT EVEN AND ODD BASES DIFFERENTLY
          */
-        b2 = MP.b / 2;
-        if (b2 << 1 != MP.b) {
+        b2 = MP_BASE / 2;
+        if (b2 << 1 != MP_BASE) {
             round = 0;
             /* ODD BASE, ROUND IF R(T+1)... > 1/2 */
             for (i = 0; i < 4; i++) {
-                i__1 = x->fraction[MP.t + i] - b2;
+                i__1 = x->fraction[MP_T + i] - b2;
                 if (i__1 < 0)
                     break;
                 else if (i__1 == 0)
@@ -1748,12 +1462,12 @@ mp_normalize(MPNumber *x, int trunc)
              *  AFTER R(T+2).
              */
             round = 1;
-            i__1 = x->fraction[MP.t] - b2;
+            i__1 = x->fraction[MP_T] - b2;
             if (i__1 < 0)
                 round = 0;
             else if (i__1 == 0) {
-                if (x->fraction[MP.t - 1] % 2 != 0) {
-                    if (x->fraction[MP.t + 1] + x->fraction[MP.t + 2] + x->fraction[MP.t + 3] == 0) {
+                if (x->fraction[MP_T - 1] % 2 != 0) {
+                    if (x->fraction[MP_T + 1] + x->fraction[MP_T + 2] + x->fraction[MP_T + 3] == 0) {
                         round = 0;
                     }
                 }
@@ -1762,9 +1476,9 @@ mp_normalize(MPNumber *x, int trunc)
 
         /* ROUND */
         if (round) {
-            for (j = MP.t - 1; j >= 0; j--) {
+            for (j = MP_T - 1; j >= 0; j--) {
                 ++x->fraction[j];
-                if (x->fraction[j] < MP.b)
+                if (x->fraction[j] < MP_BASE)
                     break;
                 x->fraction[j] = 0;
             }
@@ -1776,112 +1490,37 @@ mp_normalize(MPNumber *x, int trunc)
             }
         }
     }
-
-    /* Check for over and underflow */
-    if (x->exponent > MP.m) {
-        mpovfl(x, "*** OVERFLOW OCCURRED IN MP_NORMALIZE ***");
-        return;
-    }
-    if (x->exponent < -MP.m) {
-        mpunfl(x);
-        return;
-    }
 }
 
 
-/*  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 *y)
-{
-    int n2, ns;
-    MPNumber t;
-   
-    n2 = n;
-    if (n2 < 0) {
-        /* N < 0 */
-        mpchk();
-        n2 = -n2;
-        if (x->sign == 0) {
-            mperr("*** ATTEMPT TO RAISE ZERO TO NEGATIVE POWER IN CALL TO SUBROUTINE MP_PWR_INTEGER ***");
-            y->sign = 0;
-            return;
-        }
-    } else if (n2 == 0) {
-        /* N == 0, RETURN Y = 1. */
-        mp_set_from_integer(1, y);
-        return;
-    } else {
-        /* N > 0 */
-        mpchk();
-        if (x->sign == 0) {
-            y->sign = 0;
-            return;
-        }
-    }
-
-    /* MOVE X */
-    mp_set_from_mp(x, y);
-
-    /* IF N < 0 FORM RECIPROCAL */
-    if (n < 0)
-        mp_reciprocal(y, y);
-    mp_set_from_mp(y, &t);
-
-    /* SET PRODUCT TERM TO ONE */
-    mp_set_from_integer(1, y);
-
-    /* MAIN LOOP, LOOK AT BITS OF N2 FROM RIGHT */
-    while(1) {
-        ns = n2;
-        n2 /= 2;
-        if (n2 << 1 != ns)
-            mp_multiply(y, &t, y);
-        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;
 
-    mpchk();
-
+    /* (-x)^y imaginary */
     if (x->sign < 0) {
         mperr(_("Negative X and non-integer Y not supported"));
-        z->sign = 0;
-    }
-    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 ***");
-        }
-        z->sign = 0;
+        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^-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;
+    }
+    
+    /* 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);
 }
 
 
@@ -1903,21 +1542,15 @@ mp_reciprocal(const MPNumber *x, MPNumber *z)
     int ex, it0, t;
     float rx;
 
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
-
     /* MP_ADD_INTEGER REQUIRES 2T+6 WORDS. */
     if (x->sign == 0) {
         mperr("*** ATTEMPTED DIVISION BY ZERO IN CALL TO MP_RECIPROCAL ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
     ex = x->exponent;
 
-    /* TEMPORARILY INCREASE M TO AVOID OVERFLOW */
-    MP.m += 2;
-
     /* SET EXPONENT TO ZERO SO RX NOT TOO LARGE OR SMALL. */
     /* work-around to avoid touching X */
     mp_set_from_mp(x, &tmp_x);
@@ -1925,56 +1558,44 @@ mp_reciprocal(const MPNumber *x, MPNumber *z)
     rx = mp_cast_to_float(&tmp_x);
 
     /* USE SINGLE-PRECISION RECIPROCAL AS FIRST APPROXIMATION */
-    mp_set_from_float((float)1. / rx, &t1);
+    mp_set_from_float(1.0f / rx, &t1);
 
     /* CORRECT EXPONENT OF FIRST APPROXIMATION */
     t1.exponent -= ex;
 
     /* START WITH SMALL T TO SAVE TIME. ENSURE THAT B**(T-1) >= 100 */
-    if (MP.b < 10)
-        t = it[MP.b - 1];
+    if (MP_BASE < 10)
+        t = it[MP_BASE - 1];
     else
         t = 3;
     it0 = (t + 4) / 2;
 
     /* MAIN ITERATION LOOP */    
-    if (t <= MP.t) {        
+    if (t <= MP_T) {        
         while(1) {
-            int ts, ts2, ts3;
+            int ts2, ts3;
             
-            ts = MP.t;
-            MP.t = t;
             mp_multiply(x, &t1, &t2);
             mp_add_integer(&t2, -1, &t2);
-            MP.t = ts;
-
-            /* TEMPORARILY REDUCE T */
-            ts = MP.t;
-            MP.t = (t + it0) / 2;
             mp_multiply(&t1, &t2, &t2);
-            MP.t = ts;
-
-            ts = MP.t;
-            MP.t = t;
             mp_subtract(&t1, &t2, &t1);
-            MP.t = ts;
-            if (t >= MP.t)
+            if (t >= MP_T)
                 break;
 
             /*  FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE
              *  BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
              */
             ts3 = t;
-            t = MP.t;
+            t = MP_T;
             do {
                 ts2 = t;
                 t = (t + it0) / 2;
             } while (t > ts3);
-            t = min(ts2, MP.t);
+            t = min(ts2, MP_T);
         }
         
         /* RETURN IF NEWTON ITERATION WAS CONVERGING */
-        if (t2.sign != 0 && (t1.exponent - t2.exponent) << 1 < MP.t - it0) {
+        if (t2.sign != 0 && (t1.exponent - t2.exponent) << 1 < MP_T - it0) {
             /*  THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
              *  OR THAT THE STARTING APPROXIMATION IS NOT ACCURATE ENOUGH.
              */
@@ -1984,11 +1605,6 @@ mp_reciprocal(const MPNumber *x, MPNumber *z)
 
     /* MOVE RESULT TO Y AND RETURN AFTER RESTORING T */
     mp_set_from_mp(&t1, z);
-
-    /* RESTORE M AND CHECK FOR OVERFLOW (UNDERFLOW IMPOSSIBLE) */
-    MP.m += -2;
-    if (z->exponent > MP.m)
-        mpovfl(z, "*** OVERFLOW OCCURRED IN MP_RECIPROCAL ***");
 }
 
 
@@ -2009,9 +1625,6 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
     float rx;
     MPNumber t1, t2;
 
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk();
-
     if (n == 1) {
         mp_set_from_mp(x, z);
         return;
@@ -2019,34 +1632,31 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
 
     if (n == 0) {
         mperr("*** N == 0 IN CALL TO MP_ROOT ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
     np = abs(n);
 
     /* LOSS OF ACCURACY IF NP LARGE, SO ONLY ALLOW NP <= MAX (B, 64) */
-    if (np > max(MP.b, 64)) {
+    if (np > max(MP_BASE, 64)) {
         mperr("*** ABS(N) TOO LARGE IN CALL TO MP_ROOT ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
     /* LOOK AT SIGN OF X */
     if (x->sign == 0) {
         /* X == 0 HERE, RETURN 0 IF N POSITIVE, ERROR IF NEGATIVE */
-        z->sign = 0;
-        if (n > 0)
-            return;
-
-        mperr("*** X == 0 AND N NEGATIVE IN CALL TO MP_ROOT ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
+        if (n <= 0)
+            mperr("*** X == 0 AND N NEGATIVE IN CALL TO MP_ROOT ***");
         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 ***");
-        z->sign = 0;
+        mp_set_from_integer(0, z);
         return;
     }
 
@@ -2062,8 +1672,8 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
     }
 
     /* USE SINGLE-PRECISION ROOT FOR FIRST APPROXIMATION */
-    r__1 = exp(((float) (np * ex - x->exponent) * log((float) MP.b) - 
-           log((fabs(rx)))) / (float) np);
+    r__1 = exp(((float)(np * ex - x->exponent) * log((float)MP_BASE) -
+           log((fabs(rx)))) / (float)np);
     mp_set_from_float(r__1, &t1);
 
     /* SIGN OF APPROXIMATION SAME AS THAT OF X */
@@ -2074,57 +1684,45 @@ mp_root(const MPNumber *x, int n, MPNumber *z)
 
     /* START WITH SMALL T TO SAVE TIME */
     /* ENSURE THAT B**(T-1) >= 100 */
-    if (MP.b < 10)
-        t = it[MP.b - 1];
+    if (MP_BASE < 10)
+        t = it[MP_BASE - 1];
     else
         t = 3;        
     
-    if (t <= MP.t) {
+    if (t <= MP_T) {
         /* IT0 IS A NECESSARY SAFETY FACTOR */
         it0 = (t + 4) / 2;
 
         /* MAIN ITERATION LOOP */
         while(1) {
-            int ts, ts2, ts3;
+            int ts2, ts3;
 
-            ts = MP.t;
-            MP.t = t;
-            mp_pwr_integer(&t1, np, &t2);
+            mp_xpowy_integer(&t1, np, &t2);
             mp_multiply(x, &t2, &t2);
             mp_add_integer(&t2, -1, &t2);
-            MP.t = ts;
-
-            /* TEMPORARILY REDUCE T */
-            ts = MP.t;
-            MP.t = (t + it0) / 2;
             mp_multiply(&t1, &t2, &t2);
             mp_divide_integer(&t2, np, &t2);
-            MP.t = ts;
-
-            ts = MP.t;
-            MP.t = t;
             mp_subtract(&t1, &t2, &t1);
-            MP.t = ts;
 
             /*  FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE BECAUSE
              *  NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
              */
-            if (t >= MP.t)
+            if (t >= MP_T)
                 break;
 
             ts3 = t;
-            t = MP.t;
+            t = MP_T;
             do {
                 ts2 = t;
                 t = (t + it0) / 2;
             } while (t > ts3);
-            t = min(ts2, MP.t);
+            t = min(ts2, MP_T);
         }
 
         /*  NOW R(I2) IS X**(-1/NP)
          *  CHECK THAT NEWTON ITERATION WAS CONVERGING
          */
-        if (t2.sign != 0 && (t1.exponent - t2.exponent) << 1 < MP.t - it0) {
+        if (t2.sign != 0 && (t1.exponent - t2.exponent) << 1 < MP_T - it0) {
             /*  THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
              *  OR THAT THE INITIAL APPROXIMATION OBTAINED USING ALOG AND EXP
              *  IS NOT ACCURATE ENOUGH.
@@ -2134,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;
     }
@@ -2154,14 +1752,12 @@ mp_sqrt(const MPNumber *x, MPNumber *z)
     int i, i2, iy3;
     MPNumber t;
 
-    mpchk();
-
     /* MP_ROOT NEEDS 4T+10 WORDS, BUT CAN OVERLAP SLIGHTLY. */
-    i2 = MP.t * 3 + 9;
+    i2 = MP_T * 3 + 9;
     if (x->sign < 0) {
         mperr("*** X NEGATIVE IN CALL TO SUBROUTINE MP_SQRT ***");
     } else if (x->sign == 0) {
-        z->sign = 0;
+        mp_set_from_integer(0, z);
     } else {
         mp_root(x, -2, &t);
         i = t.fraction[0];
@@ -2224,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);
@@ -2238,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 36a14c4..2e46492 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,25 +44,31 @@
 /* Size of the multiple precision values */
 #define MP_SIZE 1000
 
-/* Object for a high precision floating point number representation */
+/* Base for numbers */
+#define MP_BASE 10000
+
+/* Object for a high precision floating point number representation
+ * 
+ * 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]; // Size MP.t?
+   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
@@ -139,20 +146,17 @@ 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) */
-void   mp_logarithm(int n, MPNumber *x, MPNumber *z);
+/* Sets z = log_n x */
+void   mp_logarithm(int n, const MPNumber *x, MPNumber *z);
 
 /* Sets z = Ï? */
 void   mp_get_pi(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 = e */
+void   mp_get_eulers(MPNumber *z);
 
 /* Sets z = nâ??x */
 void   mp_root(const MPNumber *x, int n, MPNumber *z);
@@ -163,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);
 
@@ -211,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]