gcalctool r2254 - in trunk: . gcalctool



Author: rancell
Date: Wed Oct  8 02:36:11 2008
New Revision: 2254
URL: http://svn.gnome.org/viewvc/gcalctool?rev=2254&view=rev

Log:
Refactored mp-convert.c and mp-trigonometric.c from mp.c/mpmath.c (Bug #524091)

Added:
   trunk/gcalctool/mp-convert.c
   trunk/gcalctool/mp-internal.h
   trunk/gcalctool/mp-trigonometric.c
Modified:
   trunk/ChangeLog
   trunk/gcalctool/Makefile.am
   trunk/gcalctool/calctool.c
   trunk/gcalctool/ce_tokeniser.l
   trunk/gcalctool/functions.c
   trunk/gcalctool/get.c
   trunk/gcalctool/gtk.c
   trunk/gcalctool/mp.c
   trunk/gcalctool/mp.h
   trunk/gcalctool/mpmath.c
   trunk/gcalctool/mpmath.h

Modified: trunk/gcalctool/Makefile.am
==============================================================================
--- trunk/gcalctool/Makefile.am	(original)
+++ trunk/gcalctool/Makefile.am	Wed Oct  8 02:36:11 2008
@@ -26,6 +26,8 @@
 	functions.h \
 	mp.c \
 	mp.h \
+	mp-convert.c \        
+	mp-trigonometric.c \
 	mpmath.c \
 	mpmath.h \
 	financial.c \

Modified: trunk/gcalctool/calctool.c
==============================================================================
--- trunk/gcalctool/calctool.c	(original)
+++ trunk/gcalctool/calctool.c	Wed Oct  8 02:36:11 2008
@@ -600,7 +600,7 @@
 {
     gchar *str = g_strdup(value);
 
-    MPstr_to_num(str, DEC, v->MPcon_vals[n]);
+    MPstr_to_num(str, 10, v->MPcon_vals[n]);
     g_free(str);
 }
 

Modified: trunk/gcalctool/ce_tokeniser.l
==============================================================================
--- trunk/gcalctool/ce_tokeniser.l	(original)
+++ trunk/gcalctool/ce_tokeniser.l	Wed Oct  8 02:36:11 2008
@@ -96,35 +96,35 @@
 {DEC_NUM}{EXP}{DEC_NUM} {
 if (v->base == HEX) REJECT;
 if (strlen(yytext) > MAX_DIGITS) parser_state.error = -PARSER_ERR_TOO_LONG_NUMBER;
-mp_set_from_string(yytext, celval.int_t);
+mp_set_from_string(yytext, basevals[v->base], celval.int_t);
 return tNUMBER;
 }
 
 {BIN_NUM} {
 if (v->base != BIN) REJECT;
 if (strlen(yytext) > MAX_DIGITS) parser_state.error = -PARSER_ERR_TOO_LONG_NUMBER;
-MPstr_to_num(yytext, v->base, celval.int_t);
+MPstr_to_num(yytext, basevals[v->base], celval.int_t);
 return tNUMBER;
 }
 
 {OCT_NUM} {
 if (v->base != OCT) REJECT;
 if (strlen(yytext) > MAX_DIGITS) parser_state.error = -PARSER_ERR_TOO_LONG_NUMBER;
-MPstr_to_num(yytext, v->base, celval.int_t);
+MPstr_to_num(yytext, basevals[v->base], celval.int_t);
 return tNUMBER;
 }
 
 {DEC_NUM} {
 if (v->base != DEC) REJECT;
 if (strlen(yytext) > MAX_DIGITS) parser_state.error = -PARSER_ERR_TOO_LONG_NUMBER;
-MPstr_to_num(yytext, v->base, celval.int_t);
+MPstr_to_num(yytext, basevals[v->base], celval.int_t);
 return tNUMBER;
 }
 
 {HEX_NUM} {
 if (v->base != HEX) REJECT;
 if (strlen(yytext) > MAX_DIGITS) parser_state.error = -PARSER_ERR_TOO_LONG_NUMBER;
-MPstr_to_num(yytext, v->base, celval.int_t);
+MPstr_to_num(yytext, basevals[v->base], celval.int_t);
 return tNUMBER;
 }
 

Modified: trunk/gcalctool/functions.c
==============================================================================
--- trunk/gcalctool/functions.c	(original)
+++ trunk/gcalctool/functions.c	Wed Oct  8 02:36:11 2008
@@ -221,7 +221,7 @@
         case KEY_CLEAR_ENTRY:
             display_clear(&v->display);
             ui_set_error_state(FALSE);
-            MPstr_to_num("0", DEC, ans);
+            MPstr_to_num("0", 10, ans);
             break;
 
         case KEY_SHIFT:

Modified: trunk/gcalctool/get.c
==============================================================================
--- trunk/gcalctool/get.c	(original)
+++ trunk/gcalctool/get.c	Wed Oct  8 02:36:11 2008
@@ -248,7 +248,7 @@
     for (i = 0; i < MAX_REGISTERS; i++) {
         SNPRINTF(key, MAXLINE, "register%d", i);
         if (get_str_resource(key, str)) {
-            MPstr_to_num(str, DEC, v->MPmvals[i]);
+            MPstr_to_num(str, 10, v->MPmvals[i]);
         }
     }
 

Modified: trunk/gcalctool/gtk.c
==============================================================================
--- trunk/gcalctool/gtk.c	(original)
+++ trunk/gcalctool/gtk.c	Wed Oct  8 02:36:11 2008
@@ -490,7 +490,7 @@
     int *ans;
 
     ans = display_get_answer(&v->display);
-    MPstr_to_num("0", DEC, ans);
+    MPstr_to_num("0", 10, ans);
     display_clear(&v->display);
     display_set_number(&v->display, ans);
 }
@@ -1393,7 +1393,7 @@
         }
         entry = glade_xml_get_widget(X->financial,
                                      finc_dialog_fields[dialog][i]);
-        MPstr_to_num(gtk_entry_get_text(GTK_ENTRY(entry)), DEC, arg[i]);
+        MPstr_to_num(gtk_entry_get_text(GTK_ENTRY(entry)), 10, arg[i]);
     }
     do_finc_expression(dialog, arg[0], arg[1], arg[2], arg[3]);
 }
@@ -1508,7 +1508,7 @@
                                    COLUMN_NUMBER, &number,
                                    COLUMN_VALUE, &value,
                                    COLUMN_DESCRIPTION, &description, -1);
-                MPstr_to_num(value, DEC, v->MPcon_vals[number]);
+                MPstr_to_num(value, 10, v->MPcon_vals[number]);
                 STRNCPY(v->con_names[number], description, MAXLINE - 1);
                 put_constant(number, value, description);
             } while (gtk_tree_model_iter_next(X->constants_model, &iter));
@@ -1758,7 +1758,7 @@
         return;
     }   
 
-    MPstr_to_num(vline, DEC, v->MPcon_vals[n]);
+    MPstr_to_num(vline, 10, v->MPcon_vals[n]);
     STRNCPY(v->con_names[n], nline, MAXLINE - 1);
     g_free(nline);
     g_free(vline);

Added: trunk/gcalctool/mp-convert.c
==============================================================================
--- (empty file)
+++ trunk/gcalctool/mp-convert.c	Wed Oct  8 02:36:11 2008
@@ -0,0 +1,592 @@
+
+/*  $Header$
+ *
+ *  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ *           
+ *  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
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *           
+ *  This program is distributed in the hope that it will be useful, but 
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
+ *  General Public License for more details.
+ *           
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+#include "mp.h"
+#include "mp-internal.h"
+
+// FIXME: Needed for v->radix
+#include "calctool.h"
+
+/*  SETS Y = X FOR MP X AND Y.
+ *  SEE IF X AND Y HAVE THE SAME ADDRESS (THEY OFTEN DO)
+ */
+void
+mp_set_from_mp(const int *x, int *y)
+{
+    /* 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[0] == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    memcpy (y, x, (MP.t + 2)*sizeof(int));
+}
+
+/*  CONVERTS SINGLE-PRECISION NUMBER RX TO MULTIPLE-PRECISION Z.
+ *  SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
+ *  WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mp_set_from_float(float rx, int *z)
+{
+    int i, k, i2, ib, ie, re, tp, rs;
+    float rb, rj;
+    
+    mpchk(1, 4);
+    i2 = MP.t + 4;
+
+    /* CHECK SIGN */
+    if (rx < (float) 0.0) {
+        rs = -1;
+        rj = -(double)(rx);
+    } else if (rx > (float) 0.0) {
+        rs = 1;
+        rj = rx;
+    } else {
+        /* IF RX = 0E0 RETURN 0 */
+        z[0] = 0;
+        return;
+    }
+
+    ie = 0;
+
+    /* INCREASE IE AND DIVIDE RJ BY 16. */    
+    while (rj >= (float)1.0) {
+        ++ie;
+        rj *= (float) 0.0625;
+    }
+
+    while (rj < (float).0625) {
+        --ie;
+        rj *= (float)16.0;
+    }
+
+    /*  NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
+     *  SET EXPONENT TO 0
+     */
+    re = 0;
+    rb = (float) MP.b;
+
+    /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
+    for (i = 0; i < i2; i++) {
+        rj = rb * rj;
+        MP.r[i] = (int) rj;
+        rj -= (float) MP.r[i];
+    }
+
+    /* NORMALIZE RESULT */
+    mpnzr(rs, &re, z, 0);
+
+    /* Computing MAX */
+    ib = max(MP.b * 7 * MP.b, 32767) / 16;
+    tp = 1;
+
+    /* NOW MULTIPLY BY 16**IE */
+    if (ie < 0)  {
+        k = -ie;
+        for (i = 1; i <= k; ++i) {
+            tp <<= 4;
+            if (tp <= ib && tp != MP.b && i < k)
+                continue;
+            mpdivi(z, tp, z);
+            tp = 1;
+        }
+    } else if (ie > 0)  {
+        for (i = 1; i <= ie; ++i) {
+            tp <<= 4;
+            if (tp <= ib && tp != MP.b && i < ie)
+                continue;
+            mpmuli(z, tp, z);
+            tp = 1;
+        }
+    }
+
+    return;
+}
+
+/*  CONVERTS DOUBLE-PRECISION NUMBER DX TO MULTIPLE-PRECISION Z.
+ *  SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
+ *  WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
+ *  THIS ROUTINE IS NOT CALLED BY ANY OTHER ROUTINE IN MP,
+ *  SO MAY BE OMITTED IF DOUBLE-PRECISION IS NOT AVAILABLE.
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mp_set_from_double(double dx, int *z)
+{
+    int i, k, i2, ib, ie, re, tp, rs;
+    double db, dj;
+
+    mpchk(1, 4);
+    i2 = MP.t + 4;
+
+    /* CHECK SIGN */
+    if (dx < 0.)  {
+        rs = -1;
+        dj = -dx;
+    } else if (dx > 0.)  {
+        rs = 1;
+        dj = dx;
+    } else {
+        z[0] = 0;
+        return;
+    } 
+
+    /* INCREASE IE AND DIVIDE DJ BY 16. */
+    for (ie = 0; dj >= 1.0; ie++)
+      dj *= 1.0/16.0;
+
+    for ( ; dj < 1.0/16.0; ie--)
+      dj *= 16.;
+
+    /*  NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
+     *  SET EXPONENT TO 0
+     */
+    re = 0;
+
+    db = (double) MP.b;
+
+    /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
+    for (i = 0; i < i2; i++) {
+        dj = db * dj;
+        MP.r[i] = (int) dj;
+        dj -= (double) MP.r[i];
+    }
+
+    /* NORMALIZE RESULT */
+    mpnzr(rs, &re, z, 0);
+
+    /* Computing MAX */
+    ib = max(MP.b * 7 * MP.b, 32767) / 16;
+    tp = 1;
+
+    /* NOW MULTIPLY BY 16**IE */
+    if (ie < 0) {
+        k = -ie;
+        for (i = 1; i <= k; ++i) {
+            tp <<= 4;
+            if (tp <= ib && tp != MP.b && i < k)
+                continue;
+            mpdivi(z, tp, z);
+            tp = 1;
+        }
+    } else if (ie > 0) {
+        for (i = 1; i <= ie; ++i) {
+            tp <<= 4;
+            if (tp <= ib && tp != MP.b && i < ie)
+                continue;
+            mpmuli(z, tp, z);
+            tp = 1;
+        }
+    }
+
+    return;
+}
+
+
+/*  CONVERTS INTEGER IX TO MULTIPLE-PRECISION Z.
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mp_set_from_integer(int ix, int *z)
+{
+    mpchk(1, 4);
+
+    if (ix == 0) {
+        z[0] = 0;
+        return;
+    }
+
+    if (ix < 0) {
+        ix = -ix;
+        z[0] = -1;
+    }
+    else
+        z[0] = 1;
+
+    /* SET EXPONENT TO T */
+    z[1] = MP.t;
+
+    /* CLEAR FRACTION */
+    memset(&z[2], 0, (MP.t-1)*sizeof(int));
+
+    /* INSERT IX */
+    z[MP.t + 1] = ix;
+
+    /* NORMALIZE BY CALLING MPMUL2 */
+    mpmul2(z, 1, z, 1);
+}
+
+/* CONVERTS THE RATIONAL NUMBER I/J TO MULTIPLE PRECISION Q. */
+void
+mp_set_from_fraction(int i, int j, int *q)
+{
+    mpgcd(&i, &j);
+
+    if (j == 0) {
+      mperr("*** J == 0 IN CALL TO MP_SET_FROM_FRACTION ***\n");
+      q[0] = 0;
+      return;
+    }
+
+    if (j < 0) {
+      i = -i;
+      j = -j;
+    }
+
+    mp_set_from_integer(i, q);
+    if (j != 1) mpdivi(q, j, q);
+}
+
+/*  CONVERTS MULTIPLE-PRECISION X TO INTEGER, AND
+ *  RETURNS RESULT.
+ *  ASSUMING THAT X NOT TOO LARGE (ELSE USE MPCMIM).
+ *  X IS TRUNCATED TOWARDS ZERO.
+ *  IF INT(X)IS TOO LARGE TO BE REPRESENTED AS A SINGLE-
+ *  PRECISION INTEGER, IZ IS RETURNED AS ZERO.  THE USER
+ *  MAY CHECK FOR THIS POSSIBILITY BY TESTING IF
+ *  ((X(1).NE.0).AND.(X(2).GT.0).AND.(IZ.EQ.0)) IS TRUE ON
+ *  RETURN FROM MP_CAST_TO_INST.
+ */
+int
+mp_cast_to_int(const int *x)
+{
+    int i, j, k, j1, x2, kx, xs, izs, ret_val = 0;
+
+    xs = x[0];
+    /* RETURN 0 IF X = 0 OR IF NUMBER FRACTION */    
+    if (xs == 0  ||  x[1] <= 0)
+        return 0;
+
+    x2 = x[1];
+    for (i = 1; i <= x2; ++i) {
+        izs = ret_val;
+        ret_val = MP.b * ret_val;
+        if (i <= MP.t)
+            ret_val += x[i + 1];
+
+        /* CHECK FOR SIGNS OF INTEGER OVERFLOW */
+        if (ret_val <= 0 || ret_val <= izs)
+            return 0;
+    }
+
+    /*  CHECK THAT RESULT IS CORRECT (AN UNDETECTED OVERFLOW MAY
+     *  HAVE OCCURRED).
+     */
+    j = ret_val;
+    for (i = 1; i <= x2; ++i) {
+        j1 = j / MP.b;
+        k = x2 + 1 - i;
+        kx = 0;
+        if (k <= MP.t)
+            kx = x[k + 1];
+        if (kx != j - MP.b * j1)
+            return 0;
+        j = j1;
+    }
+    if (j != 0)
+        return 0;
+
+    /* RESULT CORRECT SO RESTORE SIGN AND RETURN */
+    ret_val = xs * ret_val;
+    return ret_val;
+
+    /* Old comment about returning zero: */
+    /*  HERE OVERFLOW OCCURRED (OR X WAS UNNORMALIZED), SO
+     *  RETURN ZERO.
+     */
+}
+
+static double
+mppow_ri(float ap, int bp)
+{
+    double pow = 1.0;
+
+    if (bp != 0) { 
+        if (bp < 0) {
+            if (ap == 0) return(pow);
+            bp = -bp;
+            ap = 1/ap;
+        }
+        for (;;) { 
+            if (bp & 01)  pow *= ap;
+            if (bp >>= 1) ap *= ap;
+            else break;
+        }
+    }
+
+    return(pow);
+}
+
+/*  CONVERTS MULTIPLE-PRECISION X TO SINGLE-PRECISION.
+ *  ASSUMES X IN ALLOWABLE RANGE.  THERE IS SOME LOSS OF
+ *  ACCURACY IF THE EXPONENT IS LARGE.
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+float
+mp_cast_to_float(const int *x)
+{
+    float rz = 0.0;
+
+    int i, tm = 0;
+    float rb, rz2;
+    
+    mpchk(1, 4);
+    if (x[0] == 0)
+        return 0.0;
+
+    rb = (float) MP.b;
+    for (i = 1; i <= MP.t; ++i) {
+        rz = rb * rz + (float) x[i + 1];
+        tm = i;
+
+        /* CHECK IF FULL SINGLE-PRECISION ACCURACY ATTAINED */
+        rz2 = rz + (float) 1.0;
+        if (rz2 <= rz)
+            break;
+    }
+
+    /* NOW ALLOW FOR EXPONENT */
+    rz *= mppow_ri(rb, x[1] - tm);
+
+    /* CHECK REASONABLENESS OF RESULT */
+    /* LHS SHOULD BE <= 0.5, BUT ALLOW FOR SOME ERROR IN ALOG */
+    if (rz <= (float)0. ||
+        fabs((float) x[1] - (log(rz) / log((float) MP.b) + (float).5)) > (float).6) {
+        /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
+         *  TRY USING MPCMRE INSTEAD.
+         */
+        mperr("*** FLOATING-POINT OVER/UNDER-FLOW IN MP_CAST_TO_FLOAT ***\n");
+        return 0.0;
+    }
+
+    if (x[0] < 0)
+        rz = -(double)(rz);
+    return rz;
+}
+
+static double
+mppow_di(double ap, int bp)
+{
+    double pow = 1.0;
+
+    if (bp != 0) { 
+        if (bp < 0) {
+            if (ap == 0) return(pow);
+            bp = -bp;
+            ap = 1/ap;
+        }
+        for (;;) { 
+            if (bp & 01) pow *= ap;
+            if (bp >>= 1) ap *= ap;
+            else break;
+        }
+    }
+
+    return(pow);
+}
+
+/*  CONVERTS MULTIPLE-PRECISION X TO DOUBLE-PRECISION,
+ *  AND RETURNS RESULT.
+ *  ASSUMES X IS IN ALLOWABLE RANGE FOR DOUBLE-PRECISION
+ *  NUMBERS.   THERE IS SOME LOSS OF ACCURACY IF THE
+ *  EXPONENT IS LARGE.
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+double
+mp_cast_to_double(const int *x)
+{
+    int i, tm = 0;
+    double d__1, db, dz2, ret_val = 0.0;
+
+    mpchk(1, 4);
+    if (x[0] == 0)
+        return 0.0;
+
+    db = (double) MP.b;
+    for (i = 1; i <= MP.t; ++i) {
+        ret_val = db * ret_val + (double) x[i + 1];
+        tm = i;
+
+        /* CHECK IF FULL DOUBLE-PRECISION ACCURACY ATTAINED */
+        dz2 = ret_val + 1.;
+
+        /*  TEST BELOW NOT ALWAYS EQUIVALENT TO - IF (DZ2.LE.DZ) GO TO 20,
+         *  FOR EXAMPLE ON CYBER 76.
+         */
+        if (dz2 - ret_val <= 0.)
+            break;
+    }
+
+    /* NOW ALLOW FOR EXPONENT */
+    ret_val *= mppow_di(db, x[1] - tm);
+
+    /* CHECK REASONABLENESS OF RESULT. */
+    /* LHS SHOULD BE .LE. 0.5 BUT ALLOW FOR SOME ERROR IN DLOG */
+    if (ret_val <= 0. ||
+        ((d__1 = (double) ((float) x[1]) - (log(ret_val) / log((double)
+                ((float) MP.b)) + .5), abs(d__1)) > .6)) {
+        /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
+         *  TRY USING MPCMDE INSTEAD.
+         */
+        mperr("*** FLOATING-POINT OVER/UNDER-FLOW IN MP_CAST_TO_DOUBLE ***\n");
+        return 0.0;
+    }
+    else
+    {
+        if (x[0] < 0)
+            ret_val = -ret_val;
+        return ret_val;
+    }
+}
+
+static int
+char_val(char chr)
+{
+    if (chr >= '0' && chr <= '9') {
+        return(chr - '0');
+    } else if (chr >= 'a' && chr <= 'f') {
+        return(chr - 'a' + 10);
+    } else if (chr >= 'A' && chr <= 'F') {
+        return(chr - 'A' + 10);
+    } else {
+        return(-1);
+    }
+}
+
+/* Convert string into an MP number, in the given base
+ */
+void
+MPstr_to_num(const char *str, int base, int *MPval)
+{
+    const char *optr;
+    int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE];
+    int i, inum;
+    int exp      = 0;
+    int exp_sign = 1;
+    int negate = 0;
+
+    mp_set_from_integer(0, MPval);
+    mp_set_from_integer(base, MPbase);
+
+    optr = str;
+
+    /* Remove any initial spaces or tabs. */
+    while (*optr == ' ' || *optr == '\t') {
+        optr++;
+    }
+
+    /* Check if this is a negative number. */
+    if (*optr == '-') {
+        negate = 1;
+        optr++;
+    }
+
+    while ((inum = char_val(*optr)) >= 0) {
+        mpmul(MPval, MPbase, MPval);
+        mp_add_integer(MPval, inum, MPval);
+        optr++;
+    }
+
+    if (*optr == '.' || *optr == *v->radix) {
+        optr++;
+        for (i = 1; (inum = char_val(*optr)) >= 0; i++) {
+            mppwr(MPbase, i, MP1);
+            mp_set_from_integer(inum, MP2);
+            mpdiv(MP2, MP1, MP1);
+            mp_add(MPval, MP1, MPval);
+        optr++;
+        }
+    }
+
+    while (*optr == ' ') {
+        optr++;
+    }
+ 
+    if (*optr != '\0') {
+        if (*optr == '-') {
+            exp_sign = -1;
+        }
+ 
+        while ((inum = char_val(*++optr)) >= 0) {
+            exp = exp * basevals[(int) base] + inum;
+        }
+    }
+    exp *= exp_sign;
+
+    if (negate == 1) {
+        mp_invert_sign(MPval, MPval);
+    }
+}
+
+static void 
+calc_xtimestenpowx(int s1[MP_SIZE], int s2[MP_SIZE], int t1[MP_SIZE])
+{
+    int MP1[MP_SIZE], MP2[MP_SIZE];
+
+    mp_set_from_integer(10, MP2);
+    mppwr2(MP2, s2, MP1);
+    mpmul(s1, MP1, t1);
+}
+
+void
+mp_set_from_string(const char *number, int base, int t[MP_SIZE])
+{
+    int i;
+    char *a = NULL;
+    char *b = NULL;
+
+    int MP_a[MP_SIZE];
+    int MP_b[MP_SIZE];
+
+    assert(number);
+    a = strdup(number);
+    assert(a);
+
+    for (i = 0; !((a[i] == 'e') || (a[i] == 'E')); i++) {
+        assert(a[i]);
+    }
+
+    a[i] = 0;
+    b = &a[i+2];
+
+    MPstr_to_num(a, base, MP_a);
+    MPstr_to_num(b, base, MP_b);
+    if (a[i+1] == '-') {
+        int MP_c[MP_SIZE];
+        mp_invert_sign(MP_b, MP_c);
+        calc_xtimestenpowx(MP_a, MP_c, t);
+    } else {
+        calc_xtimestenpowx(MP_a, MP_b, t);
+    }
+
+    free(a);
+}

Added: trunk/gcalctool/mp-internal.h
==============================================================================
--- (empty file)
+++ trunk/gcalctool/mp-internal.h	Wed Oct  8 02:36:11 2008
@@ -0,0 +1,42 @@
+
+/*  $Header$
+ *
+ *  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ *           
+ *  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
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *           
+ *  This program is distributed in the hope that it will be useful, but 
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
+ *  General Public License for more details.
+ *           
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ */
+
+#ifndef MP_INTERNAL_H
+#define MP_INTERNAL_H
+
+#define min(a, b)   ((a) <= (b) ? (a) : (b))
+#define max(a, b)   ((a) >= (b) ? (a) : (b))
+
+struct {
+    int b, t, m, mxr, r[MP_SIZE];
+} MP;
+
+void mpchk(int i, int j);
+void mpgcd(int *, int *);
+void mpmul2(int *, int, int *, int);
+void mpnzr(int, int *, int *, int);
+void mpexp1(const int *, int *);
+void mpmulq(int *, int, int, int *);
+void mprec(const int *, int *);
+void mpadd2(const int *, const int *, int *, int, int);
+void mpart1(int, int *);
+
+#endif /* MP_INTERNAL_H */

Added: trunk/gcalctool/mp-trigonometric.c
==============================================================================
--- (empty file)
+++ trunk/gcalctool/mp-trigonometric.c	Wed Oct  8 02:36:11 2008
@@ -0,0 +1,661 @@
+
+/*  $Header$
+ *
+ *  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ *           
+ *  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
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *           
+ *  This program is distributed in the hope that it will be useful, but 
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
+ *  General Public License for more details.
+ *           
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <libintl.h>
+#define _ gettext
+
+#include "mp.h"
+#include "mp-internal.h"
+
+// FIXME: Needed for doerr
+#include "calctool.h"
+
+/*  COMPARES MP NUMBER X WITH INTEGER I, RETURNING
+ *      +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 int *x, int i)
+{
+    mpchk(2, 6);
+
+    /* CONVERT I TO MULTIPLE-PRECISION AND COMPARE */
+    mp_set_from_integer(i, &MP.r[MP.t + 4]);
+    return mp_compare_mp_to_mp(x, &MP.r[MP.t + 4]);
+}
+
+/*  COMPUTES Y = SIN(X) IF IS != 0, Y = COS(X) IF IS == 0,
+ *  USING TAYLOR SERIES.   ASSUMES ABS(X) .LE. 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(int *x, int *y, int is)
+{
+    int i, b2, i2, i3, ts;
+
+    mpchk(3, 8);
+
+    /* SIN(0) = 0, COS(0) = 1 */
+    if (x[0] == 0) {
+        y[0] = 0;
+        if (is == 0)
+            mp_set_from_integer(1, y);
+        return;
+    }
+
+    i2 = MP.t + 5;
+    i3 = i2 + MP.t + 2;
+    b2 = max(MP.b,64) << 1;
+    mpmul(x, x, &MP.r[i3 - 1]);
+    if (mp_compare_mp_to_int(&MP.r[i3 - 1], 1) > 0) {
+        mperr("*** ABS(X) .GT. 1 IN CALL TO MPSIN1 ***\n");
+    }
+
+    if (is == 0)
+        mp_set_from_integer(1, &MP.r[i2 - 1]);
+    if (is != 0)
+        mp_set_from_mp(x, &MP.r[i2 - 1]);
+
+    y[0] = 0;
+    i = 1;
+    ts = MP.t;
+    if (is != 0) {
+        mp_set_from_mp(&MP.r[i2 - 1], y);
+        i = 2;
+    }
+
+    /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
+    do {
+        MP.t = MP.r[i2] + ts + 2;
+        if (MP.t <= 2)
+            break;
+
+        MP.t = min(MP.t,ts);
+
+        /* PUT R(I3) FIRST IN CASE ITS DIGITS ARE MAINLY ZERO */
+        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i2 - 1]);
+
+        /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
+         *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
+         */
+        if (i > b2) {
+            mpdivi(&MP.r[i2 - 1], -i, &MP.r[i2 - 1]);
+            mpdivi(&MP.r[i2 - 1], i + 1, &MP.r[i2 - 1]);
+        } else {
+            mpdivi(&MP.r[i2 - 1], -i * (i + 1), &MP.r[i2 - 1]);
+        }
+
+        i += 2;
+        MP.t = ts;
+        mpadd2(&MP.r[i2 - 1], y, y, *y, 0);
+    } while(MP.r[i2 - 1] != 0);
+
+    MP.t = ts;
+    if (is == 0)
+        mp_add_integer(y, 1, y);
+}
+
+/*  RETURNS Y = COS(X) FOR MP X AND Y, USING MPSIN AND MPSIN1.
+ *  DIMENSION OF R IN COMMON AT LEAST 5T+12.
+ */
+void
+mpcos(int *x, int *y)
+{
+    int i2;
+
+    /* COS(0) = 1 */    
+    if (x[0] == 0) {
+        mp_set_from_integer(1, y);
+        return;
+    }
+
+    /* CHECK LEGALITY OF B, T, M AND MXR */
+    mpchk(5, 12);
+    i2 = MP.t * 3 + 12;
+
+    /* SEE IF ABS(X) <= 1 */
+    mp_abs(x, y);
+    if (mp_compare_mp_to_int(y, 1) <= 0) {
+        /* HERE ABS(X) <= 1 SO USE POWER SERIES */
+        mpsin1(y, y, 0);
+    } else {
+        /*  HERE ABS(X) > 1 SO USE COS(X) = SIN(PI/2 - ABS(X)),
+         *  COMPUTING PI/2 WITH ONE GUARD DIGIT.
+         */
+        ++MP.t;
+        mppi(&MP.r[i2 - 1]);
+        mpdivi(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
+        --MP.t;
+        mp_subtract(&MP.r[i2 - 1], y, y);
+        mpsin(y, y);
+    }
+}
+
+/*  MP precision arc cosine.
+ *
+ *  1. If (x < -1.0  or x > 1.0) then report DOMAIN error and return 0.0.
+ *
+ *  2. If (x = 0.0) then acos(x) = PI/2.
+ *
+ *  3. If (x = 1.0) then acos(x) = 0.0
+ *
+ *  4. If (x = -1.0) then acos(x) = PI.
+ *
+ *  5. If (0.0 < x < 1.0) then  acos(x) = atan(sqrt(1-(x**2)) / x)
+ *
+ *  6. If (-1.0 < x < 0.0) then acos(x) = atan(sqrt(1-(x**2)) / x) + PI
+ */
+
+void
+mpacos(int *MPx, int *MPretval)
+{
+    int MP0[MP_SIZE],  MP1[MP_SIZE],  MP2[MP_SIZE];
+    int MPn1[MP_SIZE], MPpi[MP_SIZE], MPy[MP_SIZE];
+
+    mppi(MPpi);
+    mp_set_from_integer(0, MP0);
+    mp_set_from_integer(1, MP1);
+    mp_set_from_integer(-1, MPn1);
+
+    if (mp_is_greater_than(MPx, MP1) || mp_is_less_than(MPx, MPn1)) {
+        doerr(_("Error"));
+        mp_set_from_mp(MP0, MPretval);
+    } else if (mp_is_equal(MPx, MP0)) {
+        mpdivi(MPpi, 2, MPretval);
+    } else if (mp_is_equal(MPx, MP1)) {
+        mp_set_from_mp(MP0, MPretval);
+    } else if (mp_is_equal(MPx, MPn1)) {
+        mp_set_from_mp(MPpi, MPretval);
+    } else { 
+        mpmul(MPx, MPx, MP2);
+        mp_subtract(MP1, MP2, MP2);
+        mpsqrt(MP2, MP2);
+        mpdiv(MP2, MPx, MP2);
+        mp_atan(MP2, MPy);
+        if (mp_is_greater_than(MPx, MP0)) {
+            mp_set_from_mp(MPy, MPretval);
+        } else {
+            mp_add(MPy, MPpi, MPretval);
+        }
+    }
+}
+
+/*  RETURNS Y = COSH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
+ *  USES MPEXP, DIMENSION OF R IN COMMON AT LEAST 5T+12
+ */
+void
+mpcosh(const int *x, int *y)
+{
+    int i2;
+
+    /* COSH(0) == 1 */    
+    if (x[0] == 0) {
+      mp_set_from_integer(1, y);
+      return;
+    }
+
+    /* CHECK LEGALITY OF B, T, M AND MXR */
+    mpchk(5, 12);
+    i2 = (MP.t << 2) + 11;
+    mp_abs(x, &MP.r[i2 - 1]);
+
+    /*  IF ABS(X) TOO LARGE MPEXP WILL PRINT ERROR MESSAGE
+     *  INCREASE M TO AVOID OVERFLOW WHEN COSH(X) REPRESENTABLE
+     */
+    MP.m += 2;
+    mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]);
+    mprec(&MP.r[i2 - 1], y);
+    mp_add(&MP.r[i2 - 1], y, y);
+
+    /*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI WILL
+     *  ACT ACCORDINGLY.
+     */
+    MP.m += -2;
+    mpdivi(y, 2, y);
+}
+
+/*  MP precision hyperbolic arc cosine.
+ *
+ *  1. If (x < 1.0) then report DOMAIN error and return 0.0.
+ *
+ *  2. acosh(x) = log(x + sqrt(x**2 - 1))
+ */
+void
+mpacosh(int *MPx, int *MPretval)
+{
+    int MP1[MP_SIZE];
+
+    mp_set_from_integer(1, MP1);
+    if (mp_is_less_than(MPx, MP1)) {
+        doerr(_("Error"));
+        mp_set_from_integer(0, MPretval);
+    } else {
+        mpmul(MPx, MPx, MP1);
+        mp_add_integer(MP1, -1, MP1);
+        mpsqrt(MP1, MP1);
+        mp_add(MPx, MP1, MP1);
+        mpln(MP1, MPretval);
+    }
+}
+
+/*  RETURNS Y = SIN(X) FOR MP X AND Y,
+ *  METHOD IS TO REDUCE X TO (-1, 1) AND USE MPSIN1, SO
+ *  TIME IS O(M(T)T/LOG(T)).
+ *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mpsin(int *x, int *y)
+{
+    int i2, i3, ie, xs;
+    float rx = 0.0, ry;
+
+    mpchk(5, 12);
+    
+    i2 = (MP.t << 2) + 11;
+    if (x[0] == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    xs = x[0];
+    ie = abs(x[1]);
+    if (ie <= 2)
+        rx = mp_cast_to_float(x);
+
+    mp_abs(x, &MP.r[i2 - 1]);
+
+    /* USE MPSIN1 IF ABS(X) .LE. 1 */
+    if (mp_compare_mp_to_int(&MP.r[i2 - 1], 1) <= 0)
+    {
+        mpsin1(&MP.r[i2 - 1], y, 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 MPART1
+     */
+    else {
+        i3 = (MP.t << 1) + 7;
+        mpart1(5, &MP.r[i3 - 1]);
+        mpmuli(&MP.r[i3 - 1], 4, &MP.r[i3 - 1]);
+        mpart1(239, y);
+        mp_subtract(&MP.r[i3 - 1], y, y);
+        mpdiv(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
+        mpdivi(&MP.r[i2 - 1], 8, &MP.r[i2 - 1]);
+        mpcmf(&MP.r[i2 - 1], &MP.r[i2 - 1]);
+
+        /* SUBTRACT 1/2, SAVE SIGN AND TAKE ABS */
+        mp_add_fraction(&MP.r[i2 - 1], -1, 2, &MP.r[i2 - 1]);
+        xs = -xs * MP.r[i2 - 1];
+        if (xs == 0) {
+            y[0] = 0;
+            return;
+        }
+
+        MP.r[i2 - 1] = 1;
+        mpmuli(&MP.r[i2 - 1], 4, &MP.r[i2 - 1]);
+
+        /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
+        if (MP.r[i2] > 0)
+            mp_add_integer(&MP.r[i2 - 1], -2, &MP.r[i2 - 1]);
+
+        if (MP.r[i2 - 1] == 0) {
+            y[0] = 0;
+            return;
+        }        
+
+        MP.r[i2 - 1] = 1;
+        mpmuli(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
+
+        /*  NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
+         *  POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
+         */
+        if (MP.r[i2] > 0) {
+            mp_add_integer(&MP.r[i2 - 1], -2, &MP.r[i2 - 1]);
+            mpmul(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
+            mpsin1(&MP.r[i2 - 1], y, 0);
+        } else {
+            mpmul(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
+            mpsin1(&MP.r[i2 - 1], y, 1);
+        }
+    }
+
+    y[0] = xs;
+    if (ie > 2)
+        return;
+
+    /*  CHECK THAT ABSOLUTE ERROR LESS THAN 0.01 IF ABS(X) .LE. 100
+     *  (IF ABS(X) IS LARGE THEN SINGLE-PRECISION SIN INACCURATE)
+     */
+    if (fabs(rx) > (float)100.)
+        return;
+
+    ry = mp_cast_to_float(y);
+    if (fabs(ry - sin(rx)) < (float) 0.01)
+        return;
+
+    /*  THE FOLLOWING MESSAGE MAY INDICATE THAT
+     *  B**(T-1) IS TOO SMALL.
+     */
+    mperr("*** ERROR OCCURRED IN MPSIN, RESULT INCORRECT ***\n");
+}
+
+/*  RETURNS Y = ARCSIN(X), ASSUMING ABS(X) <= 1,
+ *  FOR MP NUMBERS X AND Y.
+ *  Y IS IN THE RANGE -PI/2 TO +PI/2.
+ *  METHOD IS TO USE MP_ATAN, SO TIME IS O(M(T)T).
+ *  DIMENSION OF R MUST BE AT LEAST 5T+12
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mpasin(int *x, int *y)
+{
+    int i2, i3;
+
+    mpchk(5, 12);
+    i3 = (MP.t << 2) + 11;
+    if (x[0] == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    if (x[1] <= 0) {
+        /* HERE ABS(X) < 1,  SO USE ARCTAN(X/SQRT(1 - X**2)) */
+        i2 = i3 - (MP.t + 2);
+        mp_set_from_integer(1, &MP.r[i2 - 1]);
+        mp_set_from_mp(&MP.r[i2 - 1], &MP.r[i3 - 1]);
+        mp_subtract(&MP.r[i2 - 1], x, &MP.r[i2 - 1]);
+        mp_add(&MP.r[i3 - 1], x, &MP.r[i3 - 1]);
+        mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]);
+        mproot(&MP.r[i3 - 1], -2, &MP.r[i3 - 1]);
+        mpmul(x, &MP.r[i3 - 1], y);
+        mp_atan(y, y);
+        return;
+    }
+
+    /* HERE ABS(X) >= 1.  SEE IF X == +-1 */
+    mp_set_from_integer(x[0], &MP.r[i3 - 1]);
+    if (! mp_is_equal(x, &MP.r[i3 - 1])) {
+        mperr("*** ABS(X) > 1 IN CALL TO MP_ASIN ***\n");
+    }
+
+    /* X == +-1 SO RETURN +-PI/2 */
+    mppi(y);
+    mpdivi(y, MP.r[i3 - 1] << 1, y);
+}
+
+/*  RETURNS Y = SINH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
+ *  METHOD IS TO USE MPEXP OR MPEXP1, SPACE = 5T+12
+ *  SAVE SIGN OF X AND CHECK FOR ZERO, SINH(0) = 0
+ */
+void
+mpsinh(int *x, int *y)
+{
+    int i2, i3, xs;
+
+    xs = x[0];
+    if (xs == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    /* CHECK LEGALITY OF B, T, M AND MXR */
+    mpchk(5, 12);
+    i3 = (MP.t << 2) + 11;
+
+    /* WORK WITH ABS(X) */
+    mp_abs(x, &MP.r[i3 - 1]);
+
+    /* HERE ABS(X) .LT. 1 SO USE MPEXP1 TO AVOID CANCELLATION */
+    if (MP.r[i3] <= 0) {
+        i2 = i3 - (MP.t + 2);
+        mpexp1(&MP.r[i3 - 1], &MP.r[i2 - 1]);
+        mp_add_integer(&MP.r[i2 - 1], 2, &MP.r[i3 - 1]);
+        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], y);
+        mp_add_integer(&MP.r[i2 - 1], 1, &MP.r[i3 - 1]);
+        mpdiv(y, &MP.r[i3 - 1], y);
+    }
+    /*  HERE ABS(X) .GE. 1, IF TOO LARGE MPEXP GIVES ERROR MESSAGE
+     *  INCREASE M TO AVOID OVERFLOW IF SINH(X) REPRESENTABLE
+     */
+    else {
+        MP.m += 2;
+        mpexp(&MP.r[i3 - 1], &MP.r[i3 - 1]);
+        mprec(&MP.r[i3 - 1], y);
+        mp_subtract(&MP.r[i3 - 1], y, y);
+
+        /*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI AT
+         *  STATEMENT 30 WILL ACT ACCORDINGLY.
+         */
+        MP.m += -2;
+    }
+
+    /* DIVIDE BY TWO AND RESTORE SIGN */
+    mpdivi(y, xs << 1, y);
+}
+
+/*  MP precision hyperbolic arc sine.
+ *
+ *  1. asinh(x) = log(x + sqrt(x**2 + 1))
+ */
+
+void
+mpasinh(int *MPx, int *MPretval)
+{
+    int MP1[MP_SIZE];
+ 
+    mpmul(MPx, MPx, MP1);
+    mp_add_integer(MP1, 1, MP1);
+    mpsqrt(MP1, MP1);
+    mp_add(MPx, MP1, MP1);
+    mpln(MP1, MPretval);
+}
+
+void 
+mptan(int s1[MP_SIZE], int t1[MP_SIZE])
+{
+    int MPcos[MP_SIZE]; 
+    int MPsin[MP_SIZE];
+    double cval;
+
+    mpsin(s1, MPsin);
+    mpcos(s1, MPcos);
+    cval = mp_cast_to_double(MPcos);
+    if (cval == 0.0) {
+        doerr(_("Error, cannot calculate cosine"));
+    }
+    mpdiv(MPsin, MPcos, t1);
+}
+
+/*  RETURNS Y = ARCTAN(X) FOR MP X AND Y, USING AN O(T.M(T)) METHOD
+ *  WHICH COULD EASILY BE MODIFIED TO AN O(SQRT(T)M(T))
+ *  METHOD (AS IN MPEXP1). Y 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,
+ *  AND THE COMMENTS IN MPPIGL.
+ *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
+ *  CHECK LEGALITY OF B, T, M AND MXR
+ */
+void
+mp_atan(const int *x, int *y)
+{
+    int i, q, i2, i3, ts;
+    float rx = 0.0, ry;
+
+
+    mpchk(5, 12);
+    i2 = MP.t * 3 + 9;
+    i3 = i2 + MP.t + 2;
+    if (x[0] == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    mp_set_from_mp(x, &MP.r[i3 - 1]);
+    if (abs(x[1]) <= 2)
+        rx = mp_cast_to_float(x);
+
+    q = 1;
+
+    /* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
+    while (MP.r[i3] >= 0)
+    {
+        if (MP.r[i3] == 0 && (MP.r[i3 + 1] + 1) << 1 <= MP.b)
+            break;
+
+        q <<= 1;
+        mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], y);
+        mp_add_integer(y, 1, y);
+        mpsqrt(y, y);
+        mp_add_integer(y, 1, y);
+        mpdiv(&MP.r[i3 - 1], y, &MP.r[i3 - 1]);
+    }
+
+    /* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
+    mp_set_from_mp(&MP.r[i3 - 1], y);
+    mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]);
+    i = 1;
+    ts = MP.t;
+
+    /* SERIES LOOP.  REDUCE T IF POSSIBLE. */
+    while ( (MP.t = ts + 2 + MP.r[i3]) > 1) {
+        MP.t = min(MP.t,ts);
+        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i3 - 1]);
+        mpmulq(&MP.r[i3 - 1], -i, i + 2, &MP.r[i3 - 1]);
+        i += 2;
+        MP.t = ts;
+        mp_add(y, &MP.r[i3 - 1], y);
+	if (MP.r[i3 - 1] == 0) break;
+    }
+
+    /* RESTORE T, CORRECT FOR ARGUMENT REDUCTION, AND EXIT */
+    MP.t = ts;
+    mpmuli(y, q, y);
+
+    /*  CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS EXPONENT
+     *  OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
+     */
+    if (abs(x[1]) > 2)
+        return;
+
+    ry = mp_cast_to_float(y);
+    if (fabs(ry - atan(rx)) < fabs(ry) * (float).01)
+        return;
+
+    /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
+    mperr("*** ERROR OCCURRED IN MP_ATAN, RESULT INCORRECT ***\n");
+}
+
+/*  RETURNS Y = TANH(X) FOR MP NUMBERS X AND Y,
+ *  USING MPEXP OR MPEXP1, SPACE = 5T+12
+ */
+void
+mptanh(int *x, int *y)
+{
+    float r__1;
+
+    int i2, xs;
+
+    /* TANH(0) = 0 */    
+    if (x[0] == 0) {
+        y[0] = 0;
+        return;
+    }
+
+    /* CHECK LEGALITY OF B, T, M AND MXR */
+    mpchk(5, 12);
+    i2 = (MP.t << 2) + 11;
+
+    /* SAVE SIGN AND WORK WITH ABS(X) */
+    xs = x[0];
+    mp_abs(x, &MP.r[i2 - 1]);
+
+    /* SEE IF ABS(X) SO LARGE THAT RESULT IS +-1 */
+    r__1 = (float) MP.t * (float).5 * log((float) MP.b);
+    mp_set_from_float(r__1, y);
+    if (mp_compare_mp_to_mp(&MP.r[i2 - 1], y) > 0) {
+        /* HERE ABS(X) IS VERY LARGE */
+        mp_set_from_integer(xs, y);
+        return;
+    }
+
+    /* HERE ABS(X) NOT SO LARGE */
+    mpmuli(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
+    if (MP.r[i2] > 0) {
+        /* HERE ABS(X) .GE. 1/2 SO USE MPEXP */
+        mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]);
+        mp_add_integer(&MP.r[i2 - 1], -1, y);
+        mp_add_integer(&MP.r[i2 - 1], 1, &MP.r[i2 - 1]);
+        mpdiv(y, &MP.r[i2 - 1], y);
+    } else {
+        /* HERE ABS(X) .LT. 1/2, SO USE MPEXP1 TO AVOID CANCELLATION */
+        mpexp1(&MP.r[i2 - 1], &MP.r[i2 - 1]);
+        mp_add_integer(&MP.r[i2 - 1], 2, y);
+        mpdiv(&MP.r[i2 - 1], y, y);
+    }
+
+    /* RESTORE SIGN */
+    y[0] = xs * y[0];
+}
+
+/*  MP precision hyperbolic arc tangent.
+ *
+ *  1. If (x <= -1.0 or x >= 1.0) then report a DOMAIn error and return 0.0.
+ *
+ *  2. atanh(x) = 0.5 * log((1 + x) / (1 - x))
+ */
+
+void
+mpatanh(int *MPx, int *MPretval)
+{
+    int MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE];
+    int MP3[MP_SIZE], MPn1[MP_SIZE];
+
+    mp_set_from_integer(0, MP0);
+    mp_set_from_integer(1, MP1);
+    mp_set_from_integer(-1, MPn1);
+
+    if (mp_is_greater_equal(MPx, MP1) || mp_is_less_equal(MPx, MPn1)) {
+        doerr(_("Error"));
+        mp_set_from_mp(MP0, MPretval);
+    } else {
+        mp_add(MP1, MPx, MP2);
+        mp_subtract(MP1, MPx, MP3);
+        mpdiv(MP2, MP3, MP3);
+        mpln(MP3, MP3);
+        MPstr_to_num("0.5", 10, MP1);
+        mpmul(MP1, MP3, MPretval);
+    }
+}

Modified: trunk/gcalctool/mp.c
==============================================================================
--- trunk/gcalctool/mp.c	(original)
+++ trunk/gcalctool/mp.c	Wed Oct  8 02:36:11 2008
@@ -19,67 +19,23 @@
  *  02111-1307, USA.
  */
 
-/*  This maths library is based on the MP multi-precision floating-point
- *  arithmetic package originally written in FORTRAN by Richard Brent,
- *  Computer Centre, Australian National University in the 1970's.
- *
- *  It has been converted from FORTRAN into C using the freely available
- *  f2c translator, available via netlib on research.att.com.
- *
- *  The subsequently converted C code has then been tidied up, mainly to
- *  remove any dependencies on the libI77 and libF77 support libraries.
- *
- *  FOR A GENERAL DESCRIPTION OF THE PHILOSOPHY AND DESIGN OF MP,
- *  SEE - R. P. BRENT, A FORTRAN MULTIPLE-PRECISION ARITHMETIC
- *  PACKAGE, ACM TRANS. MATH. SOFTWARE 4 (MARCH 1978), 57-70.
- *  SOME ADDITIONAL DETAILS ARE GIVEN IN THE SAME ISSUE, 71-81.
- *  FOR DETAILS OF THE IMPLEMENTATION, CALLING SEQUENCES ETC. SEE
- *  THE MP USERS GUIDE.
- */
-
 #include <stdio.h>
 
 #include "mp.h"
+#include "mp-internal.h"
 #include "mpmath.h"
 #include "calctool.h"
 #include "display.h"
 
-#define min(a, b)   ((a) <= (b) ? (a) : (b))
-#define max(a, b)   ((a) >= (b) ? (a) : (b))
-
-static struct {
-    int b, t, m, mxr, r[MP_SIZE];
-} MP;
-
-static double mppow_di(double, int);
-static double mppow_ri(float, int);
-
-static int mp_compare_mp_to_int(const int *, int);
 static int mp_compare_mp_to_float(const int *, float);
-static int mp_compare_mp_to_mp(const int *, const int *);
 static int pow_ii(int, int);
 
-static void mpadd2(const int *, const int *, int *, int, int);
 static int  mpadd3(const int *, const int *, int, int);
-static void mp_add_fraction(const int *, int, int, int *);
-static void mpart1(int, int *);
-static void mpchk(int , int );
-static float mp_cast_to_float(const int *);
-static void mp_set_from_fraction(int, int, int *);
-static void mp_set_from_float(float, int *);
-static void mpexp1(const int *, int *);
 static void mpext(int, int, int *);
-static void mpgcd(int *, int *);
 static void mplns(const int *, int *);
 static void mpmaxr(int *);
 static void mpmlp(int *, const int *, int, int);
-static void mpmul2(int *, int, int *, int);
-static void mpmulq(int *, int, int, int *);
-static void mpnzr(int, int *, int *, int);
 static void mpovfl(int *, const char *);
-static void mprec(const int *, int *);
-static void mproot(int *, int, int *);
-static void mpsin1(int *, int *, int);
 static void mpunfl(int *);
 
 /* SETS Y = ABS(X) FOR MP NUMBERS X AND Y */
@@ -109,7 +65,7 @@
  *  16(1973), 223.  (SEE ALSO BRENT, IEEE TC-22(1973), 601.)
  *  CHECK FOR X OR Y ZERO
  */
-static void
+void
 mpadd2(const int *x, const int *y, int *z, int y_sign, int trunc)
 {
     int sign_prod;
@@ -334,7 +290,7 @@
  *  DIMENSION OF R MUST BE AT LEAST 2T+6
  *  CHECK LEGALITY OF B, T, M AND MXR
  */
-static void
+void
 mp_add_fraction(const int *x, int i, int j, int *y)
 {
     mpchk(2, 6);
@@ -349,7 +305,7 @@
  *  AT LEAST 2T+6
  *  CHECK LEGALITY OF B, T, M AND MXR
  */
-static void
+void
 mpart1(int n, int *y)
 {
     int i, b2, i2, id, ts;
@@ -407,218 +363,11 @@
 }
 
 
-/*  RETURNS Y = ARCSIN(X), ASSUMING ABS(X) <= 1,
- *  FOR MP NUMBERS X AND Y.
- *  Y IS IN THE RANGE -PI/2 TO +PI/2.
- *  METHOD IS TO USE MP_ATAN, SO TIME IS O(M(T)T).
- *  DIMENSION OF R MUST BE AT LEAST 5T+12
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mpasin(int *x, int *y)
-{
-    int i2, i3;
-
-    mpchk(5, 12);
-    i3 = (MP.t << 2) + 11;
-    if (x[0] == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    if (x[1] <= 0) {
-        /* HERE ABS(X) < 1,  SO USE ARCTAN(X/SQRT(1 - X**2)) */
-        i2 = i3 - (MP.t + 2);
-        mp_set_from_integer(1, &MP.r[i2 - 1]);
-        mp_set_from_mp(&MP.r[i2 - 1], &MP.r[i3 - 1]);
-        mp_subtract(&MP.r[i2 - 1], x, &MP.r[i2 - 1]);
-        mp_add(&MP.r[i3 - 1], x, &MP.r[i3 - 1]);
-        mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]);
-        mproot(&MP.r[i3 - 1], -2, &MP.r[i3 - 1]);
-        mpmul(x, &MP.r[i3 - 1], y);
-        mp_atan(y, y);
-        return;
-    }
-
-    /* HERE ABS(X) >= 1.  SEE IF X == +-1 */
-    mp_set_from_integer(x[0], &MP.r[i3 - 1]);
-    if (! mp_is_equal(x, &MP.r[i3 - 1])) {
-        mperr("*** ABS(X) > 1 IN CALL TO MP_ASIN ***\n");
-    }
-
-    /* X == +-1 SO RETURN +-PI/2 */
-    mppi(y);
-    mpdivi(y, MP.r[i3 - 1] << 1, y);
-}
-
-
-/*  RETURNS Y = ARCTAN(X) FOR MP X AND Y, USING AN O(T.M(T)) METHOD
- *  WHICH COULD EASILY BE MODIFIED TO AN O(SQRT(T)M(T))
- *  METHOD (AS IN MPEXP1). Y 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,
- *  AND THE COMMENTS IN MPPIGL.
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mp_atan(const int *x, int *y)
-{
-    int i, q, i2, i3, ts;
-    float rx = 0.0, ry;
-
-
-    mpchk(5, 12);
-    i2 = MP.t * 3 + 9;
-    i3 = i2 + MP.t + 2;
-    if (x[0] == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    mp_set_from_mp(x, &MP.r[i3 - 1]);
-    if (abs(x[1]) <= 2)
-        rx = mp_cast_to_float(x);
-
-    q = 1;
-
-    /* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
-    while (MP.r[i3] >= 0)
-    {
-        if (MP.r[i3] == 0 && (MP.r[i3 + 1] + 1) << 1 <= MP.b)
-            break;
-
-        q <<= 1;
-        mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], y);
-        mp_add_integer(y, 1, y);
-        mpsqrt(y, y);
-        mp_add_integer(y, 1, y);
-        mpdiv(&MP.r[i3 - 1], y, &MP.r[i3 - 1]);
-    }
-
-    /* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
-    mp_set_from_mp(&MP.r[i3 - 1], y);
-    mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]);
-    i = 1;
-    ts = MP.t;
-
-    /* SERIES LOOP.  REDUCE T IF POSSIBLE. */
-    while ( (MP.t = ts + 2 + MP.r[i3]) > 1) {
-        MP.t = min(MP.t,ts);
-        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i3 - 1]);
-        mpmulq(&MP.r[i3 - 1], -i, i + 2, &MP.r[i3 - 1]);
-        i += 2;
-        MP.t = ts;
-        mp_add(y, &MP.r[i3 - 1], y);
-	if (MP.r[i3 - 1] == 0) break;
-    }
-
-    /* RESTORE T, CORRECT FOR ARGUMENT REDUCTION, AND EXIT */
-    MP.t = ts;
-    mpmuli(y, q, y);
-
-    /*  CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS EXPONENT
-     *  OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
-     */
-    if (abs(x[1]) > 2)
-        return;
-
-    ry = mp_cast_to_float(y);
-    if (fabs(ry - atan(rx)) < fabs(ry) * (float).01)
-        return;
-
-    /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
-    mperr("*** ERROR OCCURRED IN MP_ATAN, RESULT INCORRECT ***\n");
-}
-
-
-/*  CONVERTS DOUBLE-PRECISION NUMBER DX TO MULTIPLE-PRECISION Z.
- *  SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
- *  WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
- *  THIS ROUTINE IS NOT CALLED BY ANY OTHER ROUTINE IN MP,
- *  SO MAY BE OMITTED IF DOUBLE-PRECISION IS NOT AVAILABLE.
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mp_set_from_double(double dx, int *z)
-{
-    int i, k, i2, ib, ie, re, tp, rs;
-    double db, dj;
-
-
-    mpchk(1, 4);
-    i2 = MP.t + 4;
-
-    /* CHECK SIGN */
-    if (dx < 0.)  {
-        rs = -1;
-        dj = -dx;
-    } else if (dx > 0.)  {
-        rs = 1;
-        dj = dx;
-    } else {
-        z[0] = 0;
-        return;
-    } 
-
-    /* INCREASE IE AND DIVIDE DJ BY 16. */
-    for (ie = 0; dj >= 1.0; ie++)
-      dj *= 1.0/16.0;
-
-    for ( ; dj < 1.0/16.0; ie--)
-      dj *= 16.;
-
-    /*  NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
-     *  SET EXPONENT TO 0
-     */
-    re = 0;
-
-    db = (double) MP.b;
-
-    /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
-    for (i = 0; i < i2; i++) {
-        dj = db * dj;
-        MP.r[i] = (int) dj;
-        dj -= (double) MP.r[i];
-    }
-
-    /* NORMALIZE RESULT */
-    mpnzr(rs, &re, z, 0);
-
-    /* Computing MAX */
-    ib = max(MP.b * 7 * MP.b, 32767) / 16;
-    tp = 1;
-
-    /* NOW MULTIPLY BY 16**IE */
-    if (ie < 0) {
-        k = -ie;
-        for (i = 1; i <= k; ++i) {
-            tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < k)
-                continue;
-            mpdivi(z, tp, z);
-            tp = 1;
-        }
-    } else if (ie > 0) {
-        for (i = 1; i <= ie; ++i) {
-            tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < ie)
-                continue;
-            mpmuli(z, tp, z);
-            tp = 1;
-        }
-    }
-
-    return;
-}
-
-
 /*  CHECKS LEGALITY OF B, T, M AND MXR.
  *  THE CONDITION ON MXR (THE DIMENSION OF R IN COMMON) IS THAT
  *  MXR >= (I*T + J)
  */
-static void
+void
 mpchk(int i, int j)
 {
     int ib, mx;
@@ -649,96 +398,6 @@
           i, j, mx, MP.mxr, MP.t);
 }
 
-
-/*  CONVERTS INTEGER IX TO MULTIPLE-PRECISION Z.
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mp_set_from_integer(int ix, int *z)
-{
-    mpchk(1, 4);
-
-    if (ix == 0) {
-        z[0] = 0;
-        return;
-    }
-
-    if (ix < 0) {
-        ix = -ix;
-        z[0] = -1;
-    }
-    else
-        z[0] = 1;
-
-    /* SET EXPONENT TO T */
-    z[1] = MP.t;
-
-    /* CLEAR FRACTION */
-    memset(&z[2], 0, (MP.t-1)*sizeof(int));
-
-    /* INSERT IX */
-    z[MP.t + 1] = ix;
-
-    /* NORMALIZE BY CALLING MPMUL2 */
-    mpmul2(z, 1, z, 1);
-}
-
-
-/*  CONVERTS MULTIPLE-PRECISION X TO DOUBLE-PRECISION,
- *  AND RETURNS RESULT.
- *  ASSUMES X IS IN ALLOWABLE RANGE FOR DOUBLE-PRECISION
- *  NUMBERS.   THERE IS SOME LOSS OF ACCURACY IF THE
- *  EXPONENT IS LARGE.
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-double
-mp_cast_to_double(const int *x)
-{
-    int i, tm = 0;
-    double d__1, db, dz2, ret_val = 0.0;
-
-    mpchk(1, 4);
-    if (x[0] == 0)
-        return 0.0;
-
-    db = (double) MP.b;
-    for (i = 1; i <= MP.t; ++i) {
-        ret_val = db * ret_val + (double) x[i + 1];
-        tm = i;
-
-        /* CHECK IF FULL DOUBLE-PRECISION ACCURACY ATTAINED */
-        dz2 = ret_val + 1.;
-
-        /*  TEST BELOW NOT ALWAYS EQUIVALENT TO - IF (DZ2.LE.DZ) GO TO 20,
-         *  FOR EXAMPLE ON CYBER 76.
-         */
-        if (dz2 - ret_val <= 0.)
-            break;
-    }
-
-    /* NOW ALLOW FOR EXPONENT */
-    ret_val *= mppow_di(db, x[1] - tm);
-
-    /* CHECK REASONABLENESS OF RESULT. */
-    /* LHS SHOULD BE .LE. 0.5 BUT ALLOW FOR SOME ERROR IN DLOG */
-    if (ret_val <= 0. ||
-        ((d__1 = (double) ((float) x[1]) - (log(ret_val) / log((double)
-                ((float) MP.b)) + .5), abs(d__1)) > .6)) {
-        /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
-         *  TRY USING MPCMDE INSTEAD.
-         */
-        mperr("*** FLOATING-POINT OVER/UNDER-FLOW IN MP_CAST_TO_DOUBLE ***\n");
-        return 0.0;
-    }
-    else
-    {
-        if (x[0] < 0)
-            ret_val = -ret_val;
-        return ret_val;
-    }
-}
-
-
 /*  FOR MP X AND Y, RETURNS FRACTIONAL PART OF X IN Y,
  *  I.E., Y = X - INTEGER PART OF X (TRUNCATED TOWARDS 0).
  */
@@ -776,67 +435,6 @@
     mpnzr(x[0], &offset_exp, y, 1);
 }
 
-
-/*  CONVERTS MULTIPLE-PRECISION X TO INTEGER, AND
- *  RETURNS RESULT.
- *  ASSUMING THAT X NOT TOO LARGE (ELSE USE MPCMIM).
- *  X IS TRUNCATED TOWARDS ZERO.
- *  IF INT(X)IS TOO LARGE TO BE REPRESENTED AS A SINGLE-
- *  PRECISION INTEGER, IZ IS RETURNED AS ZERO.  THE USER
- *  MAY CHECK FOR THIS POSSIBILITY BY TESTING IF
- *  ((X(1).NE.0).AND.(X(2).GT.0).AND.(IZ.EQ.0)) IS TRUE ON
- *  RETURN FROM MP_CAST_TO_INST.
- */
-int
-mp_cast_to_int(const int *x)
-{
-    int i, j, k, j1, x2, kx, xs, izs, ret_val = 0;
-
-    xs = x[0];
-    /* RETURN 0 IF X = 0 OR IF NUMBER FRACTION */    
-    if (xs == 0  ||  x[1] <= 0)
-        return 0;
-
-    x2 = x[1];
-    for (i = 1; i <= x2; ++i) {
-        izs = ret_val;
-        ret_val = MP.b * ret_val;
-        if (i <= MP.t)
-            ret_val += x[i + 1];
-
-        /* CHECK FOR SIGNS OF INTEGER OVERFLOW */
-        if (ret_val <= 0 || ret_val <= izs)
-            return 0;
-    }
-
-    /*  CHECK THAT RESULT IS CORRECT (AN UNDETECTED OVERFLOW MAY
-     *  HAVE OCCURRED).
-     */
-    j = ret_val;
-    for (i = 1; i <= x2; ++i) {
-        j1 = j / MP.b;
-        k = x2 + 1 - i;
-        kx = 0;
-        if (k <= MP.t)
-            kx = x[k + 1];
-        if (kx != j - MP.b * j1)
-            return 0;
-        j = j1;
-    }
-    if (j != 0)
-        return 0;
-
-    /* RESULT CORRECT SO RESTORE SIGN AND RETURN */
-    ret_val = xs * ret_val;
-    return ret_val;
-
-    /* Old comment about returning zero: */
-    /*  HERE OVERFLOW OCCURRED (OR X WAS UNNORMALIZED), SO
-     *  RETURN ZERO.
-     */
-}
-
-
 /* 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).
@@ -896,25 +494,6 @@
     v->dtype = dtype;
 }
 
-
-/*  COMPARES MP NUMBER X WITH INTEGER I, RETURNING
- *      +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 int *x, int i)
-{
-    mpchk(2, 6);
-
-    /* CONVERT I TO MULTIPLE-PRECISION AND COMPARE */
-    mp_set_from_integer(i, &MP.r[MP.t + 4]);
-    return mp_compare_mp_to_mp(x, &MP.r[MP.t + 4]);
-}
-
-
 /*  COMPARES MP NUMBER X WITH REAL NUMBER RI, RETURNING
  *      +1 IF X .GT. RI,
  *       0 IF X .EQ. RI,
@@ -932,61 +511,12 @@
     return mp_compare_mp_to_mp(x, &MP.r[MP.t + 4]);
 }
 
-
-/*  CONVERTS MULTIPLE-PRECISION X TO SINGLE-PRECISION.
- *  ASSUMES X IN ALLOWABLE RANGE.  THERE IS SOME LOSS OF
- *  ACCURACY IF THE EXPONENT IS LARGE.
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static float
-mp_cast_to_float(const int *x)
-{
-    float rz = 0.0;
-
-    int i, tm = 0;
-    float rb, rz2;
-    
-    mpchk(1, 4);
-    if (x[0] == 0)
-        return 0.0;
-
-    rb = (float) MP.b;
-    for (i = 1; i <= MP.t; ++i) {
-        rz = rb * rz + (float) x[i + 1];
-        tm = i;
-
-        /* CHECK IF FULL SINGLE-PRECISION ACCURACY ATTAINED */
-        rz2 = rz + (float) 1.0;
-        if (rz2 <= rz)
-            break;
-    }
-
-    /* NOW ALLOW FOR EXPONENT */
-    rz *= mppow_ri(rb, x[1] - tm);
-
-    /* CHECK REASONABLENESS OF RESULT */
-    /* LHS SHOULD BE <= 0.5, BUT ALLOW FOR SOME ERROR IN ALOG */
-    if (rz <= (float)0. ||
-        fabs((float) x[1] - (log(rz) / log((float) MP.b) + (float).5)) > (float).6) {
-        /*  FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
-         *  TRY USING MPCMRE INSTEAD.
-         */
-        mperr("*** FLOATING-POINT OVER/UNDER-FLOW IN MP_CAST_TO_FLOAT ***\n");
-        return 0.0;
-    }
-
-    if (x[0] < 0)
-        rz = -(double)(rz);
-    return rz;
-}
-
-
 /*  COMPARES THE MULTIPLE-PRECISION NUMBERS X AND Y,
  *  RETURNING +1 IF X  >  Y,
  *            -1 IF X  <  Y,
  *  AND        0 IF X  == Y.
  */
-static int
+int
 mp_compare_mp_to_mp(const int *x, const int *y)
 {
     int i, t2;
@@ -1018,188 +548,6 @@
     return 0;
 }
 
-
-/*  RETURNS Y = COS(X) FOR MP X AND Y, USING MPSIN AND MPSIN1.
- *  DIMENSION OF R IN COMMON AT LEAST 5T+12.
- */
-void
-mpcos(int *x, int *y)
-{
-    int i2;
-
-    /* COS(0) = 1 */    
-    if (x[0] == 0) {
-        mp_set_from_integer(1, y);
-        return;
-    }
-
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk(5, 12);
-    i2 = MP.t * 3 + 12;
-
-    /* SEE IF ABS(X) <= 1 */
-    mp_abs(x, y);
-    if (mp_compare_mp_to_int(y, 1) <= 0) {
-        /* HERE ABS(X) <= 1 SO USE POWER SERIES */
-        mpsin1(y, y, 0);
-    } else {
-        /*  HERE ABS(X) > 1 SO USE COS(X) = SIN(PI/2 - ABS(X)),
-         *  COMPUTING PI/2 WITH ONE GUARD DIGIT.
-         */
-        ++MP.t;
-        mppi(&MP.r[i2 - 1]);
-        mpdivi(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
-        --MP.t;
-        mp_subtract(&MP.r[i2 - 1], y, y);
-        mpsin(y, y);
-    }
-}
-
-
-/*  RETURNS Y = COSH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
- *  USES MPEXP, DIMENSION OF R IN COMMON AT LEAST 5T+12
- */
-void
-mpcosh(const int *x, int *y)
-{
-    int i2;
-
-    if (x[0] == 0) {
-      /* COSH(0) == 1 */
-      mp_set_from_integer(1, y);
-      return;
-    }
-
-/* CHECK LEGALITY OF B, T, M AND MXR */
-
-    mpchk(5, 12);
-    i2 = (MP.t << 2) + 11;
-    mp_abs(x, &MP.r[i2 - 1]);
-
-/*  IF ABS(X) TOO LARGE MPEXP WILL PRINT ERROR MESSAGE
- *  INCREASE M TO AVOID OVERFLOW WHEN COSH(X) REPRESENTABLE
- */
-
-    MP.m += 2;
-    mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]);
-    mprec(&MP.r[i2 - 1], y);
-    mp_add(&MP.r[i2 - 1], y, y);
-
-/*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI WILL
- *  ACT ACCORDINGLY.
- */
-
-    MP.m += -2;
-    mpdivi(y, 2, y);
-}
-
-
-/* CONVERTS THE RATIONAL NUMBER I/J TO MULTIPLE PRECISION Q. */
-static void
-mp_set_from_fraction(int i, int j, int *q)
-{
-    mpgcd(&i, &j);
-
-    if (j == 0) {
-      mperr("*** J == 0 IN CALL TO MP_SET_FROM_FRACTION ***\n");
-      q[0] = 0;
-      return;
-    }
-
-    if (j < 0) {
-      i = -i;
-      j = -j;
-    }
-
-    mp_set_from_integer(i, q);
-    if (j != 1) mpdivi(q, j, q);
-}
-
-
-/*  CONVERTS SINGLE-PRECISION NUMBER RX TO MULTIPLE-PRECISION Z.
- *  SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
- *  WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-static void
-mp_set_from_float(float rx, int *z)
-{
-    int i, k, i2, ib, ie, re, tp, rs;
-    float rb, rj;
-    
-    mpchk(1, 4);
-    i2 = MP.t + 4;
-
-    /* CHECK SIGN */
-    if (rx < (float) 0.0) {
-        rs = -1;
-        rj = -(double)(rx);
-    } else if (rx > (float) 0.0) {
-        rs = 1;
-        rj = rx;
-    } else {
-        /* IF RX = 0E0 RETURN 0 */
-        z[0] = 0;
-        return;
-    }
-
-    ie = 0;
-
-    /* INCREASE IE AND DIVIDE RJ BY 16. */    
-    while (rj >= (float)1.0) {
-        ++ie;
-        rj *= (float) 0.0625;
-    }
-
-    while (rj < (float).0625) {
-        --ie;
-        rj *= (float)16.0;
-    }
-
-    /*  NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
-     *  SET EXPONENT TO 0
-     */
-    re = 0;
-    rb = (float) MP.b;
-
-    /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
-    for (i = 0; i < i2; i++) {
-        rj = rb * rj;
-        MP.r[i] = (int) rj;
-        rj -= (float) MP.r[i];
-    }
-
-    /* NORMALIZE RESULT */
-    mpnzr(rs, &re, z, 0);
-
-    /* Computing MAX */
-    ib = max(MP.b * 7 * MP.b, 32767) / 16;
-    tp = 1;
-
-    /* NOW MULTIPLY BY 16**IE */
-    if (ie < 0)  {
-        k = -ie;
-        for (i = 1; i <= k; ++i) {
-            tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < k)
-                continue;
-            mpdivi(z, tp, z);
-            tp = 1;
-        }
-    } else if (ie > 0)  {
-        for (i = 1; i <= ie; ++i) {
-            tp <<= 4;
-            if (tp <= ib && tp != MP.b && i < ie)
-                continue;
-            mpmuli(z, tp, z);
-            tp = 1;
-        }
-    }
-
-    return;
-}
-
-
 /*  SETS Z = X/Y, FOR MP X, Y AND Z.
  *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 4T+10
  *  (BUT Z(1) MAY BE R(3T+9)).
@@ -1621,7 +969,7 @@
  *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 3T+8
  *  CHECK LEGALITY OF B, T, M AND MXR
  */
-static void
+void
 mpexp1(const int *x, int *y)
 {
     int i, q, i2, i3, ib, ic, ts;
@@ -1738,7 +1086,7 @@
  *  GREATEST COMMON DIVISOR OF K AND L.
  *  SAVE INPUT PARAMETERS IN LOCAL VARIABLES
  */
-static void
+void
 mpgcd(int *k, int *l)
 {
     int i, j;
@@ -2117,7 +1465,7 @@
  *  EVEN IF SOME DIGITS ARE GREATER THAN B-1.
  *  RESULT IS ROUNDED IF TRUNC == 0, OTHERWISE TRUNCATED.
  */
-static void
+void
 mpmul2(int *x, int iy, int *z, int trunc)
 {
     int c, i, c1, c2, j1, j2;
@@ -2250,7 +1598,7 @@
 
 
 /* MULTIPLIES MP X BY I/J, GIVING MP Y */
-static void
+void
 mpmulq(int *x, int i, int j, int *y)
 {
     int is, js;
@@ -2295,7 +1643,7 @@
  *  AND RETURNS MP RESULT IN Z.  INTEGER ARGUMENTS RE IS
  *  NOT PRESERVED. R*-ROUNDING IS USED IF TRUNC == 0
  */
-static void
+void
 mpnzr(int rs, int *re, int *z, int trunc)
 {
     int i__1;
@@ -2583,7 +1931,7 @@
  *  NEWTONS METHOD IS USED, SO FINAL ONE OR TWO DIGITS MAY
  *  NOT BE CORRECT.
  */
-static void
+void
 mprec(const int *x, int *y)
 {
     /* Initialized data */
@@ -2689,7 +2037,7 @@
  *  USING NEWTONS METHOD WITHOUT DIVISIONS.   SPACE = 4T+10
  *  (BUT Y(1) MAY BE R(3T+9))
  */
-static void
+void
 mproot(int *x, int n, int *y)
 {
     /* Initialized data */
@@ -2915,239 +2263,6 @@
     mpchk(1, 4);
 }
 
-
-/*  RETURNS Y = SIN(X) FOR MP X AND Y,
- *  METHOD IS TO REDUCE X TO (-1, 1) AND USE MPSIN1, SO
- *  TIME IS O(M(T)T/LOG(T)).
- *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
- *  CHECK LEGALITY OF B, T, M AND MXR
- */
-void
-mpsin(int *x, int *y)
-{
-    int i2, i3, ie, xs;
-    float rx = 0.0, ry;
-
-    mpchk(5, 12);
-    
-    i2 = (MP.t << 2) + 11;
-    if (x[0] == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    xs = x[0];
-    ie = abs(x[1]);
-    if (ie <= 2)
-        rx = mp_cast_to_float(x);
-
-    mp_abs(x, &MP.r[i2 - 1]);
-
-    /* USE MPSIN1 IF ABS(X) .LE. 1 */
-    if (mp_compare_mp_to_int(&MP.r[i2 - 1], 1) <= 0)
-    {
-        mpsin1(&MP.r[i2 - 1], y, 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 MPART1
-     */
-    else {
-        i3 = (MP.t << 1) + 7;
-        mpart1(5, &MP.r[i3 - 1]);
-        mpmuli(&MP.r[i3 - 1], 4, &MP.r[i3 - 1]);
-        mpart1(239, y);
-        mp_subtract(&MP.r[i3 - 1], y, y);
-        mpdiv(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
-        mpdivi(&MP.r[i2 - 1], 8, &MP.r[i2 - 1]);
-        mpcmf(&MP.r[i2 - 1], &MP.r[i2 - 1]);
-
-        /* SUBTRACT 1/2, SAVE SIGN AND TAKE ABS */
-        mp_add_fraction(&MP.r[i2 - 1], -1, 2, &MP.r[i2 - 1]);
-        xs = -xs * MP.r[i2 - 1];
-        if (xs == 0) {
-            y[0] = 0;
-            return;
-        }
-
-        MP.r[i2 - 1] = 1;
-        mpmuli(&MP.r[i2 - 1], 4, &MP.r[i2 - 1]);
-
-        /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
-        if (MP.r[i2] > 0)
-            mp_add_integer(&MP.r[i2 - 1], -2, &MP.r[i2 - 1]);
-
-        if (MP.r[i2 - 1] == 0) {
-            y[0] = 0;
-            return;
-        }        
-
-        MP.r[i2 - 1] = 1;
-        mpmuli(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
-
-        /*  NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
-         *  POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
-         */
-        if (MP.r[i2] > 0) {
-            mp_add_integer(&MP.r[i2 - 1], -2, &MP.r[i2 - 1]);
-            mpmul(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
-            mpsin1(&MP.r[i2 - 1], y, 0);
-        } else {
-            mpmul(&MP.r[i2 - 1], y, &MP.r[i2 - 1]);
-            mpsin1(&MP.r[i2 - 1], y, 1);
-        }
-    }
-
-    y[0] = xs;
-    if (ie > 2)
-        return;
-
-    /*  CHECK THAT ABSOLUTE ERROR LESS THAN 0.01 IF ABS(X) .LE. 100
-     *  (IF ABS(X) IS LARGE THEN SINGLE-PRECISION SIN INACCURATE)
-     */
-    if (fabs(rx) > (float)100.)
-        return;
-
-    ry = mp_cast_to_float(y);
-    if (fabs(ry - sin(rx)) < (float) 0.01)
-        return;
-
-    /*  THE FOLLOWING MESSAGE MAY INDICATE THAT
-     *  B**(T-1) IS TOO SMALL.
-     */
-    mperr("*** ERROR OCCURRED IN MPSIN, RESULT INCORRECT ***\n");
-}
-
-
-/*  COMPUTES Y = SIN(X) IF IS != 0, Y = COS(X) IF IS == 0,
- *  USING TAYLOR SERIES.   ASSUMES ABS(X) .LE. 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(int *x, int *y, int is)
-{
-    int i, b2, i2, i3, ts;
-
-    mpchk(3, 8);
-
-    /* SIN(0) = 0, COS(0) = 1 */
-    if (x[0] == 0) {
-        y[0] = 0;
-        if (is == 0)
-            mp_set_from_integer(1, y);
-        return;
-    }
-
-    i2 = MP.t + 5;
-    i3 = i2 + MP.t + 2;
-    b2 = max(MP.b,64) << 1;
-    mpmul(x, x, &MP.r[i3 - 1]);
-    if (mp_compare_mp_to_int(&MP.r[i3 - 1], 1) > 0) {
-        mperr("*** ABS(X) .GT. 1 IN CALL TO MPSIN1 ***\n");
-    }
-
-    if (is == 0)
-        mp_set_from_integer(1, &MP.r[i2 - 1]);
-    if (is != 0)
-        mp_set_from_mp(x, &MP.r[i2 - 1]);
-
-    y[0] = 0;
-    i = 1;
-    ts = MP.t;
-    if (is != 0) {
-        mp_set_from_mp(&MP.r[i2 - 1], y);
-        i = 2;
-    }
-
-    /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
-    do {
-        MP.t = MP.r[i2] + ts + 2;
-        if (MP.t <= 2)
-            break;
-
-        MP.t = min(MP.t,ts);
-
-        /* PUT R(I3) FIRST IN CASE ITS DIGITS ARE MAINLY ZERO */
-        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i2 - 1]);
-
-        /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
-         *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
-         */
-        if (i > b2) {
-            mpdivi(&MP.r[i2 - 1], -i, &MP.r[i2 - 1]);
-            mpdivi(&MP.r[i2 - 1], i + 1, &MP.r[i2 - 1]);
-        } else {
-            mpdivi(&MP.r[i2 - 1], -i * (i + 1), &MP.r[i2 - 1]);
-        }
-
-        i += 2;
-        MP.t = ts;
-        mpadd2(&MP.r[i2 - 1], y, y, *y, 0);
-    } while(MP.r[i2 - 1] != 0);
-
-    MP.t = ts;
-    if (is == 0)
-        mp_add_integer(y, 1, y);
-}
-
-/*  RETURNS Y = SINH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
- *  METHOD IS TO USE MPEXP OR MPEXP1, SPACE = 5T+12
- *  SAVE SIGN OF X AND CHECK FOR ZERO, SINH(0) = 0
- */
-void
-mpsinh(int *x, int *y)
-{
-    int i2, i3, xs;
-
-    xs = x[0];
-    if (xs == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk(5, 12);
-    i3 = (MP.t << 2) + 11;
-
-    /* WORK WITH ABS(X) */
-    mp_abs(x, &MP.r[i3 - 1]);
-
-    /* HERE ABS(X) .LT. 1 SO USE MPEXP1 TO AVOID CANCELLATION */
-    if (MP.r[i3] <= 0) {
-        i2 = i3 - (MP.t + 2);
-        mpexp1(&MP.r[i3 - 1], &MP.r[i2 - 1]);
-        mp_add_integer(&MP.r[i2 - 1], 2, &MP.r[i3 - 1]);
-        mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], y);
-        mp_add_integer(&MP.r[i2 - 1], 1, &MP.r[i3 - 1]);
-        mpdiv(y, &MP.r[i3 - 1], y);
-    }
-    /*  HERE ABS(X) .GE. 1, IF TOO LARGE MPEXP GIVES ERROR MESSAGE
-     *  INCREASE M TO AVOID OVERFLOW IF SINH(X) REPRESENTABLE
-     */
-    else {
-        MP.m += 2;
-        mpexp(&MP.r[i3 - 1], &MP.r[i3 - 1]);
-        mprec(&MP.r[i3 - 1], y);
-        mp_subtract(&MP.r[i3 - 1], y, y);
-
-        /*  RESTORE M.  IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI AT
-         *  STATEMENT 30 WILL ACT ACCORDINGLY.
-         */
-        MP.m += -2;
-    }
-
-    /* DIVIDE BY TWO AND RESTORE SIGN */
-    mpdivi(y, xs << 1, y);
-}
-
-
 /*  RETURNS Y = SQRT(X), USING SUBROUTINE MPROOT IF X .GT. 0.
  *  DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 4T+10
  *  (BUT Y(1) MAY BE R(3T+9)).  X AND Y ARE MP NUMBERS.
@@ -3175,27 +2290,6 @@
     }
 }
 
-
-/*  SETS Y = X FOR MP X AND Y.
- *  SEE IF X AND Y HAVE THE SAME ADDRESS (THEY OFTEN DO)
- */
-void
-mp_set_from_mp(const int *x, int *y)
-{
-    /* 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[0] == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    memcpy (y, x, (MP.t + 2)*sizeof(int));
-}
-
-
 /*  SUBTRACTS Y FROM X, FORMING RESULT IN Z, FOR MP X, Y AND Z.
  *  FOUR GUARD DIGITS ARE USED, AND THEN R*-ROUNDING
  */
@@ -3205,60 +2299,6 @@
     mpadd2(x, y, z, -y[0], 0);
 }
 
-
-/*  RETURNS Y = TANH(X) FOR MP NUMBERS X AND Y,
- *  USING MPEXP OR MPEXP1, SPACE = 5T+12
- */
-void
-mptanh(int *x, int *y)
-{
-    float r__1;
-
-    int i2, xs;
-
-    /* TANH(0) = 0 */    
-    if (x[0] == 0) {
-        y[0] = 0;
-        return;
-    }
-
-    /* CHECK LEGALITY OF B, T, M AND MXR */
-    mpchk(5, 12);
-    i2 = (MP.t << 2) + 11;
-
-    /* SAVE SIGN AND WORK WITH ABS(X) */
-    xs = x[0];
-    mp_abs(x, &MP.r[i2 - 1]);
-
-    /* SEE IF ABS(X) SO LARGE THAT RESULT IS +-1 */
-    r__1 = (float) MP.t * (float).5 * log((float) MP.b);
-    mp_set_from_float(r__1, y);
-    if (mp_compare_mp_to_mp(&MP.r[i2 - 1], y) > 0) {
-        /* HERE ABS(X) IS VERY LARGE */
-        mp_set_from_integer(xs, y);
-        return;
-    }
-
-    /* HERE ABS(X) NOT SO LARGE */
-    mpmuli(&MP.r[i2 - 1], 2, &MP.r[i2 - 1]);
-    if (MP.r[i2] > 0) {
-        /* HERE ABS(X) .GE. 1/2 SO USE MPEXP */
-        mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]);
-        mp_add_integer(&MP.r[i2 - 1], -1, y);
-        mp_add_integer(&MP.r[i2 - 1], 1, &MP.r[i2 - 1]);
-        mpdiv(y, &MP.r[i2 - 1], y);
-    } else {
-        /* HERE ABS(X) .LT. 1/2, SO USE MPEXP1 TO AVOID CANCELLATION */
-        mpexp1(&MP.r[i2 - 1], &MP.r[i2 - 1]);
-        mp_add_integer(&MP.r[i2 - 1], 2, y);
-        mpdiv(&MP.r[i2 - 1], y, y);
-    }
-
-    /* RESTORE SIGN */
-    y[0] = xs * y[0];
-}
-
-
 /*  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.
@@ -3277,29 +2317,6 @@
     x[0] = 0;
 }
 
-
-static double
-mppow_di(double ap, int bp)
-{
-    double pow = 1.0;
-
-    if (bp != 0) { 
-        if (bp < 0) {
-            if (ap == 0) return(pow);
-            bp = -bp;
-            ap = 1/ap;
-        }
-        for (;;) { 
-            if (bp & 01) pow *= ap;
-            if (bp >>= 1) ap *= ap;
-            else break;
-        }
-    }
-
-    return(pow);
-}
-
-
 static int
 pow_ii(int x, int n)
 {
@@ -3315,25 +2332,3 @@
 
     return(pow);
 }
-
-
-static double
-mppow_ri(float ap, int bp)
-{
-    double pow = 1.0;
-
-    if (bp != 0) { 
-        if (bp < 0) {
-            if (ap == 0) return(pow);
-            bp = -bp;
-            ap = 1/ap;
-        }
-        for (;;) { 
-            if (bp & 01)  pow *= ap;
-            if (bp >>= 1) ap *= ap;
-            else break;
-        }
-    }
-
-    return(pow);
-}

Modified: trunk/gcalctool/mp.h
==============================================================================
--- trunk/gcalctool/mp.h	(original)
+++ trunk/gcalctool/mp.h	Wed Oct  8 02:36:11 2008
@@ -19,6 +19,24 @@
  *  02111-1307, USA.
  */
 
+/*  This maths library is based on the MP multi-precision floating-point
+ *  arithmetic package originally written in FORTRAN by Richard Brent,
+ *  Computer Centre, Australian National University in the 1970's.
+ *
+ *  It has been converted from FORTRAN into C using the freely available
+ *  f2c translator, available via netlib on research.att.com.
+ *
+ *  The subsequently converted C code has then been tidied up, mainly to
+ *  remove any dependencies on the libI77 and libF77 support libraries.
+ *
+ *  FOR A GENERAL DESCRIPTION OF THE PHILOSOPHY AND DESIGN OF MP,
+ *  SEE - R. P. BRENT, A FORTRAN MULTIPLE-PRECISION ARITHMETIC
+ *  PACKAGE, ACM TRANS. MATH. SOFTWARE 4 (MARCH 1978), 57-70.
+ *  SOME ADDITIONAL DETAILS ARE GIVEN IN THE SAME ISSUE, 71-81.
+ *  FOR DETAILS OF THE IMPLEMENTATION, CALLING SEQUENCES ETC. SEE
+ *  THE MP USERS GUIDE.
+ */
+
 #ifndef MP_H
 #define MP_H
 
@@ -31,31 +49,24 @@
 
 void mperr(const char *format, ...) __attribute__((format(printf, 1, 2)));
 
+int mp_compare_mp_to_mp(const int *x, const int *y);
+
 int mp_is_equal(const int *, const int *);
 int mp_is_greater_equal(const int *, const int *);
 int mp_is_greater_than(const int *, const int *);
 int mp_is_less_equal(const int *, const int *);
 int mp_is_less_than(const int *, const int *);
 
-double mp_cast_to_double(const int *);
-int    mp_cast_to_int(const int *);
-void   mp_set_from_double(double, int *);
-void   mp_set_from_integer(int, int *);
-void   mp_set_from_mp(const int *, int *);
-
 void mp_abs(const int *, int *);
 void mp_invert_sign(const int *, int *);
 
 void mp_add(const int *, const int *, int *);
 void mp_add_integer(const int *, int, int *);
+void mp_add_fraction(const int *, int, int, int *);
 void mp_subtract(const int *, const int *, int *);
 
-void mpasin(int *, int *);
-void mp_atan(const int *, int *);
 void mpcmf(const int *, int *);
 void mpcmim(const int *, int *);
-void mpcos(int *, int *);
-void mpcosh(const int *, int *);
 void mpdiv(const int *, const int *, int *);
 void mpdivi(const int *, int, int *);
 void mpexp(const int *, int *);
@@ -66,9 +77,34 @@
 void mppwr(const int *, int, int *);
 void mppwr2(int *, int *, int *);
 void mpset(int, int, int);
-void mpsin(int *, int *);
-void mpsinh(int *, int *);
+void mproot(int *, int, int *);
 void mpsqrt(int *, int *);
-void mptanh(int *, int *);
+
+/* mp-convert.c */
+void   mp_set_from_mp(const int *, int *);
+void   mp_set_from_float(float, int *);
+void   mp_set_from_double(double, int *);
+void   mp_set_from_integer(int, int *);
+void   mp_set_from_fraction(int, int, int *);
+float  mp_cast_to_float(const int *);
+double mp_cast_to_double(const int *);
+int    mp_cast_to_int(const int *);
+void   MPstr_to_num(const char *, int, int *);
+void   mp_set_from_string(const char *number, int base, int t[MP_SIZE]);
+
+/* mp-trigonometric.c */
+void mpcos(int *x, int *y);
+void mpcosh(const int *x, int *y);
+void mpsin(int *x, int *y);
+void mpasin(int *, int *);
+void mpsinh(int *x, int *y);
+void mpasinh(int *MPx, int *MPretval);
+void mpacosh(int *MPx, int *MPretval);
+void mpacos(int *MPx, int *MPretval);
+void mptan(int *s1, int *t1);
+void mp_atan(const int *, int *);
+void mptanh(int *x, int *y);
+void mpatanh(int *MPx, int *MPretval);
+
 
 #endif /* MP_H */

Modified: trunk/gcalctool/mpmath.c
==============================================================================
--- trunk/gcalctool/mpmath.c	(original)
+++ trunk/gcalctool/mpmath.c	Wed Oct  8 02:36:11 2008
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <errno.h>
 
+#include "mp.h"
 #include "mpmath.h"
 
 static char digits[] = "0123456789ABCDEF";
@@ -139,7 +140,6 @@
     mp_set_from_double(dval, t1);
 }
 
-
 void
 calc_inv(const int s1[MP_SIZE], int t1[MP_SIZE])     /* Calculate 1/x */
 {
@@ -151,16 +151,6 @@
     mpdiv(MP1, MP2, t1);
 }
 
-
-void 
-calc_tenpowx(int s1[MP_SIZE], int t1[MP_SIZE])   /* Calculate 10^x */
-{
-    int MP1[MP_SIZE];
-    mp_set_from_integer(10, MP1);
-    mppwr2(MP1, s1, t1);
-}
-
-
 void
 calc_xpowy(int MPx[MP_SIZE], int MPy[MP_SIZE], int MPres[MP_SIZE]) /* Do x^y */
 {
@@ -189,16 +179,6 @@
     }
 }
 
-
-void 
-calc_xtimestenpowx(int s1[MP_SIZE], int s2[MP_SIZE], int t1[MP_SIZE])
-{
-    int MP1[MP_SIZE];
-
-    calc_tenpowx(s2, MP1);
-    mpmul(s1, MP1, t1);
-}
-
 int
 calc_modulus(int op1[MP_SIZE], 
 	     int op2[MP_SIZE], 
@@ -230,7 +210,7 @@
 {
     int MP1[MP_SIZE];
 
-    MPstr_to_num("0.01", DEC, MP1);
+    MPstr_to_num("0.01", 10, MP1);
     mpmul(s1, MP1, t1);
 }
 
@@ -241,23 +221,6 @@
 }
 
 
-static void 
-mptan(int s1[MP_SIZE], int t1[MP_SIZE])
-{
-    int MPcos[MP_SIZE]; 
-    int MPsin[MP_SIZE];
-    double cval;
-
-    mpsin(s1, MPsin);
-    mpcos(s1, MPcos);
-    cval = mp_cast_to_double(MPcos);
-    if (cval == 0.0) {
-        doerr(_("Error, cannot calculate cosine"));
-    }
-    mpdiv(MPsin, MPcos, t1);
-}
-
-
 /* Change type to radian */
 
 static void
@@ -312,136 +275,6 @@
     }
 }
 
-
-/*  The following MP routines were not in the Brent FORTRAN package. They are
- *  derived here, in terms of the existing routines.
- */
-
-/*  MP precision arc cosine.
- *
- *  1. If (x < -1.0  or x > 1.0) then report DOMAIN error and return 0.0.
- *
- *  2. If (x = 0.0) then acos(x) = PI/2.
- *
- *  3. If (x = 1.0) then acos(x) = 0.0
- *
- *  4. If (x = -1.0) then acos(x) = PI.
- *
- *  5. If (0.0 < x < 1.0) then  acos(x) = atan(sqrt(1-(x**2)) / x)
- *
- *  6. If (-1.0 < x < 0.0) then acos(x) = atan(sqrt(1-(x**2)) / x) + PI
- */
-
-static void
-mpacos(int *MPx, int *MPretval)
-{
-    int MP0[MP_SIZE],  MP1[MP_SIZE],  MP2[MP_SIZE];
-    int MPn1[MP_SIZE], MPpi[MP_SIZE], MPy[MP_SIZE];
-
-    mppi(MPpi);
-    mp_set_from_integer(0, MP0);
-    mp_set_from_integer(1, MP1);
-    mp_set_from_integer(-1, MPn1);
-
-    if (mp_is_greater_than(MPx, MP1) || mp_is_less_than(MPx, MPn1)) {
-        doerr(_("Error"));
-        mp_set_from_mp(MP0, MPretval);
-    } else if (mp_is_equal(MPx, MP0)) {
-        mpdivi(MPpi, 2, MPretval);
-    } else if (mp_is_equal(MPx, MP1)) {
-        mp_set_from_mp(MP0, MPretval);
-    } else if (mp_is_equal(MPx, MPn1)) {
-        mp_set_from_mp(MPpi, MPretval);
-    } else { 
-        mpmul(MPx, MPx, MP2);
-        mp_subtract(MP1, MP2, MP2);
-        mpsqrt(MP2, MP2);
-        mpdiv(MP2, MPx, MP2);
-        mp_atan(MP2, MPy);
-        if (mp_is_greater_than(MPx, MP0)) {
-            mp_set_from_mp(MPy, MPretval);
-        } else {
-            mp_add(MPy, MPpi, MPretval);
-        }
-    }
-}
-
-
-/*  MP precision hyperbolic arc cosine.
- *
- *  1. If (x < 1.0) then report DOMAIN error and return 0.0.
- *
- *  2. acosh(x) = log(x + sqrt(x**2 - 1))
- */
-
-static void
-mpacosh(int *MPx, int *MPretval)
-{
-    int MP1[MP_SIZE];
-
-    mp_set_from_integer(1, MP1);
-    if (mp_is_less_than(MPx, MP1)) {
-        doerr(_("Error"));
-        mp_set_from_integer(0, MPretval);
-    } else {
-        mpmul(MPx, MPx, MP1);
-        mp_add_integer(MP1, -1, MP1);
-        mpsqrt(MP1, MP1);
-        mp_add(MPx, MP1, MP1);
-        mpln(MP1, MPretval);
-    }
-}
-
-
-/*  MP precision hyperbolic arc sine.
- *
- *  1. asinh(x) = log(x + sqrt(x**2 + 1))
- */
-
-static void
-mpasinh(int *MPx, int *MPretval)
-{
-    int MP1[MP_SIZE];
- 
-    mpmul(MPx, MPx, MP1);
-    mp_add_integer(MP1, 1, MP1);
-    mpsqrt(MP1, MP1);
-    mp_add(MPx, MP1, MP1);
-    mpln(MP1, MPretval);
-}
-
-
-/*  MP precision hyperbolic arc tangent.
- *
- *  1. If (x <= -1.0 or x >= 1.0) then report a DOMAIn error and return 0.0.
- *
- *  2. atanh(x) = 0.5 * log((1 + x) / (1 - x))
- */
-
-static void
-mpatanh(int *MPx, int *MPretval)
-{
-    int MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE];
-    int MP3[MP_SIZE], MPn1[MP_SIZE];
-
-    mp_set_from_integer(0, MP0);
-    mp_set_from_integer(1, MP1);
-    mp_set_from_integer(-1, MPn1);
-
-    if (mp_is_greater_equal(MPx, MP1) || mp_is_less_equal(MPx, MPn1)) {
-        doerr(_("Error"));
-        mp_set_from_mp(MP0, MPretval);
-    } else {
-        mp_add(MP1, MPx, MP2);
-        mp_subtract(MP1, MPx, MP3);
-        mpdiv(MP2, MP3, MP3);
-        mpln(MP3, MP3);
-        MPstr_to_num("0.5", DEC, MP1);
-        mpmul(MP1, MP3, MPretval);
-    }
-}
-
-
 /*  MP precision common log.
  *
  *  1. log10(x) = log10(e) * log(x)
@@ -619,7 +452,7 @@
     mppwr(MP1base, v->accuracy, MP1);
     /* FIXME: string const. if MPstr_to_num can get it */
     SNPRINTF(half, MAXLINE, "0.5");
-    MPstr_to_num(half, DEC, MP2);
+    MPstr_to_num(half, 10, MP2);
     mpdiv(MP2, MP1, MP1);
     mp_add(MPval, MP1, MPval);
 
@@ -742,7 +575,7 @@
     }
  
     SNPRINTF(half, MAXLINE, "0.5");
-    MPstr_to_num(half, DEC, MP1);
+    MPstr_to_num(half, 10, MP1);
     mp_add_integer(MP1, exp, MPval);
     mp_set_from_integer(1, MP1);
     for (ddig = 0; mp_is_greater_equal(MPval, MP1); ddig++) {
@@ -795,124 +628,6 @@
     }
 }
 
-
-static int
-char_val(char chr)
-{
-    if (chr >= '0' && chr <= '9') {
-        return(chr - '0');
-    } else if (chr >= 'a' && chr <= 'f') {
-        return(chr - 'a' + 10);
-    } else if (chr >= 'A' && chr <= 'F') {
-        return(chr - 'A' + 10);
-    } else {
-        return(-1);
-    }
-}
-
-
-/* Convert string into an MP number, in the given base
- */
-
-void
-MPstr_to_num(const char *str, enum base_type base, int *MPval)
-{
-    const char *optr;
-    int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE];
-    int i, inum;
-    int exp      = 0;
-    int exp_sign = 1;
-    int negate = 0;
-
-    mp_set_from_integer(0, MPval);
-    mp_set_from_integer(basevals[(int) base], MPbase);
-
-    optr = str;
-
-    /* Remove any initial spaces or tabs. */
-    while (*optr == ' ' || *optr == '\t') {
-        optr++;
-    }
-
-    /* Check if this is a negative number. */
-    if (*optr == '-') {
-        negate = 1;
-        optr++;
-    }
-
-    while ((inum = char_val(*optr)) >= 0) {
-        mpmul(MPval, MPbase, MPval);
-        mp_add_integer(MPval, inum, MPval);
-        optr++;
-    }
-
-    if (*optr == '.' || *optr == *v->radix) {
-        optr++;
-        for (i = 1; (inum = char_val(*optr)) >= 0; i++) {
-            mppwr(MPbase, i, MP1);
-            mp_set_from_integer(inum, MP2);
-            mpdiv(MP2, MP1, MP1);
-            mp_add(MPval, MP1, MPval);
-        optr++;
-        }
-    }
-
-    while (*optr == ' ') {
-        optr++;
-    }
- 
-    if (*optr != '\0') {
-        if (*optr == '-') {
-            exp_sign = -1;
-        }
- 
-        while ((inum = char_val(*++optr)) >= 0) {
-            exp = exp * basevals[(int) base] + inum;
-        }
-    }
-    exp *= exp_sign;
-
-    if (negate == 1) {
-        mp_invert_sign(MPval, MPval);
-    }
-}
-
-
-void
-mp_set_from_string(const char *number, int t[MP_SIZE])
-{
-    int i;
-    char *a = NULL;
-    char *b = NULL;
-
-    int MP_a[MP_SIZE];
-    int MP_b[MP_SIZE];
-
-    assert(number);
-    a = strdup(number);
-    assert(a);
-
-    for (i = 0; !((a[i] == 'e') || (a[i] == 'E')); i++) {
-        assert(a[i]);
-    }
-
-    a[i] = 0;
-    b = &a[i+2];
-
-    MPstr_to_num(a, v->base, MP_a);
-    MPstr_to_num(b, v->base, MP_b);
-    if (a[i+1] == '-') {
-        int MP_c[MP_SIZE];
-        mp_invert_sign(MP_b, MP_c);
-        calc_xtimestenpowx(MP_a, MP_c, t);
-    } else {
-        calc_xtimestenpowx(MP_a, MP_b, t);
-    }
-
-    free(a);
-}
-
-
 /* Calculate the factorial of MPval. */
 void
 calc_factorial(int *MPval, int *MPres)

Modified: trunk/gcalctool/mpmath.h
==============================================================================
--- trunk/gcalctool/mpmath.h	(original)
+++ trunk/gcalctool/mpmath.h	Wed Oct  8 02:36:11 2008
@@ -49,10 +49,8 @@
 void calc_u16(const int s1[MP_SIZE], int t1[MP_SIZE]);
 void calc_percent(int s1[MP_SIZE], int t1[MP_SIZE]);
 void calc_inv(const int s1[MP_SIZE], int t1[MP_SIZE]);
-void calc_tenpowx(int s1[MP_SIZE], int t1[MP_SIZE]);
 void calc_xpowy(int MPx[MP_SIZE], int MPy[MP_SIZE], int MPres[MP_SIZE]);
 void do_e(int t1[MP_SIZE]);
-void calc_xtimestenpowx(int s1[MP_SIZE], int s2[MP_SIZE], int t1[MP_SIZE]);
 int calc_modulus(int op1[MP_SIZE], int op2[MP_SIZE], int result[MP_SIZE]);
 void calc_shift(int s[MP_SIZE], int t[MP_SIZE], int times);
 void calc_epowy(int s[MP_SIZE], int t[MP_SIZE]);
@@ -69,8 +67,6 @@
 is_natural(int MPnum[MP_SIZE]);
 
 // FIXME: These should be merged together
-void MPstr_to_num(const char *, enum base_type, int *);
-void mp_set_from_string(const char *number, int t[MP_SIZE]);
 void make_fixed(char *, int, int *, int, int, int);
 void make_number(char *, int, int *, int, int);
 



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