components/gnome/gnome-calculator/patches/01-no-mpfr.patch
changeset 7956 4f61047bec23
parent 7955 e2e23e69f5e7
child 7957 39baccd8f6e8
--- a/components/gnome/gnome-calculator/patches/01-no-mpfr.patch	Thu Apr 13 17:10:44 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3543 +0,0 @@
-A new version of mpfr is expected which isn't in Solaris yet, so we
-are removing that functionality till we can get mpfr updated and
-then will revert back these changes.
-
-Not suitable for upstream
-
---- a/data/org.gnome.calculator.gschema.xml	Fri Jan 29 15:39:20 2016
-+++ b/data/org.gnome.calculator.gschema.xml	Fri Jan 29 15:40:20 2016
-@@ -22,6 +22,7 @@
-   <schema path="/org/gnome/calculator/" id="org.gnome.calculator" gettext-domain="calculator">
-     <key type="i" name="accuracy">
-       <default>9</default>
-+      <range min="0" max="9"/>
-       <summary>Accuracy value</summary>
-       <description>The number of digits displayed after the numeric point</description>
-     </key>
-@@ -82,10 +83,5 @@
-       <summary>Target units</summary>
-       <description>Units to convert the current calculation into</description>
-     </key>
--    <key type="i" name="precision">
--      <default>2000</default>
--      <summary>Internal precision</summary>
--      <description>The internal precision used with the MPFR library</description>
--    </key>
-   </schema>
- </schemalist>
---- a/src/Makefile.am	Fri Jan 29 15:40:46 2016
-+++ b/src/Makefile.am	Fri Jan 29 15:41:34 2016
-@@ -33,8 +33,7 @@
- 	--pkg gtk+-3.0 \
- 	--pkg gtksourceview-3.0 \
- 	--pkg libxml-2.0 \
--	$(top_builddir)/lib/libcalculator.vapi \
--	$(top_builddir)/lib/mpfr.vapi
-+	$(top_builddir)/lib/libcalculator.vapi
- 
- gnome_calculator_CPPFLAGS = \
- 	$(AM_CPPFLAGS) \
-@@ -54,8 +53,7 @@
- 	--pkg gio-2.0 \
- 	--pkg gtksourceview-3.0 \
- 	--pkg libxml-2.0 \
--	$(top_builddir)/lib/libcalculator.vapi \
--	$(top_builddir)/lib/mpfr.vapi
-+	$(top_builddir)/lib/libcalculator.vapi
- 
- gcalccmd_LDADD = \
- 	$(top_builddir)/lib/libcalculator.la
---- a/lib/Makefile.am	Fri Jan 29 15:42:13 2016
-+++ b/lib/Makefile.am	Fri Jan 29 15:42:24 2016
-@@ -10,7 +10,6 @@
- 
- libcalculator_la_SOURCES = \
- 	config.vapi \
--	mpfr.vapi \
- 	currency.vala \
- 	equation.vala \
- 	equation-lexer.vala \
-@@ -37,8 +36,7 @@
- libcalculator_la_LIBADD = \
- 	$(LIBCALCULATOR_LIBS) \
- 	-lgmp \
--	-lm \
--	-lmpfr
-+	-lm
- 
- EXTRA_DIST = \
- 	libcalculator.h \
---- a/lib/equation-parser.vala	Fri Jan 29 15:47:35 2016
-+++ b/lib/equation-parser.vala	Fri Jan 29 16:00:51 2016
-@@ -78,20 +78,8 @@
-         var r = right.solve ();
-         if (r == null)
-             return null;
--        var z = solve_r (r);
-+        return solve_r (r);
- 
--        /* check for errors */
--        Number.check_flags ();
--        if (Number.error != null)
--        {
--            var tmpleft = right;
--            var tmpright = right;
--            while (tmpleft.left != null) tmpleft = tmpleft.left;
--            while (tmpright.right != null) tmpright = tmpright.right;
--            parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--            Number.error = null;
--        }
--        return z;
-     }
- 
-     public abstract Number solve_r (Number r);
-@@ -110,20 +98,7 @@
-         var r = right.solve ();
-         if (l == null || r == null)
-             return null;
--        var z = solve_lr (l, r);
--
--        /* check for errors */
--        Number.check_flags ();
--        if (Number.error != null)
--        {
--            var tmpleft = left;
--            var tmpright = right;
--            while (tmpleft.left != null) tmpleft = tmpleft.left;
--            while (tmpright.right != null) tmpright = tmpright.right;
--            parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--            Number.error = null;
--        }
--        return z;
-+        return solve_lr (l, r);
-     }
- 
-     public abstract Number solve_lr (Number left, Number r);
-@@ -261,18 +236,6 @@
-             value = value.multiply (t);
-         }
- 
--        /* check for errors */
--        Number.check_flags ();
--        if (Number.error != null)
--        {
--            var tmpleft = left;
--            var tmpright = right;
--            while (tmpleft.left != null) tmpleft = tmpleft.left;
--            while (tmpright.right != null) tmpright = tmpright.right;
--            parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--            Number.error = null;
--        }
--
-         return value;
-     }
- }
-@@ -392,14 +355,6 @@
-         if (tmp != null)
-             tmp = tmp.xpowy_integer (pow);
- 
--        /* check for errors */
--        Number.check_flags ();
--        if (Number.error != null)
--        {
--            parser.set_error (ErrorCode.MP, Number.error);
--            Number.error = null;
--        }
--
-         return tmp;
-     }
- }
-@@ -574,17 +529,7 @@
- 
-     public override Number solve_lr (Number l, Number r)
-     {
--        var z = l.divide (r);
--        if (Number.error != null)
--        {
--            var tmpleft = right;
--            var tmpright = right;
--            while (tmpleft.left != null) tmpleft = tmpleft.left;
--            while (tmpright.right != null) tmpright = tmpright.right;
--            parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--            Number.error = null;
--        }
--        return z;
-+        return l.divide (r);
-     }
- }
- 
-@@ -604,21 +549,8 @@
-             var mod = right.solve ();
-             if (base_value == null || exponent == null || mod == null)
-                 return null;
--            var z = base_value.modular_exponentiation (exponent, mod);
-+            return base_value.modular_exponentiation (exponent, mod);
- 
--            /* check for errors */
--            Number.check_flags ();
--            if (Number.error != null)
--            {
--                var tmpleft = left;
--                var tmpright = right;
--                while (tmpleft.left != null) tmpleft = tmpleft.left;
--                while (tmpright.right != null) tmpright = tmpright.right;
--                parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--                Number.error = null;
--            }
--
--            return z;
-         }
-         else
-         {
-@@ -626,21 +558,8 @@
-             var r = right.solve ();
-             if (l == null || r == null)
-                 return null;
--            var z = solve_lr (l, r);
-+            return solve_lr (l, r);
- 
--            /* check for errors */
--            Number.check_flags ();
--            if (Number.error != null)
--            {
--                var tmpleft = left;
--                var tmpright = right;
--                while (tmpleft.left != null) tmpleft = tmpleft.left;
--                while (tmpright.right != null) tmpright = tmpright.right;
--                parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--                Number.error = null;
--            }
--
--            return z;
-         }
-     }
- 
-@@ -709,21 +628,8 @@
-         if (val == null)
-             return null;
- 
--        var z = val.xpowy_integer (pow);
-+        return val.xpowy_integer (pow);
- 
--        /* check for errors */
--        Number.check_flags ();
--        if (Number.error != null)
--        {
--            var tmpleft = left;
--            var tmpright = right;
--            while (tmpleft.left != null) tmpleft = tmpleft.left;
--            while (tmpright.right != null) tmpright = tmpright.right;
--            parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index, tmpright.token.end_index);
--            Number.error = null;
--        }
--
--        return z;
-     }
- }
- 
-@@ -1036,10 +942,10 @@
-         }
- 
-         representation_base = this.representation_base;
--        error_code = this.error;
--        error_token = this.error_token;
--        error_start = this.error_token_start;
--        error_end = this.error_token_end;
-+        error_code = ErrorCode.NONE; 
-+        error_token = null;
-+        error_start = 0;
-+        error_end = 0;
-         return ans;
-     }
- 
---- a/lib/equation.vala	Fri Jan 29 16:01:11 2016
-+++ b/lib/equation.vala	Fri Jan 29 16:02:09 2016
-@@ -117,17 +117,15 @@
-     public new Number? parse (out uint representation_base = null, out ErrorCode error_code = null, out string? error_token = null, out uint? error_start = null, out uint? error_end = null)
-     {
-         var parser = new EquationParser (this, expression);
--        Number.error = null;
-+        mp_clear_error();
- 
-         var z = parser.parse (out representation_base, out error_code, out error_token, out error_start, out error_end);
- 
-         /* Error during parsing */
-         if (error_code != ErrorCode.NONE)
--        {
-             return null;
--        }
- 
--        if (Number.error != null)
-+        if (mp_get_error() != null)
-         {
-             error_code = ErrorCode.MP;
-             return null;
---- a/src/gnome-calculator.vala	Fri Jan 29 16:05:17 2016
-+++ b/src/gnome-calculator.vala	Fri Jan 29 16:06:27 2016
-@@ -56,7 +56,6 @@
-         var target_currency = settings.get_string ("target-currency");
-         var source_units = settings.get_string ("source-units");
-         var target_units = settings.get_string ("target-units");
--        var precision = settings.get_int ("precision");
- 
-         var equation = new MathEquation ();
-         equation.accuracy = accuracy;
-@@ -69,7 +68,6 @@
-         equation.target_currency = target_currency;
-         equation.source_units = source_units;
-         equation.target_units = target_units;
--        Number.precision = precision;
- 
-         add_action_entries (app_entries, this);
- 
-@@ -173,7 +171,7 @@
-             }
-             else if (error == ErrorCode.MP)
-             {
--                stderr.printf ("Error: %s\n", Number.error);
-+                stderr.printf ("Error: %s\n", mp_get_error());
-                 return Posix.EXIT_FAILURE;
-             }
-             else
---- a/src/gcalccmd.vala	Fri Jan 29 16:03:42 2016
-+++ b/src/gcalccmd.vala	Fri Jan 29 16:04:56 2016
-@@ -34,18 +34,9 @@
- 
-     result_serializer.set_representation_base (representation_base);
-     if (z != null)
--    {
--        var str = result_serializer.to_string (z);
--        if (result_serializer.error != null)
--        {
--            stderr.printf ("%s\n", result_serializer.error);
--            result_serializer.error = null;
--        }
--        else
--            stdout.printf ("%s\n", str);
--    }
-+	stdout.printf ("%s\n", result_serializer.to_string (z));
-     else if (ret == ErrorCode.MP)
--        stderr.printf ("Error %s\n", Number.error);
-+        stderr.printf ("Error %s\n", mp_get_error());
-     else
-         stderr.printf ("Error %d\n", ret);
- }
---- a/lib/math-equation.vala	Fri Jan 29 16:33:36 2016
-+++ b/lib/math-equation.vala	Fri Jan 29 16:39:56 2016
-@@ -786,11 +786,6 @@
-         ans_end_mark = create_mark (null, end, true);
-         apply_tag (ans_tag, start, end);
- 
--        if (serializer.error != null)
--        {
--            status = serializer.error;
--            serializer.error = null;
--        }
-     }
- 
-     public new void insert (string text)
-@@ -964,13 +959,11 @@
-                 break;
- 
-             case ErrorCode.MP:
--                if (Number.error != null) // LEGACY, should never be run
-+		if (mp_get_error () != null)
-+		    solvedata.error = mp_get_error ();
-+		else if (error_token != null)
-                 {
--                    solvedata.error = Number.error;
--                }
--                else if (error_token != null) // should always be run
--                {
--                    solvedata.error = _("%s").printf (error_token);
-+                    solvedata.error = _("Malformed expression at token '%s'").printf(error_token);
-                     solvedata.error_start = error_start;
-                     solvedata.error_end = error_end;
-                 }
-@@ -1015,8 +1008,6 @@
- 
-             /* Fix thousand separator offsets in the start and end offsets of error token. */
-             error_token_fix_thousands_separator ();
--            /* Fix missing Parenthesis before the start and after the end offsets of error token */
--            error_token_fix_parenthesis ();
- 
-             /* Notify the GUI about the change in error token locations. */
-             notify_property ("error-token-end");
-@@ -1087,70 +1078,6 @@
-             end.forward_chars (length);
-         }
-     }
--
--    /* Fix the offsets to consider starting  and ending parenthesis */
--    private void error_token_fix_parenthesis ()
--    {
--        unichar c;
--        int count = 0;
--        int real_end = display.index_of_nth_char (error_token_end);
--        int real_start = display.index_of_nth_char (error_token_start);
--
--        /* checks if there are more opening/closing parenthesis than closing/opening parenthesis */
--        for (int i = real_start; display.get_next_char (ref i, out c) && i <= real_end;)
--        {
--            if (c.to_string () == "(") count++;
--            if (c.to_string () == ")") count--;
--        }
--
--        /* if there are more opening than closing parenthesis and there are closing parenthesis
--           after the end offset, include those in the offsets */
--        for (int i = real_end; display.get_next_char (ref i, out c) && count > 0;)
--        {
--            if (c.to_string () == ")")
--            {
--                state.error_token_end++;
--                count--;
--            }
--            else
--            {
--                break;
--            }
--        }
--
--        /* the same for closing parenthesis */
--        for (int i = real_start; display.get_prev_char (ref i, out c) && count < 0;)
--        {
--            if (c.to_string () == "(")
--            {
--                state.error_token_start--;
--                count++;
--            }
--            else
--            {
--                break;
--            }
--        }
--
--        real_end = display.index_of_nth_char (error_token_end);
--        real_start = display.index_of_nth_char (error_token_start);
--
--        unichar d;
--
--        /* if there are opening parenthesis directly before aswell as closing parenthesis directly after the offsets, include those aswell */
--        while (display.get_next_char (ref real_end, out d) && display.get_prev_char (ref real_start, out c))
--        {
--            if (c.to_string () == "(" && d.to_string () == ")")
--            {
--                state.error_token_start--;
--                state.error_token_end++;
--            }
--            else
--            {
--                break;
--            }
--        }
--    }
- 
-     private void* factorize_real ()
-     {
---- a/src/math-preferences.vala	Fri Jan 29 16:40:37 2016
-+++ b/src/math-preferences.vala	Fri Jan 29 16:43:30 2016
-@@ -90,7 +90,7 @@
-         var string = _("Show %d decimal _places");
-         var tokens = string.split ("%d", 2);
- 
--        var decimal_places_adjustment = new Gtk.Adjustment (0.0, 0.0, 100.0, 1.0, 1.0, 0.0);
-+        var decimal_places_adjustment = new Gtk.Adjustment (0.0, 0.0, 9.0, 1.0, 1.0, 0.0);
-         decimal_places_spin = new Gtk.SpinButton (decimal_places_adjustment, 0.0, 0);
- 
-         if (tokens.length > 0)
---- a/lib/serializer.vala	Mon Feb  1 10:45:23 2016
-+++ b/lib/serializer.vala	Mon Feb  1 10:46:37 2016
-@@ -32,9 +32,6 @@
-     private unichar tsep;            /* Locale specific thousands separator. */
-     private int tsep_count;          /* Number of digits between separator. */
- 
--    /* is set when an error (for example precision error while converting) occurs */
--    public string? error { get; set; default = null; }
--
-     public Serializer (DisplayFormat format, int number_base, int trailing_digits)
-     {
-         var radix_string = Posix.nl_langinfo (Posix.NLItem.RADIXCHAR);
-@@ -322,17 +319,8 @@
- 
-             var d = t3.to_integer ();
- 
--            if (d < 16 && d >= 0)
--            {
--                string.prepend_c (digits[d]);
--            }
--            else
--            {
--                string.prepend_c ('?');
--                error = _("Precision error");
--                string.assign ("0");
--                break;
--            }
-+            string.prepend_c (d < 16 ? digits[d] : '?');
-+
-             n_digits++;
- 
-             temp = t;
---- a/tests/test-number.vala	Mon Feb  1 10:48:08 2016
-+++ b/tests/test-number.vala	Mon Feb  1 10:49:35 2016
-@@ -72,6 +72,22 @@
-     pass ();
- }
- 
-+private void test_float ()
-+{
-+    for (var a = -10.0f; a <= 10.0f; a += 0.5f)
-+    {
-+        var z = new Number.float (a);
-+        if (z.to_float () != a)
-+        {
-+            fail ("Number.float (%f).to_float () -> %f, expected %f".printf (a, z.to_float (), a));
-+            return;
-+        }
-+    }
-+
-+    pass ();
-+}
-+
-+
- private void test_double ()
- {
-     for (var a = -10.0; a <= 10.0; a += 0.5)
-@@ -1074,6 +1090,7 @@
-     test_integer ();
-     test_unsigned_integer ();
-     test_fraction ();
-+    test_float ();
-     test_double ();
-     test_complex ();
-     test_polar ();
---- a/tests/test-equation.c	Mon Feb  1 12:22:33 2016
-+++ b/tests/test-equation.c	Mon Feb  1 12:22:47 2016
-@@ -95,7 +95,7 @@
- 		const gchar* _tmp1_ = NULL;
- 		const gchar* _tmp2_ = NULL;
- 		gchar* _tmp3_ = NULL;
--		_tmp1_ = number_get_error ();
-+		_tmp1_ = mp_get_error ();
- 		_tmp2_ = _tmp1_;
- 		_tmp3_ = g_strdup_printf ("ErrorCode.MP(\"%s\")", _tmp2_);
- 		result = _tmp3_;
-
---- a/lib/number.vala	Fri Jan 29 16:44:36 2016
-+++ b/lib/number.vala	Mon Feb  1 12:02:40 2016
-@@ -27,8 +27,15 @@
-  *  THE MP USERS GUIDE.
-  */
- 
--using MPFR;
- 
-+/* Size of the multiple precision values */
-+private const int SIZE = 1000;
-+
-+/* Base for numbers */
-+private const int BASE = 10000;
-+
-+private const int T = 100;
-+
- private delegate int BitwiseFunc (int v1, int v2);
- 
- public enum AngleUnit
-@@ -41,37 +48,69 @@
- /* Object for a high precision floating point number representation */
- public class Number : Object
- {
--    /* real and imaginary part of a Number */
--    private MPFloat re_num { get; set; }
--    private MPFloat im_num { get; set; }
-+    /* Sign (+1, -1) or 0 for the value zero */
-+    public int re_sign;
-+    public int im_sign;
- 
--    public static ulong precision { get; set; default = 1000; }
-+    /* Exponent (to base BASE) */
-+    public int re_exponent;
-+    public int im_exponent;
- 
--    /* Stores the error msg if an error occurs during calculation. Otherwise should be null */
--    public static string? error { get; set; default = null; }
-+    /* Normalized fraction */
-+    public int re_fraction[1000]; // SIZE
-+    public int im_fraction[1000]; // SIZE
- 
-     public Number.integer (int64 value)
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_signed_integer ((long)value, Round.NEAREST);
--        re_num = tmp;
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp2;
-+        if (value < 0)
-+        {
-+            value = -value;
-+            re_sign = -1;
-+        }
-+        else if (value > 0)
-+            re_sign = 1;
-+        else
-+            re_sign = 0;
-+
-+        while (value != 0)
-+        {
-+            re_fraction[re_exponent] = (int) (value % BASE);
-+            re_exponent++;
-+            value /= BASE;
-+        }
-+        for (var i = 0; i < re_exponent / 2; i++)
-+        {
-+            int t = re_fraction[i];
-+            re_fraction[i] = re_fraction[re_exponent - i - 1];
-+            re_fraction[re_exponent - i - 1] = t;
-+        }
-     }
- 
-     public Number.unsigned_integer (uint64 x)
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer ((ulong)x, Round.NEAREST);
--        re_num = tmp;
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp2;
-+        if (x == 0)
-+            re_sign = 0;
-+        else
-+            re_sign = 1;
-+
-+        while (x != 0)
-+        {
-+            re_fraction[re_exponent] = (int) (x % BASE);
-+            x = x / BASE;
-+            re_exponent++;
-+        }
-+        for (var i = 0; i < re_exponent / 2; i++)
-+        {
-+            int t = re_fraction[i];
-+            re_fraction[i] = re_fraction[re_exponent - i - 1];
-+            re_fraction[re_exponent - i - 1] = t;
-+        }
-     }
- 
-     public Number.fraction (int64 numerator, int64 denominator)
-     {
-+        mp_gcd (ref numerator, ref denominator);
-+
-         if (denominator < 0)
-         {
-             numerator = -numerator;
-@@ -81,39 +120,203 @@
-         Number.integer (numerator);
-         if (denominator != 1)
-         {
--            var tmp = re_num;
--            tmp.divide_signed_integer (re_num, (long) denominator, Round.NEAREST);
--            re_num = tmp;
-+            var z = divide_integer (denominator);
-+            re_sign = z.re_sign;
-+            im_sign = z.im_sign;
-+            re_exponent = z.re_exponent;
-+            im_exponent = z.im_exponent;
-+            for (var i = 0; i < z.re_fraction.length; i++)
-+            {
-+                re_fraction[i] = z.re_fraction[i];
-+                im_fraction[i] = z.im_fraction[i];
-+            }
-         }
-     }
- 
--    /* Helper constructor. Creates new Number from already existing MPFloat. */
--    public Number.mpfloat (MPFloat value)
-+    public Number.float (float value)
-     {
--        re_num = value;
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp;
-+        var z = new Number.integer (0);
-+
-+        if (value != 0)
-+        {
-+            /* CHECK SIGN */
-+            var rj = 0f;
-+            if (value < 0.0f)
-+            {
-+                z.re_sign = -1;
-+                rj = -value;
-+            }
-+            else if (value > 0.0f)
-+            {
-+                z.re_sign = 1;
-+                rj = value;
-+            }
-+
-+            /* INCREASE IE AND DIVIDE RJ BY 16. */
-+            var ie = 0;
-+            while (rj >= 1.0f)
-+            {
-+                ie++;
-+                rj *= 0.0625f;
-+            }
-+            while (rj < 0.0625f)
-+            {
-+                ie--;
-+                rj *= 16.0f;
-+            }
-+
-+            /*  NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
-+             *  SET re_exponent TO 0
-+             */
-+            z.re_exponent = 0;
-+
-+            /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
-+            for (var i = 0; i < T + 4; i++)
-+            {
-+                rj *= BASE;
-+                z.re_fraction[i] = (int) rj;
-+                rj -= z.re_fraction[i];
-+            }
-+
-+            /* NORMALIZE RESULT */
-+            mp_normalize (ref z);
-+
-+            /* Computing MAX */
-+            var ib = int.max (BASE * 7 * BASE, 32767) / 16;
-+            var tp = 1;
-+
-+            /* NOW MULTIPLY BY 16**IE */
-+            if (ie < 0)
-+            {
-+                var k = -ie;
-+                for (var i = 1; i <= k; i++)
-+                {
-+                    tp <<= 4;
-+                    if (tp <= ib && tp != BASE && i < k)
-+                        continue;
-+                    z = z.divide_integer (tp);
-+                    tp = 1;
-+                }
-+            }
-+            else if (ie > 0)
-+            {
-+                for (var i = 1; i <= ie; i++)
-+                {
-+                    tp <<= 4;
-+                    if (tp <= ib && tp != BASE && i < ie)
-+                        continue;
-+                    z = z.multiply_integer (tp);
-+                    tp = 1;
-+                }
-+            }
-+        }
-+
-+        re_sign = z.re_sign;
-+        im_sign = z.im_sign;
-+        re_exponent = z.re_exponent;
-+        im_exponent = z.im_exponent;
-+        for (var i = 0; i < z.re_fraction.length; i++)
-+        {
-+            re_fraction[i] = z.re_fraction[i];
-+            im_fraction[i] = z.im_fraction[i];
-+        }
-     }
- 
-     public Number.double (double value)
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_double (value, Round.NEAREST);
--        re_num = tmp;
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp2;
-+        var z = new Number.integer (0);
-+
-+        if (value != 0)
-+        {
-+            /* CHECK SIGN */
-+            var dj = 0.0;
-+            if (value < 0.0)
-+            {
-+                z.re_sign = -1;
-+                dj = -value;
-+            }
-+            else if (value > 0.0)
-+            {
-+                z.re_sign = 1;
-+                dj = value;
-+            }
-+
-+            /* INCREASE IE AND DIVIDE DJ BY 16. */
-+            var ie = 0;
-+            for (ie = 0; dj >= 1.0; ie++)
-+                dj *= 1.0/16.0;
-+
-+            for ( ; dj < 1.0/16.0; ie--)
-+                dj *= 16.0;
-+
-+            /*  NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
-+             *  SET re_exponent TO 0
-+             */
-+            z.re_exponent = 0;
-+
-+            /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
-+            for (var i = 0; i < T + 4; i++)
-+            {
-+                dj *= (double) BASE;
-+                z.re_fraction[i] = (int) dj;
-+                dj -= (double) z.re_fraction[i];
-+            }
-+
-+            /* NORMALIZE RESULT */
-+            mp_normalize (ref z);
-+
-+            /* Computing MAX */
-+            var ib = int.max (BASE * 7 * BASE, 32767) / 16;
-+            var tp = 1;
-+
-+            /* NOW MULTIPLY BY 16**IE */
-+            if (ie < 0)
-+            {
-+                var k = -ie;
-+                for (var i = 1; i <= k; ++i)
-+                {
-+                    tp <<= 4;
-+                    if (tp <= ib && tp != BASE && i < k)
-+                        continue;
-+                    z = z.divide_integer (tp);
-+                    tp = 1;
-+                }
-+            }
-+            else if (ie > 0)
-+            {
-+                for (var i = 1; i <= ie; ++i)
-+                {
-+                    tp <<= 4;
-+                    if (tp <= ib && tp != BASE && i < ie)
-+                        continue;
-+                    z = z.multiply_integer (tp);
-+                    tp = 1;
-+                }
-+            }
-+        }
-+
-+        re_sign = z.re_sign;
-+        im_sign = z.im_sign;
-+        re_exponent = z.re_exponent;
-+        im_exponent = z.im_exponent;
-+        for (var i = 0; i < z.re_fraction.length; i++)
-+        {
-+            re_fraction[i] = z.re_fraction[i];
-+            im_fraction[i] = z.im_fraction[i];
-+        }
-     }
- 
-     public Number.complex (Number x, Number y)
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.@set (x.re_num, Round.NEAREST);
--        re_num = tmp;
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.@set (y.re_num, Round.NEAREST);
--        im_num = tmp2;
-+        re_sign = x.re_sign;
-+        re_exponent = x.re_exponent;
-+        for (var i = 0; i < im_fraction.length; i++)
-+            re_fraction[i] = x.re_fraction[i];
-+
-+        im_sign = y.re_sign;
-+        im_exponent = y.re_exponent;
-+        for (var i = 0; i < im_fraction.length; i++)
-+            im_fraction[i] = y.re_fraction[i];
-     }
- 
-     public Number.polar (Number r, Number theta, AngleUnit unit = AngleUnit.RADIANS)
-@@ -125,35 +328,28 @@
- 
-     public Number.eulers ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.set_unsigned_integer (1, Round.NEAREST);
--        /* e^1, since mpfr doesn't have a function to return e */
--        tmp.exp (tmp2, Round.NEAREST);
--        re_num = tmp;
--        var tmp3 = MPFloat.init2 ((Precision) precision);
--        tmp3.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp3;
-+        var z = new Number.integer (1).epowy ();
-+        re_sign = z.re_sign;
-+        im_sign = z.im_sign;
-+        re_exponent = z.re_exponent;
-+        im_exponent = z.im_exponent;
-+        for (var i = 0; i < z.re_fraction.length; i++)
-+        {
-+            re_fraction[i] = z.re_fraction[i];
-+            im_fraction[i] = z.im_fraction[i];
-+        }
-     }
- 
-     public Number.i ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer (0, Round.NEAREST);
--        tmp2.set_unsigned_integer (1, Round.NEAREST);
--        re_num = tmp;
--        im_num = tmp2;
-+        im_sign = 1;
-+        im_exponent = 1;
-+        im_fraction[0] = 1;
-     }
- 
-     public Number.pi ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.const_pi (Round.NEAREST);
--        re_num = tmp;
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp2.set_unsigned_integer (0, Round.NEAREST);
--        im_num = tmp2;
-+        Number.double (Math.PI);
-     }
- 
-     /* Sets z to be a uniform random number in the range [0, 1] */
-@@ -162,42 +358,123 @@
-         Number.double (Random.next_double ());
-     }
- 
--    ~Number ()
--    {
--        re_num.clear ();
--        im_num.clear ();
--    }
--
-     public int64 to_integer ()
-     {
--        return re_num.get_signed_integer (Round.NEAREST);
-+        int64 z = 0;
-+
-+        /* |x| <= 1 */
-+        if (re_sign == 0 || re_exponent <= 0)
-+            return 0;
-+
-+        /* Multiply digits together */
-+        for (var i = 0; i < re_exponent; i++)
-+        {
-+            var t = z;
-+            z = z * BASE + re_fraction[i];
-+
-+            /* Check for overflow */
-+            if (z <= t)
-+                return 0;
-+        }
-+
-+        /* Validate result */
-+        var v = z;
-+        for (var i = re_exponent - 1; i >= 0; i--)
-+        {
-+            /* Get last digit */
-+            var digit = v - (v / BASE) * BASE;
-+            if (re_fraction[i] != digit)
-+                return 0;
-+
-+            v /= BASE;
-+        }
-+        if (v != 0)
-+            return 0;
-+
-+        return re_sign * z;
-     }
- 
-     public uint64 to_unsigned_integer ()
-     {
--        return re_num.get_unsigned_integer (Round.NEAREST);
-+        /* x <= 1 */
-+        if (re_sign <= 0 || re_exponent <= 0)
-+            return 0;
-+
-+        /* Multiply digits together */
-+        uint64 z = 0;
-+        for (var i = 0; i < re_exponent; i++)
-+        {
-+            var t = z;
-+            z = z * BASE + re_fraction[i];
-+
-+            /* Check for overflow */
-+            if (z <= t)
-+                return 0;
-+        }
-+
-+        /* Validate result */
-+        var v = z;
-+        for (var i = re_exponent - 1; i >= 0; i--)
-+        {
-+            /* Get last digit */
-+            var digit = (uint64) v - (v / BASE) * BASE;
-+            if (re_fraction[i] != digit)
-+                return 0;
-+
-+            v /= BASE;
-+        }
-+        if (v != 0)
-+            return 0;
-+
-+        return z;
-     }
- 
-     public float to_float ()
-     {
--        return re_num.get_float (Round.NEAREST);
-+        if (is_zero ())
-+            return 0f;
-+
-+        var z = 0f;
-+        for (var i = 0; i < T; i++)
-+        {
-+            if (re_fraction[i] != 0)
-+                z += re_fraction[i] * Math.powf (BASE, re_exponent - i - 1);
-+        }
-+
-+        if (re_sign < 0)
-+            return -z;
-+        else
-+            return z;
-     }
- 
-     public double to_double ()
-     {
--        return re_num.get_double (Round.NEAREST);
-+        if (is_zero ())
-+            return 0d;
-+
-+        var z = 0d;
-+        for (var i = 0; i < T; i++)
-+        {
-+            if (re_fraction[i] != 0)
-+                z += re_fraction[i] * Math.pow (BASE, re_exponent - i - 1);
-+        }
-+
-+        if (re_sign < 0)
-+            return -z;
-+        else
-+            return z;
-     }
- 
-     /* Return true if the value is x == 0 */
-     public bool is_zero ()
-     {
--        return re_num.is_zero () && im_num.is_zero ();
-+        return re_sign == 0 && im_sign == 0;
-     }
- 
-     /* Return true if x < 0 */
-     public bool is_negative ()
-     {
--        return re_num.sgn () < 0;
-+        return re_sign < 0;
-     }
- 
-     /* Return true if x is integer */
-@@ -205,8 +482,35 @@
-     {
-         if (is_complex ())
-             return false;
-+        /* Multiplication and division by 10000 is used to get around a
-+         * limitation to the "fix" for Sun bugtraq bug #4006391 in the
-+         * floor () routine in mp.c, when the re_exponent is less than 1.
-+         */
-+        var t3 = new Number.integer (10000);
-+        var t1 = multiply (t3);
-+        t1 = t1.divide (t3);
-+        var t2 = t1.floor ();
-+        return t1.equals (t2);
- 
--        return re_num.is_integer () != 0;
-+        /* Correct way to check for integer */
-+        /*
-+
-+        // Zero is an integer
-+        if (is_zero ())
-+            return true;
-+
-+        // fractional
-+        if (re_exponent <= 0)
-+            return false;
-+
-+        // Look for fractional components
-+        for (var i = re_exponent; i < SIZE; i++)
-+        {
-+            if (re_fraction[i] != 0)
-+                return false;
-+        }
-+
-+        return true;*/
-     }
- 
-     /* Return true if x is a positive integer */
-@@ -215,7 +519,7 @@
-         if (is_complex ())
-             return false;
-         else
--            return re_num.sgn () >= 0 && is_integer ();
-+            return re_sign >= 0 && is_integer ();
-     }
- 
-     /* Return true if x is a natural number (an integer ≥ 0) */
-@@ -224,34 +528,19 @@
-         if (is_complex ())
-             return false;
-         else
--            return re_num.sgn () > 0 && is_integer ();
-+            return re_sign > 0 && is_integer ();
-     }
- 
-     /* Return true if x has an imaginary component */
-     public bool is_complex ()
-     {
--        return !im_num.is_zero ();
-+        return im_sign != 0;
-     }
- 
--    /* Return error if overflow or underflow */
--    public static void check_flags ()
--    {
--        if (mpfr_is_underflow () != 0)
--        {
--            /* Translators: Error displayed when underflow error occured */
--            error = _("Underflow error");
--        }
--        else if (mpfr_is_overflow () != 0)
--        {
--            /* Translators: Error displayed when overflow error occured */
--            error = _("Overflow error");
--        }
--    }
--
-     /* Return true if x == y */
-     public bool equals (Number y)
-     {
--        return re_num.is_equal (y.re_num);
-+        return compare (y) == 0;
-     }
- 
-     /* Returns:
-@@ -261,25 +550,62 @@
-      */
-     public int compare (Number y)
-     {
--        return re_num.cmp (y.re_num);
-+        if (re_sign != y.re_sign)
-+        {
-+            if (re_sign > y.re_sign)
-+                return 1;
-+            else
-+                return -1;
-+        }
-+
-+        /* x = y = 0 */
-+        if (is_zero ())
-+            return 0;
-+
-+        /* See if numbers are of different magnitude */
-+        if (re_exponent != y.re_exponent)
-+        {
-+            if (re_exponent > y.re_exponent)
-+                return re_sign;
-+            else
-+                return -re_sign;
-+        }
-+
-+        /* Compare fractions */
-+        for (var i = 0; i < SIZE; i++)
-+        {
-+            if (re_fraction[i] == y.re_fraction[i])
-+                continue;
-+
-+            if (re_fraction[i] > y.re_fraction[i])
-+                return re_sign;
-+            else
-+                return -re_sign;
-+        }
-+
-+        /* x = y */
-+        return 0;
-     }
- 
-     /* Sets z = sgn (x) */
-     public Number sgn ()
-     {
--        var z = new Number.integer (re_num.sgn ());
--        return z;
-+        if (is_zero ())
-+            return new Number.integer (0);
-+        else if (is_negative ())
-+            return new Number.integer (-1);
-+        else
-+            return new Number.integer (1);
-     }
- 
-     /* Sets z = −x */
-     public Number invert_sign ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.neg (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        var tmp_im = z.im_num;
--        tmp_im.neg (im_num, Round.NEAREST);
--        z.im_num = tmp_im;
-+        var z = copy ();
-+
-+        z.re_sign = -z.re_sign;
-+        z.im_sign = -z.im_sign;
-+
-         return z;
-     }
- 
-@@ -294,13 +620,13 @@
-             x_real = x_real.multiply (x_real);
-             x_im = x_im.multiply (x_im);
-             var z = x_real.add (x_im);
--            return z.sqrt ();
-+            return z.root (2);
-         }
-         else
-         {
--            var tmp = MPFloat.init2 ((Precision) precision);
--            tmp.abs (re_num, Round.NEAREST);
--            var z = new Number.mpfloat (tmp);
-+            var z = copy ();
-+            if (z.re_sign < 0)
-+                z.re_sign = -z.re_sign;
-             return z;
-         }
-     }
-@@ -311,7 +637,7 @@
-         if (is_zero ())
-         {
-             /* Translators: Error display when attempting to take argument of zero */
--            error = _("Argument not defined for zero");
-+            mperr (_("Argument not defined for zero"));
-             return new Number.integer (0);
-         }
- 
-@@ -355,12 +681,8 @@
-     /* Sets z = ‾̅x */
-     public Number conjugate ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.neg (im_num, Round.NEAREST);
-         var z = copy ();
--        var tmp2 = z.im_num;
--        tmp2.clear ();
--        z.im_num = tmp;
-+        z.im_sign = -z.im_sign;
-         return z;
-     }
- 
-@@ -368,11 +690,13 @@
-     public Number real_component ()
-     {
-         var z = copy ();
--        var tmp = z.im_num;
--        tmp.clear ();
--        tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer (0, Round.NEAREST);
--        z.im_num = tmp;
-+
-+        /* Clear imaginary component */
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+
-         return z;
-     }
- 
-@@ -380,30 +704,65 @@
-     public Number imaginary_component ()
-     {
-         /* Copy imaginary component to real component */
--        var z = copy ();
--        var tmp = z.re_num;
--        tmp.clear ();
--        z.re_num = z.im_num;
--        tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer (0, Round.NEAREST);
--        z.im_num = tmp;
-+        var z = new Number ();
-+        z.re_sign = im_sign;
-+        z.re_exponent = im_exponent;
-+
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.re_fraction[i] = im_fraction[i];
-+
-+        /* Clear (old) imaginary component */
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+
-         return z;
-     }
- 
-     public Number integer_component ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.trunc (re_num);
--        var z = new Number.mpfloat (tmp);
-+        /* Clear re_fraction */
-+        var z = copy ();
-+        for (var i = z.re_exponent; i < SIZE; i++)
-+            z.re_fraction[i] = 0;
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+
-         return z;
-+
-     }
- 
-     /* Sets z = x mod 1 */
-     public Number fractional_component ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.frac (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-+       /* fractional component of zero is 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        /* All fractional */
-+        if (re_exponent <= 0)
-+            return this;
-+
-+        /* Shift fractional component */
-+        var shift = re_exponent;
-+        for (var i = shift; i < SIZE && re_fraction[i] == 0; i++)
-+            shift++;
-+        var z = new Number.integer (0);
-+        z.re_sign = re_sign;
-+        z.re_exponent = re_exponent - shift;
-+        for (var i = 0; i < SIZE; i++)
-+        {
-+            if (i + shift >= SIZE)
-+                z.re_fraction[i] = 0;
-+            else
-+                z.re_fraction[i] = re_fraction[i + shift];
-+        }
-+        if (z.re_fraction[0] == 0)
-+            z.re_sign = 0;
-+
-         return z;
-     }
- 
-@@ -416,9 +775,36 @@
-     /* Sets z = ⌊x⌋ */
-     public Number floor ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.floor (re_num);
--        var z = new Number.mpfloat (tmp);
-+        /* Integer component of zero = 0 */
-+        if (is_zero ())
-+            return this;
-+
-+        /* If all fractional then no integer component */
-+        if (re_exponent <= 0)
-+        {
-+            if (is_negative ())
-+                return new Number.integer (-1);
-+            else
-+                return new Number.integer (0);
-+        }
-+
-+        /* Clear fractional component */
-+        var z = copy ();
-+        var have_fraction = false;
-+        for (var i = z.re_exponent; i < SIZE; i++)
-+        {
-+            if (z.re_fraction[i] != 0)
-+                have_fraction = true;
-+            z.re_fraction[i] = 0;
-+        }
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+
-+        if (have_fraction && is_negative ())
-+            z = z.add (new Number.integer (-1));
-+
-         return z;
-     }
- 
-@@ -425,19 +811,29 @@
-     /* Sets z = ⌈x⌉ */
-     public Number ceiling ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.ceil (re_num);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        var z = floor ();
-+        var f = fractional_component ();
-+        if (f.is_zero ())
-+            return z;
-+        return z.add (new Number.integer (1));
-     }
- 
-     /* Sets z = [x] */
-     public Number round ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.round (re_num);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        var do_floor = !is_negative ();
-+
-+        var f = fractional_component ();
-+        f = f.multiply_integer (2);
-+        f = f.abs ();
-+        if (f.compare (new Number.integer (1)) >= 0)
-+            do_floor = !do_floor;
-+
-+        if (do_floor)
-+            return floor ();
-+        else
-+            return ceiling ();
-+
-     }
- 
-     /* Sets z = 1 ÷ x */
-@@ -482,24 +878,10 @@
-     /* Sets z = x^y */
-     public Number xpowy (Number y)
-     {
--        /* 0^-n invalid */
--        if (is_zero () && y.is_negative ())
-+        if (y.is_integer ())
-+            return xpowy_integer (y.to_integer ());
-+        else
-         {
--            /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
--            error = _("The power of zero is undefined for a negative exponent");
--            return new Number.integer (0);
--        }
--
--        /* 0^0 is indeterminate */
--        if (is_zero () && y.is_zero ())
--        {
--            /* Translators: Error displayed when attempted to raise 0 to power of zero */
--            error = _("Zero raised to zero is undefined");
--            return new Number.integer (0);
--        }
--
--        if (!y.is_integer ())
--        {
-             var reciprocal = y.reciprocal ();
-             if (reciprocal.is_integer ())
-                 return root (reciprocal.to_integer ());
-@@ -506,29 +888,6 @@
-             else
-                 return pwr (y);
-         }
--
--        Number t;
--        Number t2;
--        if (y.is_negative ())
--        {
--            t = reciprocal ();
--            t2 = y.invert_sign ();
--        }
--        else
--        {
--            t = this;
--            t2 = y;
--        }
--
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.power (t.re_num, t2.re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        var tmp2 = z.im_num;
--        tmp2.clear ();
--        tmp = MPFloat.init2 ((Precision) precision);
--        tmp.@set (t.im_num, Round.NEAREST);
--        z.im_num = tmp;
--        return z;
-     }
- 
-     /* Sets z = x^y */
-@@ -538,7 +897,7 @@
-         if (is_zero () && n < 0)
-         {
-             /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
--            error = _("The power of zero is undefined for a negative exponent");
-+            mperr (_("The power of zero is undefined for a negative exponent"));
-             return new Number.integer (0);
-         }
- 
-@@ -546,10 +905,22 @@
-         if (is_zero () && n == 0)
-         {
-             /* Translators: Error displayed when attempted to raise 0 to power of zero */
--            error = _("Zero raised to zero is undefined");
-+            mperr (_("Zero raised to zero is undefined"));
-             return new Number.integer (0);
-         }
- 
-+        /* x^0 = 1 */
-+        if (n == 0)
-+            return new Number.integer (1);
-+
-+        /* 0^n = 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        /* x^1 = x */
-+        if (n == 1)
-+            return this;
-+
-         Number t;
-         if (n < 0)
-         {
-@@ -557,44 +928,17 @@
-             n = -n;
-         }
-         else
--        {
-             t = this;
--        }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.power_signed_integer (t.re_num, (long) n, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        var tmp2 = z.im_num;
--        tmp2.clear ();
--        tmp = MPFloat.init2 ((Precision) precision);
--        tmp.@set (t.im_num, Round.NEAREST);
--        z.im_num = tmp;
--        return z;
--    }
--
--    private Number pwr (Number y)
--    {
--        /* (-x)^y imaginary */
--        /* FIXME: Make complex numbers optional */
--        /*if (re_sign < 0)
-+        var z = new Number.integer (1);
-+        while (n != 0)
-         {
--            mperr (_("The power of negative numbers is only defined for integer exponents"));
--            return new Number.integer (0);
--        }*/
--
--        /* 0^y = 0, 0^-y undefined */
--        if (is_zero ())
--        {
--            if (y.is_negative ())
--                error = _("The power of zero is undefined for a negative exponent");
--            return new Number.integer (0);
-+            if (n % 2 == 1)
-+                z = z.multiply (t);
-+            t = t.multiply (t);
-+            n = n / 2;
-         }
--
--        /* x^0 = 1 */
--        if (y.is_zero ())
--            return new Number.integer (1);
--
--        return y.multiply (ln ()).epowy ();
-+        return z;
-     }
- 
-     /* Sets z = n√x */
-@@ -623,10 +967,22 @@
-     /* Sets z = √x */
-     public Number sqrt ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.sqrt (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        if (is_zero ())
-+            return this;
-+
-+        /* FIXME: Make complex numbers optional */
-+        /*if (re_sign < 0)
-+        {
-+            mperr (_("Square root is undefined for negative values"));
-+            return new Number.integer (0);
-+        }*/
-+        else
-+        {
-+            var t = root (-2);
-+            var z = multiply (t);
-+            return z.ext (t.re_fraction[0], z.re_fraction[0]);
-+        }
-+
-     }
- 
-     /* Sets z = ln x */
-@@ -636,7 +992,7 @@
-         if (is_zero ())
-         {
-             /* Translators: Error displayed when attempting to take logarithm of zero */
--            error = _("Logarithm of zero is undefined");
-+            mperr (_("Logarithm of zero is undefined"));
-             return new Number.integer (0);
-         }
- 
-@@ -669,7 +1025,7 @@
-         if (is_zero ())
-         {
-             /* Translators: Error displayed when attempting to take logarithm of zero */
--            error = _("Logarithm of zero is undefined");
-+            mperr (_("Logarithm of zero is undefined"));
-             return new Number.integer (0);
-         }
- 
-@@ -691,17 +1047,17 @@
-             if (is_negative () || is_complex ())
-             {
-                 /* Translators: Error displayed when attempted take the factorial of a negative or complex number */
--                error = _("Factorial is only defined for non-negative real numbers");
-+                mperr (_("Factorial is only defined for non-negative real numbers"));
-                 return new Number.integer (0);
-             }
- 
--            var tmp = add (new Number.integer (1));
--            var tmp2 = MPFloat.init2 ((Precision) precision);
-+	    var val = to_double ();
- 
-             /* Factorial(x) = Gamma(x+1) - This is the formula used to calculate Factorial.*/
--            tmp2.gamma (tmp.re_num, Round.NEAREST);
-+            var fact = Math.tgamma(val+1);
- 
--            return new Number.mpfloat (tmp2);
-+            return new Number.double(fact);
-+
-         }
- 
-         /* Convert to integer - if couldn't be converted then the factorial would be too big anyway */
-@@ -716,41 +1072,23 @@
-     /* Sets z = x + y */
-     public Number add (Number y)
-     {
--        if (is_complex () || y.is_complex ())
--        {
--            Number real_z, im_z;
--
--            var real_x = real_component ();
--            var im_x = imaginary_component ();
--            var real_y = y.real_component ();
--            var im_y = y.imaginary_component ();
--
--            real_z = real_x.add_real (real_y);
--            im_z = im_x.add_real (im_y);
--
--            return new Number.complex (real_z, im_z);
--        }
--        else
--            return add_real (y);
-+        return add_with_sign (1, y);
-     }
- 
--    public Number add_real (Number y)
--    {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.add (re_num, y.re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
--    }
--
-     /* Sets z = x − y */
-     public Number subtract (Number y)
-     {
--        return add (y.invert_sign ());
-+        return add_with_sign (-1, y);
-     }
- 
-     /* Sets z = x × y */
-     public Number multiply (Number y)
-     {
-+        /* x*0 = 0*y = 0 */
-+        if (is_zero () || y.is_zero ())
-+            return new Number.integer (0);
-+
-+        /* (a+bi)(c+di) = (ac-bd)+(ad+bc)i */
-         if (is_complex () || y.is_complex ())
-         {
-             Number t1, t2, real_z, im_z;
-@@ -774,23 +1112,17 @@
-             return multiply_real (y);
-     }
- 
--    public Number multiply_real (Number y)
--    {
--        var z = new Number.integer (0);
--        var tmp = z.re_num;
--        tmp.multiply (re_num, y.re_num, Round.NEAREST);
--        z.re_num = tmp;
--        return z;
--    }
--
-     /* Sets z = x × y */
-     public Number multiply_integer (int64 y)
-     {
--        var z = new Number.integer (0);
--        var tmp = z.re_num;
--        tmp.multiply_signed_integer (re_num, (long) y, Round.NEAREST);
--        z.re_num = tmp;
--        return z;
-+        if (is_complex ())
-+        {
-+            var re_z = real_component ().multiply_integer_real (y);;
-+            var im_z = imaginary_component ().multiply_integer_real (y);
-+            return new Number.complex (re_z, im_z);
-+        }
-+        else
-+            return multiply_integer_real (y);
-     }
- 
-     /* Sets z = x ÷ y */
-@@ -799,31 +1131,23 @@
-         if (y.is_zero ())
-         {
-             /* Translators: Error displayed attempted to divide by zero */
--            error = _("Division by zero is undefined");
-+            mperr (_("Division by zero is undefined"));
-             return new Number.integer (0);
-         }
-+        /* 0/y = 0 */
-+        if (is_zero ())
-+            return this;
- 
--        if (is_complex () || y.is_complex ())
--        {
--            var a = real_component ();
--            var b = imaginary_component ();
--            var c = y.real_component ();
--            var d = y.imaginary_component ();
-+        /* z = x × y⁻¹ */
-+        /* FIXME: Set re_exponent to zero to avoid overflow in multiply??? */
-+        var t = y.reciprocal ();
-+        var ie = t.re_exponent;
-+        t.re_exponent = 0;
-+        var i = t.re_fraction[0];
-+        var z = multiply (t);
-+        z = z.ext (i, z.re_fraction[0]);
-+        z.re_exponent += ie;
- 
--            var tmp = a.multiply (c).add (b.multiply (d));
--            var tmp_2 = c.xpowy_integer (2).add (d.xpowy_integer (2));
--            var z_1 = tmp.divide (tmp_2);
--
--            tmp = b.multiply (c).subtract (a.multiply (d));
--            var z_2 = tmp.divide (tmp_2);
--
--            var z = new Number.complex (z_1, z_2);
--            return z;
--        }
--
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.divide (re_num, y.re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-         return z;
-     }
- 
-@@ -830,7 +1154,14 @@
-     /* Sets z = x ÷ y */
-     public Number divide_integer (int64 y)
-     {
--        return divide (new Number.integer (y));
-+        if (is_complex ())
-+        {
-+            var re_z = real_component ().divide_integer_real (y);
-+            var im_z = imaginary_component ().divide_integer_real (y);
-+            return new Number.complex (re_z, im_z);
-+        }
-+        else
-+            return divide_integer_real (y);
-     }
- 
-     /* Sets z = x mod y */
-@@ -839,7 +1170,7 @@
-         if (!is_integer () || !y.is_integer ())
-         {
-             /* Translators: Error displayed when attemping to do a modulus division on non-integer numbers */
--            error = _("Modulus division is only defined for integers");
-+            mperr (_("Modulus division is only defined for integers"));
-             return new Number.integer (0);
-         }
- 
-@@ -857,7 +1188,7 @@
-     /* Sets z = x ^ y mod p */
-     public Number modular_exponentiation (Number exp, Number mod)
-     {
--        var base_value = copy ();
-+        var base_value = this.copy ();
-         if (exp.is_negative ())
-             base_value = base_value.reciprocal ();
-         var exp_value = exp.abs ();
-@@ -927,51 +1258,87 @@
-     public Number tan (AngleUnit unit = AngleUnit.RADIANS)
-     {
-         /* Check for undefined values */
--        var x_radians = to_radians (unit);
--        var check = x_radians.subtract (new Number.pi ().divide_integer (2)).divide (new Number.pi ());
--
--        if (check.is_integer ())
-+        var cos_x = cos (unit);
-+        if (cos_x.is_zero ())
-         {
-             /* Translators: Error displayed when tangent value is undefined */
--            error = _("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)");
-+            mperr (_("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)"));
-             return new Number.integer (0);
-         }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.tan (x_radians.re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* tan (x) = sin (x) / cos (x) */
-+        return sin (unit).divide (cos_x);
-     }
- 
-     /* Sets z = sin⁻¹ x */
-     public Number asin (AngleUnit unit = AngleUnit.RADIANS)
-     {
--        if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
--        {
--            /* Translators: Error displayed when inverse sine value is undefined */
--            error = _("Inverse sine is undefined for values outside [-1, 1]");
-+        /* asin⁻¹(0) = 0 */
-+        if (is_zero ())
-             return new Number.integer (0);
-+
-+        /* sin⁻¹(x) = tan⁻¹(x / √(1 - x²)), |x| < 1 */
-+        if (re_exponent <= 0)
-+        {
-+            var t1 = new Number.integer (1);
-+            var t2 = t1;
-+            t1 = t1.subtract (this);
-+            t2 = t2.add (this);
-+            t2 = t1.multiply (t2);
-+            t2 = t2.root (-2);
-+            var z = multiply (t2);
-+            z = z.atan (unit);
-+            return z;
-         }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.asin (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z.from_radians (unit);
-+        /* sin⁻¹(1) = π/2, sin⁻¹(-1) = -π/2 */
-+        var t2 = new Number.integer (re_sign);
-+        if (equals (t2))
-+        {
-+            var z = new Number.pi ().divide_integer (2 * t2.re_sign);
-+            return z.from_radians (unit);
-+        }
-+
-+        /* Translators: Error displayed when inverse sine value is undefined */
-+        mperr (_("Inverse sine is undefined for values outside [-1, 1]"));
-+        return new Number.integer (0);
-     }
- 
-     /* Sets z = cos⁻¹ x */
-     public Number acos (AngleUnit unit = AngleUnit.RADIANS)
-     {
--        if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
-+        var pi = new Number.pi ();
-+        var t1 = new Number.integer (1);
-+        var n1 = new Number.integer (-1);
-+
-+        Number z;
-+        if (compare (t1) > 0 || compare (n1) < 0)
-         {
-             /* Translators: Error displayed when inverse cosine value is undefined */
--            error = _("Inverse cosine is undefined for values outside [-1, 1]");
--            return new Number.integer (0);
-+            mperr (_("Inverse cosine is undefined for values outside [-1, 1]"));
-+            z = new Number.integer (0);
-         }
-+        else if (is_zero ())
-+            z = pi.divide_integer (2);
-+        else if (equals (t1))
-+            z = new Number.integer (0);
-+        else if (equals (n1))
-+            z = pi;
-+        else
-+        {
-+            /* cos⁻¹(x) = tan⁻¹(√(1 - x²) / x) */
-+            Number y;
-+            var t2 = multiply (this);
-+            t2 = t1.subtract (t2);
-+            t2 = t2.sqrt ();
-+            t2 = t2.divide (this);
-+            y = t2.atan (AngleUnit.RADIANS);
-+            if (re_sign > 0)
-+                z = y;
-+            else
-+                z = y.add (pi);
-+        }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.acos (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-         return z.from_radians (unit);
-     }
- 
-@@ -978,9 +1345,63 @@
-     /* Sets z = tan⁻¹ x */
-     public Number atan (AngleUnit unit = AngleUnit.RADIANS)
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.atan (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        var t2 = this;
-+        var rx = 0f;
-+        if (re_exponent.abs () <= 2)
-+            rx = to_float ();
-+
-+        /* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
-+        var q = 1;
-+        Number z;
-+        while (t2.re_exponent >= 0)
-+        {
-+            if (t2.re_exponent == 0 && 2 * (t2.re_fraction[0] + 1) <= BASE)
-+                break;
-+
-+            q *= 2;
-+
-+            /* t = t / (√(t² + 1) + 1) */
-+            z = t2.multiply (t2);
-+            z = z.add (new Number.integer (1));
-+            z = z.sqrt ();
-+            z = z.add (new Number.integer (1));
-+            t2 = t2.divide (z);
-+        }
-+
-+        /* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
-+        z = t2;
-+        var t1 = t2.multiply (t2);
-+
-+        /* SERIES LOOP.  REDUCE T IF POSSIBLE. */
-+        for (var i = 1; ; i += 2)
-+        {
-+            if (T + 2 + t2.re_exponent <= 1)
-+                break;
-+
-+            t2 = t2.multiply (t1).multiply_integer (-i).divide_integer (i + 2);
-+
-+            z = z.add (t2);
-+            if (t2.is_zero ())
-+                break;
-+        }
-+
-+        /* CORRECT FOR ARGUMENT REDUCTION */
-+        z = z.multiply_integer (q);
-+
-+        /*  CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS re_exponent
-+         *  OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
-+         */
-+        if (re_exponent.abs () <= 2)
-+        {
-+            float ry = z.to_float ();
-+            /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
-+            if (Math.fabs (ry - Math.atan (rx)) >= Math.fabs (ry) * 0.01)
-+                mperr ("*** ERROR OCCURRED IN ATAN, RESULT INCORRECT ***");
-+        }
-+
-         return z.from_radians (unit);
-     }
- 
-@@ -987,27 +1408,88 @@
-     /* Sets z = sinh x */
-     public Number sinh ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.sinh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* sinh (0) = 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        /* WORK WITH ABS (X) */
-+        var abs_x = abs ();
-+
-+        /* If |x| < 1 USE EXP TO AVOID CANCELLATION, otherwise IF TOO LARGE EPOWY GIVES ERROR MESSAGE */
-+        Number z;
-+        if (abs_x.re_exponent <= 0)
-+        {
-+            /* ((e^|x| + 1) * (e^|x| - 1)) / e^|x| */
-+            // FIXME: Solves to e^|x| - e^-|x|, why not lower branch always? */
-+            var exp_x = abs_x.epowy ();
-+            var a = exp_x.add (new Number.integer (1));
-+            var b = exp_x.add (new Number.integer (-1));
-+            z = a.multiply (b);
-+            z = z.divide (exp_x);
-+        }
-+        else
-+        {
-+            /* e^|x| - e^-|x| */
-+            var exp_x = abs_x.epowy ();
-+            z = exp_x.reciprocal ();
-+            z = exp_x.subtract (z);
-+        }
-+
-+        /* DIVIDE BY TWO AND RESTORE re_sign */
-+        z = z.divide_integer (2);
-+        return z.multiply_integer (re_sign);
-     }
- 
-     /* Sets z = cosh x */
-     public Number cosh ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.cosh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* cosh (0) = 1 */
-+        if (is_zero ())
-+            return new Number.integer (1);
-+
-+        /* cosh (x) = (e^x + e^-x) / 2 */
-+        var t = abs ();
-+        t = t.epowy ();
-+        var z = t.reciprocal ();
-+        z = t.add (z);
-+        return z.divide_integer (2);
-     }
- 
-     /* Sets z = tanh x */
-     public Number tanh ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.tanh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-+        /* tanh (0) = 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        var t = abs ();
-+
-+        /* SEE IF ABS (X) SO LARGE THAT RESULT IS +-1 */
-+        var r__1 = (float) T * 0.5 * Math.log ((float) BASE);
-+        var z = new Number.double (r__1);
-+        if (t.compare (z) > 0)
-+            return new Number.integer (re_sign);
-+
-+        /* If |x| >= 1/2 use ?, otherwise use ? to avoid cancellation */
-+        /* |tanh (x)| = (e^|2x| - 1) / (e^|2x| + 1) */
-+        t = t.multiply_integer (2);
-+        if (t.re_exponent > 0)
-+        {
-+            t = t.epowy ();
-+            z = t.add (new Number.integer (-1));
-+            t = t.add (new Number.integer (1));
-+            z = z.divide (t);
-+        }
-+        else
-+        {
-+            t = t.epowy ();
-+            z = t.add (new Number.integer (1));
-+            t = t.add (new Number.integer (-1));
-+            z = t.divide (z);
-+        }
-+
-+        /* Restore re_sign */
-+        z.re_sign = re_sign * z.re_sign;
-         return z;
-     }
- 
-@@ -1014,10 +1496,12 @@
-     /* Sets z = sinh⁻¹ x */
-     public Number asinh ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.asinh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* sinh⁻¹(x) = ln (x + √(x² + 1)) */
-+        var t = multiply (this);
-+        t = t.add (new Number.integer (1));
-+        t = t.sqrt ();
-+        t = add (t);
-+        return t.ln ();
-     }
- 
-     /* Sets z = cosh⁻¹ x */
-@@ -1028,14 +1512,16 @@
-         if (compare (t) < 0)
-         {
-             /* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
--            error = _("Inverse hyperbolic cosine is undefined for values less than one");
-+            mperr (_("Inverse hyperbolic cosine is undefined for values less than one"));
-             return new Number.integer (0);
-         }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.acosh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* cosh⁻¹(x) = ln (x + √(x² - 1)) */
-+        t = multiply (this);
-+        t = t.add (new Number.integer (-1));
-+        t = t.sqrt ();
-+        t = add (t);
-+        return t.ln ();
-     }
- 
-     /* Sets z = tanh⁻¹ x */
-@@ -1045,14 +1531,17 @@
-         if (compare (new Number.integer (1)) >= 0 || compare (new Number.integer (-1)) <= 0)
-         {
-             /* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
--            error = _("Inverse hyperbolic tangent is undefined for values outside [-1, 1]");
-+            mperr (_("Inverse hyperbolic tangent is undefined for values outside [-1, 1]"));
-             return new Number.integer (0);
-         }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.atanh (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* atanh (x) = 0.5 * ln ((1 + x) / (1 - x)) */
-+        var n = add (new Number.integer (1));
-+        var d = invert_sign ();
-+        d = d.add (new Number.integer (1));
-+        var z = n.divide (d);
-+        z = z.ln ();
-+        return z.divide_integer (2);
-     }
- 
-     /* Sets z = boolean AND for each bit in x and z */
-@@ -1062,7 +1551,7 @@
-         is_positive_integer () || !y.is_positive_integer ())
-         {
-             /* Translators: Error displayed when boolean AND attempted on non-integer values */
--            error = _("Boolean AND is only defined for positive integers");
-+            mperr (_("Boolean AND is only defined for positive integers"));
-         }
- 
-         return bitwise (y, (v1, v2) => { return v1 & v2; }, 0);
-@@ -1074,7 +1563,7 @@
-         if (!is_positive_integer () || !y.is_positive_integer ())
-         {
-             /* Translators: Error displayed when boolean OR attempted on non-integer values */
--            error = _("Boolean OR is only defined for positive integers");
-+            mperr (_("Boolean OR is only defined for positive integers"));
-         }
- 
-         return bitwise (y, (v1, v2) => { return v1 | v2; }, 0);
-@@ -1086,7 +1575,7 @@
-         if (!is_positive_integer () || !y.is_positive_integer ())
-         {
-             /* Translators: Error displayed when boolean XOR attempted on non-integer values */
--            error = _("Boolean XOR is only defined for positive integers");
-+            mperr (_("Boolean XOR is only defined for positive integers"));
-         }
- 
-         return bitwise (y, (v1, v2) => { return v1 ^ v2; }, 0);
-@@ -1098,7 +1587,7 @@
-         if (!is_positive_integer ())
-         {
-             /* Translators: Error displayed when boolean XOR attempted on non-integer values */
--            error = _("Boolean NOT is only defined for positive integers");
-+            mperr (_("Boolean NOT is only defined for positive integers"));
-         }
- 
-         return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ 0xF; }, wordlen);
-@@ -1121,7 +1610,7 @@
-         if (!is_integer ())
-         {
-             /* Translators: Error displayed when bit shift attempted on non-integer values */
--            error = _("Shift is only possible on integer values");
-+            mperr (_("Shift is only possible on integer values"));
-             return new Number.integer (0);
-         }
- 
-@@ -1253,60 +1742,1056 @@
-     private Number copy ()
-     {
-         var z = new Number ();
--        var tmp = MPFloat.init2 ((Precision) precision);
--        var tmp2 = MPFloat.init2 ((Precision) precision);
--        tmp.@set(re_num, Round.NEAREST);
--        tmp2.@set(im_num, Round.NEAREST);
--        z.re_num = tmp;
--        z.im_num = tmp2;
-+        z.re_sign = re_sign;
-+        z.im_sign = im_sign;
-+        z.re_exponent = re_exponent;
-+        z.im_exponent = im_exponent;
-+        for (var i = 0; i < re_fraction.length; i++)
-+        {
-+            z.re_fraction[i] = re_fraction[i];
-+            z.im_fraction[i] = im_fraction[i];
-+        }
-+
-         return z;
-     }
- 
-+    private Number add_with_sign (int y_sign, Number y)
-+    {
-+        if (is_complex () || y.is_complex ())
-+        {
-+            Number real_z, im_z;
-+
-+            var real_x = real_component ();
-+            var im_x = imaginary_component ();
-+            var real_y = y.real_component ();
-+            var im_y = y.imaginary_component ();
-+
-+            real_z = real_x.add_real (y_sign * y.re_sign, real_y);
-+            im_z = im_x.add_real (y_sign * y.im_sign, im_y);
-+
-+            return new Number.complex (real_z, im_z);
-+        }
-+        else
-+            return add_real (y_sign * y.re_sign, y);
-+    }
-+
-+
-     private Number epowy_real ()
-     {
--        var z = copy ();
--        var tmp = z.re_num;
--        tmp.exp (re_num, Round.NEAREST);
--        z.re_num = tmp;
-+        /* e^0 = 1 */
-+        if (is_zero ())
-+            return new Number.integer (1);
-+
-+        /* If |x| < 1 use exp */
-+        if (re_exponent <= 0)
-+            return exp ();
-+
-+        /* NOW SAFE TO CONVERT X TO REAL */
-+        var rx = to_double ();
-+
-+        /* SAVE re_sign AND WORK WITH ABS (X) */
-+        var xs = re_sign;
-+        var t2 = abs ();
-+
-+        /* GET fractional AND INTEGER PARTS OF ABS (X) */
-+        var ix = t2.to_integer ();
-+        t2 = t2.fractional_component ();
-+
-+        /* ATTACH re_sign TO fractional PART AND COMPUTE EXP OF IT */
-+        t2.re_sign *= xs;
-+        var z = t2.exp ();
-+
-+        /*  COMPUTE E-2 OR 1/E USING TWO EXTRA DIGITS IN CASE ABS (X) LARGE
-+         *  (BUT ONLY ONE EXTRA DIGIT IF T < 4)
-+         */
-+        var tss = 0;
-+        if (T < 4)
-+            tss = T + 1;
-+        else
-+            tss = T + 2;
-+
-+        /* LOOP FOR E COMPUTATION. DECREASE T IF POSSIBLE. */
-+        /* Computing MIN */
-+        var t1 = new Number.integer (xs);
-+
-+        t2.re_sign = 0;
-+        for (var i = 2 ; ; i++)
-+        {
-+            if (int.min (tss, tss + 2 + t1.re_exponent) <= 2)
-+                break;
-+
-+            t1 = t1.divide_integer (i * xs);
-+            t2 = t2.add (t1);
-+            if (t1.is_zero ())
-+                break;
-+        }
-+
-+        /* RAISE E OR 1/E TO POWER IX */
-+        if (xs > 0)
-+            t2 = t2.add (new Number.integer (2));
-+        t2 = t2.xpowy_integer (ix);
-+
-+        /* MULTIPLY EXPS OF INTEGER AND fractional PARTS */
-+        z = z.multiply (t2);
-+
-+        /*  CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS ABS (X) LARGE
-+         *  (WHEN EXP MIGHT OVERFLOW OR UNDERFLOW)
-+         */
-+        if (Math.fabs (rx) > 10.0f)
-+            return z;
-+        var rz = z.to_double ();
-+        var r__1 = rz - Math.exp (rx);
-+        if (Math.fabs (r__1) < rz * 0.01f)
-+            return z;
-+
-+        /*  THE FOLLOWING MESSAGE MAY INDICATE THAT
-+         *  B**(T-1) IS TOO SMALL, OR THAT M IS TOO SMALL SO THE
-+         *  RESULT UNDERFLOWED.
-+         */
-+        mperr ("*** ERROR OCCURRED IN EPOWY, RESULT INCORRECT ***");
-         return z;
-+
-     }
- 
-+    /*  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.
-+     */
-+    private Number exp ()
-+    {
-+        /* e^0 = 1 */
-+        if (is_zero ())
-+            return new Number.integer (1);
-+
-+        /* Only defined for |x| < 1 */
-+        if (re_exponent > 0)
-+        {
-+            mperr ("*** ABS (X) NOT LESS THAN 1 IN CALL TO MP_EXP ***");
-+            return new Number.integer (0);
-+        }
-+
-+        var t1 = this;
-+        var rlb = Math.log (BASE);
-+
-+        /* Compute approximately optimal q (and divide x by 2^q) */
-+        var q = (int) (Math.sqrt (T * 0.48 * rlb) + re_exponent * 1.44 * rlb);
-+
-+        /* HALVE Q TIMES */
-+        if (q > 0)
-+        {
-+            var ib = BASE << 2;
-+            var ic = 1;
-+            for (var i = 1; i <= q; i++)
-+            {
-+                ic *= 2;
-+                if (ic < ib && ic != BASE && i < q)
-+                    continue;
-+                t1 = t1.divide_integer (ic);
-+                ic = 1;
-+            }
-+        }
-+
-+        if (t1.is_zero ())
-+            return new Number.integer (0);
-+
-+        /* Sum series, reducing t where possible */
-+        var z = t1.copy ();
-+        var t2 = t1;
-+        for (var i = 2; T + t2.re_exponent - z.re_exponent > 0; i++)
-+        {
-+            t2 = t1.multiply (t2);
-+            t2 = t2.divide_integer (i);
-+            z = t2.add (z);
-+            if (t2.is_zero ())
-+                break;
-+        }
-+
-+        /* Apply (x+1)^2 - 1 = x (2 + x) for q iterations */
-+        for (var i = 1; i <= q; i++)
-+        {
-+            t1 = z.add (new Number.integer (2));
-+            z = t1.multiply (z);
-+        }
-+
-+        return z.add (new Number.integer (1));    
-+    }
-+
-+    private Number pwr (Number y)
-+    {
-+        /* (-x)^y imaginary */
-+        /* FIXME: Make complex numbers optional */
-+        /*if (re_sign < 0)
-+        {
-+            mperr (_("The power of negative numbers is only defined for integer exponents"));
-+            return new Number.integer (0);
-+        }*/
-+
-+        /* 0^y = 0, 0^-y undefined */
-+        if (is_zero ())
-+        {
-+            if (y.re_sign < 0)
-+                mperr (_("The power of zero is undefined for a negative exponent"));
-+            return new Number.integer (0);
-+        }
-+
-+        /* x^0 = 1 */
-+        if (y.is_zero ())
-+            return new Number.integer (1);
-+
-+        return y.multiply (ln ()).epowy ();
-+    }
-+
-     private Number root_real (int64 n)
-     {
-+        /* x^(1/1) = x */
-+        if (n == 1)
-+            return this;
-+
-+        /* x^(1/0) invalid */
-+        if (n == 0)
-+        {
-+            mperr (_("Root must be non-zero"));
-+            return new Number.integer (0);
-+        }
-+
-+        var np = n.abs ();
-+
-+        /* LOSS OF ACCURACY IF NP LARGE, SO ONLY ALLOW NP <= MAX (B, 64) */
-+        if (np > int.max (BASE, 64))
-+        {
-+            mperr ("*** ABS (N) TOO LARGE IN CALL TO ROOT ***");
-+            return new Number.integer (0);
-+        }
-+
-+        /* 0^(1/n) = 0 for positive n */
-+        if (is_zero ())
-+        {
-+            if (n <= 0)
-+                mperr (_("Negative root of zero is undefined"));
-+            return new Number.integer (0);
-+        }
-+
-+        // FIXME: Imaginary root
-+        if (re_sign < 0 && np % 2 == 0)
-+        {
-+            mperr (_("nth root of negative number is undefined for even n"));
-+            return new Number.integer (0);
-+        }
-+
-+        /* DIVIDE re_exponent BY NP */
-+        var ex = re_exponent / np;
-+
-+        /* Get initial approximation */
-+        var t1 = copy ();
-+        t1.re_exponent = 0;
-+        var approximation = Math.exp (((np * ex - re_exponent) * Math.log (BASE) - Math.log (Math.fabs (t1.to_float ()))) / np);
-+        t1 = new Number.double (approximation);
-+        t1.re_sign = re_sign;
-+        t1.re_exponent -= (int) ex;
-+
-+        /* MAIN ITERATION LOOP */
-+        var it0 = 3;
-+        var t = it0;
-+        Number t2;
-+        while (true)
-+        {
-+            /* t1 = t1 - ((t1 * ((x * t1^np) - 1)) / np) */
-+            t2 = t1.xpowy_integer (np);
-+            t2 = multiply (t2);
-+            t2 = t2.add (new Number.integer (-1));
-+            t2 = t1.multiply (t2);
-+            t2 = t2.divide_integer (np);
-+            t1 = t1.subtract (t2);
-+
-+            /*  FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE BECAUSE
-+             *  NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
-+             */
-+            if (t >= T)
-+                break;
-+
-+            var ts3 = t;
-+            var ts2 = t;
-+            t = T;
-+            do
-+            {
-+                ts2 = t;
-+                t = (t + it0) / 2;
-+            } while (t > ts3);
-+            t = int.min (ts2, T);
-+        }
-+
-+        /*  NOW r (I2) IS X**(-1/NP)
-+         *  CHECK THAT NEWTON ITERATION WAS CONVERGING
-+         */
-+        if (t2.re_sign != 0 && (t1.re_exponent - t2.re_exponent) << 1 < 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.
-+             */
-+            mperr ("*** ERROR OCCURRED IN ROOT, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
-+        }
-+
-+        if (n >= 0)
-+        {
-+            t1 = t1.xpowy_integer (n - 1);
-+            return multiply (t1);
-+        }
-+
-+        return t1;
-+
-+    }
-+
-+    /*  ROUTINE CALLED BY DIVIDE AND SQRT TO ENSURE THAT
-+     *  RESULTS ARE REPRESENTED EXACTLY IN T-2 DIGITS IF THEY
-+     *  CAN BE.  X IS AN MP NUMBER, I AND J ARE INTEGERS.
-+     */
-+    private Number ext (int i, int j)
-+    {
-+        if (is_zero () || T <= 2 || i == 0)
-+            return this;
-+
-+        /* COMPUTE MAXIMUM POSSIBLE ERROR IN THE LAST PLACE */
-+        var q = (j + 1) / i + 1;
-+        var s = BASE * re_fraction[T - 2] + re_fraction[T - 1];
-+
-+        /* SET LAST TWO DIGITS TO ZERO */
-         var z = copy ();
--        var tmp = z.re_num;
--        tmp.root (re_num, (ulong) n, Round.NEAREST);
--        z.re_num = tmp;
--        return z;
-+        if (s <= q)
-+        {
-+            z.re_fraction[T - 2] = 0;
-+            z.re_fraction[T - 1] = 0;
-+            return z;
-+        }
-+
-+        if (s + q < BASE * BASE)
-+            return z;
-+
-+        /* ROUND UP HERE */
-+        z.re_fraction[T - 2] = BASE - 1;
-+        z.re_fraction[T - 1] = BASE;
-+
-+        /* NORMALIZE X (LAST DIGIT B IS OK IN MULTIPLY_INTEGER) */
-+        return z.multiply_integer (1);
-     }
- 
-+
-     private Number ln_real ()
-     {
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.log (re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
-+        // ln(e^1) = 1, fixes precision loss
-+        if (equals (new Number.eulers ()))
-+            return new Number.integer (1);
-+
-+        /* LOOP TO GET APPROXIMATE Ln (X) USING SINGLE-PRECISION */
-+        var t1 = copy ();
-+        var z = new Number.integer (0);
-+        for (var k = 0; k < 10; k++)
-+        {
-+            /* COMPUTE FINAL CORRECTION ACCURATELY USING LNS */
-+            var t2 = t1.add (new Number.integer (-1));
-+            if (t2.is_zero () || t2.re_exponent + 1 <= 0)
-+                return z.add (t2.lns ());
-+
-+            /* REMOVE EXPONENT TO AVOID FLOATING-POINT OVERFLOW */
-+            var e = t1.re_exponent;
-+            t1.re_exponent = 0;
-+            var rx = t1.to_double ();
-+            t1.re_exponent = e;
-+            var rlx = Math.log (rx) + e * Math.log (BASE);
-+            t2 = new Number.double (-rlx);
-+
-+            /* UPDATE Z AND COMPUTE ACCURATE EXP OF APPROXIMATE LOG */
-+            z = z.subtract (t2);
-+            t2 = t2.epowy ();
-+
-+            /* COMPUTE RESIDUAL WHOSE LOG IS STILL TO BE FOUND */
-+            t1 = t1.multiply (t2);
-+        }
-+
-+        mperr ("*** ERROR IN LN, ITERATION NOT CONVERGING ***");
-         return z;
-+
-     }
- 
-+    /*  RETURNS MP Y = Ln (1+X) IF X IS AN MP NUMBER SATISFYING THE
-+     *  CONDITION ABS (X) < 1/B, ERROR OTHERWISE.
-+     *  USES NEWTONS METHOD TO SOLVE THE EQUATION
-+     *  EXP1(-Y) = X, THEN REVERSES re_sign OF Y.
-+     */
-+    private Number lns ()
-+    {
-+        /* ln (1+0) = 0 */
-+        if (is_zero ())
-+            return this;
-+
-+        /* Get starting approximation -ln (1+x) ~= -x + x^2/2 - x^3/3 + x^4/4 */
-+        var t2 = copy ();
-+        var t1 = divide_integer (4);
-+        t1 = t1.add (new Number.fraction (-1, 3));
-+        t1 = multiply (t1);
-+        t1 = t1.add (new Number.fraction (1, 2));
-+        t1 = multiply (t1);
-+        t1 = t1.add (new Number.integer (-1));
-+        var z = multiply (t1);
-+
-+        /* Solve using Newtons method */
-+        var it0 = 5;
-+        var t = it0;
-+        Number t3;
-+        while (true)
-+        {
-+            /* t3 = (e^t3 - 1) */
-+            /* z = z - (t2 + t3 + (t2 * t3)) */
-+            t3 = z.epowy ();
-+            t3 = t3.add (new Number.integer (-1));
-+            t1 = t2.multiply (t3);
-+            t3 = t3.add (t1);
-+            t3 = t2.add (t3);
-+            z = z.subtract (t3);
-+            if (t >= T)
-+                break;
-+
-+            /*  FOLLOWING LOOP COMPUTES NEXT VALUE OF T TO USE.
-+             *  BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE,
-+             *  WE CAN ALMOST DOUBLE T EACH TIME.
-+             */
-+            var ts3 = t;
-+            var ts2 = t;
-+            t = T;
-+            do
-+            {
-+                ts2 = t;
-+                t = (t + it0) / 2;
-+            } while (t > ts3);
-+            t = ts2;
-+        }
-+
-+        /* CHECK THAT NEWTON ITERATION WAS CONVERGING AS EXPECTED */
-+        if (t3.re_sign != 0 && t3.re_exponent << 1 > it0 - T)
-+            mperr ("*** ERROR OCCURRED IN LNS, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
-+
-+        z.re_sign = -z.re_sign;
-+
-+        return z;
-+    }
-+
-+    private Number add_real (int y_sign, Number y)
-+    {
-+        var re_sign_prod = y_sign * re_sign;
-+
-+        /* 0 + y = y */
-+        if (is_zero ())
-+        {
-+            if (y_sign != y.re_sign)
-+                return y.invert_sign ();
-+            else
-+                return y;
-+        }
-+        /* x + 0 = x */
-+        else if (y.is_zero ())
-+            return this;
-+
-+        var exp_diff = re_exponent - y.re_exponent;
-+        var med = exp_diff.abs ();
-+        var x_largest = false;
-+        if (exp_diff < 0)
-+            x_largest = false;
-+        else if (exp_diff > 0)
-+            x_largest = true;
-+        else
-+        {
-+            /* EXPONENTS EQUAL SO COMPARE SIGNS, THEN FRACTIONS IF NEC. */
-+            if (re_sign_prod < 0)
-+            {
-+                /* signs are not equal.  find out which mantissa is larger. */
-+                int j;
-+                for (j = 0; j < T; j++)
-+                {
-+                    int i = re_fraction[j] - y.re_fraction[j];
-+                    if (i != 0)
-+                    {
-+                        if (i < 0)
-+                            x_largest = false;
-+                        else if (i > 0)
-+                            x_largest = true;
-+                        break;
-+                    }
-+                }
-+
-+                /* Both mantissas equal, so result is zero. */
-+                if (j >= T)
-+                    return new Number.integer (0);
-+            }
-+        }
-+
-+        var z = new Number.integer (0);
-+        int[] big_fraction, small_fraction;
-+        if (x_largest)
-+        {
-+            z.re_sign = re_sign;
-+            z.re_exponent = re_exponent;
-+            big_fraction = re_fraction;
-+            small_fraction = y.re_fraction;
-+        }
-+        else
-+        {
-+            z.re_sign = y_sign;
-+            z.re_exponent = y.re_exponent;
-+            big_fraction = y.re_fraction;
-+            small_fraction = re_fraction;
-+        }
-+
-+        /* CLEAR GUARD DIGITS TO RIGHT OF X DIGITS */
-+        for (var i = 3; i >= med; i--)
-+            z.re_fraction[T + i] = 0;
-+
-+        if (re_sign_prod >= 0)
-+        {
-+            /* This is probably insufficient overflow detection, but it makes us not crash at least. */
-+            if (T + 3 < med)
-+            {
-+                mperr (_("Overflow: the result couldn't be calculated"));
-+                return new Number.integer (0);
-+            }
-+
-+            /* HERE DO ADDITION, re_exponent (Y) >= re_exponent (X) */
-+            var i = 0;
-+            for (i = T + 3; i >= T; i--)
-+                z.re_fraction[i] = small_fraction[i - med];
-+
-+            var c = 0;
-+            for (; i >= med; i--)
-+            {
-+                c = big_fraction[i] + small_fraction[i - med] + c;
-+
-+                if (c < BASE)
-+                {
-+                    /* NO CARRY GENERATED HERE */
-+                    z.re_fraction[i] = c;
-+                    c = 0;
-+                }
-+                else
-+                {
-+                    /* CARRY GENERATED HERE */
-+                    z.re_fraction[i] = c - BASE;
-+                    c = 1;
-+                }
-+            }
-+
-+            for (; i >= 0; i--)
-+            {
-+                c = big_fraction[i] + c;
-+                if (c < BASE)
-+                {
-+                    z.re_fraction[i] = c;
-+                    i--;
-+
-+                    /* NO CARRY POSSIBLE HERE */
-+                    for (; i >= 0; i--)
-+                        z.re_fraction[i] = big_fraction[i];
-+
-+                    c = 0;
-+                    break;
-+                }
-+
-+                z.re_fraction[i] = 0;
-+                c = 1;
-+            }
-+
-+            /* MUST SHIFT RIGHT HERE AS CARRY OFF END */
-+            if (c != 0)
-+            {
-+                for (var j = T + 3; j > 0; j--)
-+                    z.re_fraction[j] = z.re_fraction[j - 1];
-+                z.re_fraction[0] = 1;
-+                z.re_exponent++;
-+            }
-+        }
-+        else
-+        {
-+            var c = 0;
-+            var i = 0;
-+            for (i = T + med - 1; i >= T; i--)
-+            {
-+                /* HERE DO SUBTRACTION, ABS (Y) > ABS (X) */
-+                z.re_fraction[i] = c - small_fraction[i - med];
-+                c = 0;
-+
-+                /* BORROW GENERATED HERE */
-+                if (z.re_fraction[i] < 0)
-+                {
-+                    c = -1;
-+                    z.re_fraction[i] += BASE;
-+                }
-+            }
-+
-+            for (; i >= med; i--)
-+            {
-+                c = big_fraction[i] + c - small_fraction[i - med];
-+                if (c >= 0)
-+                {
-+                    /* NO BORROW GENERATED HERE */
-+                    z.re_fraction[i] = c;
-+                    c = 0;
-+                }
-+                else
-+                {
-+                    /* BORROW GENERATED HERE */
-+                    z.re_fraction[i] = c + BASE;
-+                    c = -1;
-+                }
-+            }
-+
-+            for (; i >= 0; i--)
-+            {
-+                c = big_fraction[i] + c;
-+
-+                if (c >= 0)
-+                {
-+                    z.re_fraction[i] = c;
-+                    i--;
-+
-+                    /* NO CARRY POSSIBLE HERE */
-+                    for (; i >= 0; i--)
-+                        z.re_fraction[i] = big_fraction[i];
-+
-+                    break;
-+                }
-+
-+                z.re_fraction[i] = c + BASE;
-+                c = -1;
-+            }
-+        }
-+
-+        mp_normalize (ref z);
-+
-+        return z;
-+    }
-+
-+    private Number multiply_real (Number y)
-+    {
-+        /* x*0 = 0*y = 0 */
-+        if (re_sign == 0 || y.re_sign == 0)
-+            return new Number.integer (0);
-+
-+        var z = new Number.integer (0);
-+        z.re_sign = re_sign * y.re_sign;
-+        z.re_exponent = re_exponent + y.re_exponent;
-+
-+        var r = new Number.integer (0);
-+
-+        /* PERFORM MULTIPLICATION */
-+        var c = 8;
-+        for (var i = 0; i < T; i++)
-+        {
-+            var xi = re_fraction[i];
-+
-+            /* FOR SPEED, PUT THE NUMBER WITH MANY ZEROS FIRST */
-+            if (xi == 0)
-+                continue;
-+
-+            /* Computing MIN */
-+            for (var j = 0; j < int.min (T, T + 3 - i); j++)
-+                r.re_fraction[i+j+1] += xi * y.re_fraction[j];
-+            c--;
-+            if (c > 0)
-+                continue;
-+
-+            /* CHECK FOR LEGAL BASE B DIGIT */
-+            if (xi < 0 || xi >= BASE)
-+            {
-+                mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-+                return new Number.integer (0);
-+            }
-+
-+            /*  PROPAGATE CARRIES AT END AND EVERY EIGHTH TIME,
-+             *  FASTER THAN DOING IT EVERY TIME.
-+             */
-+            for (var j = T + 3; j >= 0; j--)
-+            {
-+                int ri = r.re_fraction[j] + c;
-+                if (ri < 0)
-+                {
-+                    mperr ("*** INTEGER OVERFLOW IN MULTIPLY, B TOO LARGE ***");
-+                    return new Number.integer (0);
-+                }
-+                c = ri / BASE;
-+                r.re_fraction[j] = ri - BASE * c;
-+            }
-+            if (c != 0)
-+            {
-+                mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-+                return new Number.integer (0);
-+            }
-+            c = 8;
-+        }
-+
-+        if (c != 8)
-+        {
-+            c = 0;
-+            for (var i = T + 3; i >= 0; i--)
-+            {
-+                int ri = r.re_fraction[i] + c;
-+                if (ri < 0)
-+                {
-+                    mperr ("*** INTEGER OVERFLOW IN MULTIPLY, B TOO LARGE ***");
-+                    return new Number.integer (0);
-+                }
-+                c = ri / BASE;
-+                r.re_fraction[i] = ri - BASE * c;
-+            }
-+
-+            if (c != 0)
-+            {
-+                mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
-+                return new Number.integer (0);
-+            }
-+        }
-+
-+        /* Clear complex part */
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+
-+        /* NORMALIZE AND ROUND RESULT */
-+        // FIXME: Use stack variable because of mp_normalize brokeness
-+        for (var i = 0; i < SIZE; i++)
-+            z.re_fraction[i] = r.re_fraction[i];
-+        mp_normalize (ref z);
-+
-+        return z;
-+    }
-+
-+    private Number multiply_integer_real (int64 y)
-+    {
-+        /* x*0 = 0*y = 0 */
-+        if (is_zero () || y == 0)
-+            return new Number.integer (0);
-+
-+        /* x*1 = x, x*-1 = -x */
-+        // FIXME: Why is this not working? mp_ext is using this function to do a normalization
-+        /*if (y == 1 || y == -1)
-+        {
-+            if (y < 0)
-+                z = invert_sign ();
-+            else
-+                z = this;
-+            return z;
-+        }*/
-+
-+        /* Copy x as z may also refer to x */
-+        var z = new Number.integer (0);
-+
-+        if (y < 0)
-+        {
-+            y = -y;
-+            z.re_sign = -re_sign;
-+        }
-+        else
-+            z.re_sign = re_sign;
-+        z.re_exponent = re_exponent + 4;
-+
-+        /* FORM PRODUCT IN ACCUMULATOR */
-+        int64 c = 0;
-+
-+        /*  IF y*B NOT REPRESENTABLE AS AN INTEGER WE HAVE TO SIMULATE
-+         *  DOUBLE-PRECISION MULTIPLICATION.
-+         */
-+
-+        /* Computing MAX */
-+        if (y >= int.max (BASE << 3, 32767 / BASE))
-+        {
-+            /* HERE J IS TOO LARGE FOR SINGLE-PRECISION MULTIPLICATION */
-+            var j1 = y / BASE;
-+            var j2 = y - j1 * BASE;
-+
-+            /* FORM PRODUCT */
-+            for (var i = T + 3; i >= 0; i--)
-+            {
-+                var c1 = c / BASE;
-+                var c2 = c - BASE * c1;
-+                var ix = 0;
-+                if (i > 3)
-+                    ix = re_fraction[i - 4];
-+
-+                var t = j2 * ix + c2;
-+                var is = t / BASE;
-+                c = j1 * ix + c1 + is;
-+                z.re_fraction[i] = (int) (t - BASE * is);
-+            }
-+        }
-+        else
-+        {
-+            int64 ri = 0;
-+            for (var i = T + 3; i >= 4; i--)
-+            {
-+                ri = y * re_fraction[i - 4] + c;
-+                c = ri / BASE;
-+                z.re_fraction[i] = (int) (ri - BASE * c);
-+            }
-+
-+            /* CHECK FOR INTEGER OVERFLOW */
-+            if (ri < 0)
-+            {
-+                mperr ("*** INTEGER OVERFLOW IN multiply_integer, B TOO LARGE ***");
-+                return new Number.integer (0);
-+            }
-+
-+            /* HAVE TO TREAT FIRST FOUR WORDS OF R SEPARATELY */
-+            for (var i = 3; i >= 0; i--)
-+            {
-+                var t = c;
-+                c = t / BASE;
-+                z.re_fraction[i] = (int) (t - BASE * c);
-+            }
-+        }
-+
-+        /* HAVE TO SHIFT RIGHT HERE AS CARRY OFF END */
-+        while (c != 0)
-+        {
-+            for (var i = T + 3; i >= 1; i--)
-+                z.re_fraction[i] = z.re_fraction[i - 1];
-+            var t = c;
-+            c = t / BASE;
-+            z.re_fraction[0] = (int) (t - BASE * c);
-+            z.re_exponent++;
-+        }
-+
-+        if (c < 0)
-+        {
-+            mperr ("*** INTEGER OVERFLOW IN multiply_integer, B TOO LARGE ***");
-+            return new Number.integer (0);
-+        }
-+
-+        z.im_sign = 0;
-+        z.im_exponent = 0;
-+        for (var i = 0; i < z.im_fraction.length; i++)
-+            z.im_fraction[i] = 0;
-+        mp_normalize (ref z);
-+        return z;
-+    }
-+
-     private Number reciprocal_real ()
-     {
-         /* 1/0 invalid */
-         if (is_zero ())
-         {
--            error = _("Reciprocal of zero is undefined");
-+            mperr (_("Reciprocal of zero is undefined"));
-             return new Number.integer (0);
-         }
- 
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.set_unsigned_integer (1, Round.NEAREST);
--        tmp.divide (tmp, re_num, Round.NEAREST);
--        var z = copy ();
--        z.re_num.clear ();
--        z.re_num = tmp;
--        return z;
-+        /* Start by approximating value using floating point */
-+        var t1 = copy ();
-+        t1.re_exponent = 0;
-+        t1 = new Number.double (1.0 / t1.to_double ());
-+        t1.re_exponent -= re_exponent;
-+
-+        var t = 3;
-+        var it0 = t;
-+        Number t2;
-+        while (true)
-+        {
-+            /* t1 = t1 - (t1 * ((x * t1) - 1))   (2*t1 - t1^2*x) */
-+            t2 = multiply (t1);
-+            t2 = t2.add (new Number.integer (-1));
-+            t2 = t1.multiply (t2);
-+            t1 = t1.subtract (t2);
-+            if (t >= T)
-+                break;
-+
-+            /*  FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE
-+             *  BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
-+             */
-+            var ts3 = t;
-+            var ts2 = 0;
-+            t = T;
-+            do
-+            {
-+                ts2 = t;
-+                t = (t + it0) / 2;
-+            } while (t > ts3);
-+            t = int.min (ts2, T);
-+        }
-+
-+        /* RETURN IF NEWTON ITERATION WAS CONVERGING */
-+        if (t2.re_sign != 0 && (t1.re_exponent - t2.re_exponent) << 1 < T - it0)
-+        {
-+            /*  THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
-+             *  OR THAT THE STARTING APPROXIMATION IS NOT ACCURATE ENOUGH.
-+             */
-+            mperr ("*** ERROR OCCURRED IN RECIPROCAL, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
-+        }
-+
-+        return t1;
-     }
- 
-+    private Number divide_integer_real (int64 y)
-+    {
-+        /* x/0 */
-+        if (y == 0)
-+        {
-+            /* Translators: Error displayed attempted to divide by zero */
-+            mperr (_("Division by zero is undefined"));
-+            return new Number.integer (0);
-+        }
- 
-+        /* 0/y = 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-+        /* Division by -1 or 1 just changes re_sign */
-+        if (y == 1 || y == -1)
-+        {
-+            if (y < 0)
-+                return invert_sign ();
-+            else
-+                return this;
-+        }
-+
-+        var z = new Number.integer (0);
-+        if (y < 0)
-+        {
-+            y = -y;
-+            z.re_sign = -re_sign;
-+        }
-+        else
-+            z.re_sign = re_sign;
-+        z.re_exponent = re_exponent;
-+
-+        int64 c = 0;
-+        int64 i = 0;
-+
-+        /*  IF y*B NOT REPRESENTABLE AS AN INTEGER HAVE TO SIMULATE
-+         *  LONG DIVISION.  ASSUME AT LEAST 16-BIT WORD.
-+         */
-+
-+        /* Computing MAX */
-+        var b2 = int.max (BASE << 3, 32767 / BASE);
-+        if (y < b2)
-+        {
-+            /* LOOK FOR FIRST NONZERO DIGIT IN QUOTIENT */
-+            int64 r1 = 0;
-+            do
-+            {
-+                c = BASE * c;
-+                if (i < T)
-+                    c += re_fraction[i];
-+                i++;
-+                r1 = c / y;
-+                if (r1 < 0)
-+                {
-+                    mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
-+                    return new Number.integer (0);
-+                }
-+            } while (r1 == 0);
-+
-+            /* ADJUST re_exponent AND GET T+4 DIGITS IN QUOTIENT */
-+            z.re_exponent += (int) (1 - i);
-+            z.re_fraction[0] = (int) r1;
-+            c = BASE * (c - y * r1);
-+            int64 kh = 1;
-+            if (i < T)
-+            {
-+                kh = T + 1 - i;
-+                for (var k = 1; k < kh; k++)
-+                {
-+                    c += re_fraction[i];
-+                    z.re_fraction[k] = (int) (c / y);
-+                    c = BASE * (c - y * z.re_fraction[k]);
-+                    i++;
-+                }
-+                if (c < 0)
-+                {
-+                    mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
-+                    return new Number.integer (0);
-+                }
-+            }
-+
-+            for (var k = kh; k < T + 4; k++)
-+            {
-+                z.re_fraction[k] = (int) (c / y);
-+                c = BASE * (c - y * z.re_fraction[k]);
-+            }
-+            if (c < 0)
-+            {
-+                mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
-+                return new Number.integer (0);
-+            }
-+
-+            mp_normalize (ref z);
-+            return z;
-+        }
-+
-+        /* HERE NEED SIMULATED DOUBLE-PRECISION DIVISION */
-+        var j1 = y / BASE;
-+        var j2 = y - j1 * BASE;
-+
-+        /* LOOK FOR FIRST NONZERO DIGIT */
-+        var c2 = 0;
-+        do
-+        {
-+            c = BASE * c + c2;
-+            c2 = i < T ? re_fraction[i] : 0;
-+            i++;
-+        } while (c < j1 || (c == j1 && c2 < j2));
-+
-+        /* COMPUTE T+4 QUOTIENT DIGITS */
-+        z.re_exponent += (int) (1 - i);
-+        i--;
-+
-+        /* MAIN LOOP FOR LARGE ABS (y) CASE */
-+        for (var k = 1; k <= T + 4; k++)
-+        {
-+            /* GET APPROXIMATE QUOTIENT FIRST */
-+            var ir = c / (j1 + 1);
-+
-+            /* NOW REDUCE SO OVERFLOW DOES NOT OCCUR */
-+            var iq = c - ir * j1;
-+            if (iq >= b2)
-+            {
-+                /* HERE IQ*B WOULD POSSIBLY OVERFLOW SO INCREASE IR */
-+                ir++;
-+                iq -= j1;
-+            }
-+
-+            iq = iq * BASE - ir * j2;
-+            if (iq < 0)
-+            {
-+                /* HERE IQ NEGATIVE SO IR WAS TOO LARGE */
-+                ir--;
-+                iq += y;
-+            }
-+
-+            if (i < T)
-+                iq += re_fraction[i];
-+            i++;
-+            var iqj = iq / y;
-+
-+            /* r (K) = QUOTIENT, C = REMAINDER */
-+            z.re_fraction[k - 1] = (int) (iqj + ir);
-+            c = iq - y * iqj;
-+
-+            if (c < 0)
-+            {
-+                /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
-+                mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
-+                return new Number.integer (0);
-+            }
-+        }
-+
-+        mp_normalize (ref z);
-+
-+        /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
-+        mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
-+        return new Number.integer (0);
-+    }
-+
-+
-+
-     private Number from_radians (AngleUnit unit)
-     {
-         switch (unit)
-@@ -1340,23 +2825,146 @@
-         }
-     }
- 
-+    /* z = sin (x) -1 >= x >= 1, do_sin = 1
-+     * z = cos (x) -1 >= x >= 1, do_sin = 0
-+     */
-+    private Number sin1 (bool do_sin)
-+    {
-+        /* sin (0) = 0, cos (0) = 1 */
-+        if (is_zero ())
-+        {
-+            if (do_sin)
-+                return new Number.integer (0);
-+            else
-+                return new Number.integer (1);
-+        }
-+
-+        var t2 = multiply (this);
-+        if (t2.compare (new Number.integer (1)) > 0)
-+            mperr ("*** ABS (X) > 1 IN CALL TO SIN1 ***");
-+
-+        Number t1;
-+        int i;
-+        Number z;
-+        if (do_sin)
-+        {
-+            t1 = this;
-+            z = t1;
-+            i = 2;
-+        }
-+        else
-+        {
-+            t1 = new Number.integer (1);
-+            z = new Number.integer (0);
-+            i = 1;
-+        }
-+
-+        /* Taylor series */
-+        /* POWER SERIES LOOP.  REDUCE T IF POSSIBLE */
-+        var b2 = 2 * int.max (BASE, 64);
-+        do
-+        {
-+            if (T + t1.re_exponent <= 0)
-+                break;
-+
-+            /*  IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
-+             *  DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
-+             */
-+            t1 = t2.multiply (t1);
-+            if (i > b2)
-+            {
-+                t1 = t1.divide_integer (-i);
-+                t1 = t1.divide_integer (i + 1);
-+            }
-+            else
-+                t1 = t1.divide_integer (-i * (i + 1));
-+            z = t1.add (z);
-+
-+            i += 2;
-+        } while (t1.re_sign != 0);
-+
-+        if (!do_sin)
-+            z = z.add (new Number.integer (1));
-+
-+        return z;
-+    }
-+
-+
-     private Number sin_real (AngleUnit unit)
-     {
-+        /* sin (0) = 0 */
-+        if (is_zero ())
-+            return new Number.integer (0);
-+
-         var x_radians = to_radians (unit);
--        var z = new Number.integer (0);
--        var tmp = z.re_num;
--        tmp.sin (x_radians.re_num, Round.NEAREST);
--        z.re_num = tmp;
-+
-+        var xs = x_radians.re_sign;
-+        x_radians = x_radians.abs ();
-+
-+        /* USE SIN1 IF ABS (X) <= 1 */
-+        Number z;
-+        if (x_radians.compare (new Number.integer (1)) <= 0)
-+            z = x_radians.sin1 (true);
-+        /* FIND ABS (X) MODULO 2PI */
-+        else
-+        {
-+            z = new Number.pi ().divide_integer (4);
-+            x_radians = x_radians.divide (z);
-+            x_radians = x_radians.divide_integer (8);
-+            x_radians = x_radians.fractional_component ();
-+
-+            /* SUBTRACT 1/2, SAVE re_sign AND TAKE ABS */
-+            x_radians = x_radians.add (new Number.fraction (-1, 2));
-+            xs = -xs * x_radians.re_sign;
-+            if (xs == 0)
-+                return new Number.integer (0);
-+
-+            x_radians.re_sign = 1;
-+            x_radians = x_radians.multiply_integer (4);
-+
-+            /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
-+            if (x_radians.re_exponent > 0)
-+                x_radians = x_radians.add (new Number.integer (-2));
-+
-+            if (x_radians.is_zero ())
-+                return new Number.integer (0);
-+
-+            x_radians.re_sign = 1;
-+            x_radians = x_radians.multiply_integer (2);
-+
-+            /*  NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
-+             *  POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
-+             */
-+            if (x_radians.re_exponent > 0)
-+            {
-+                x_radians = x_radians.add (new Number.integer (-2));
-+                x_radians = x_radians.multiply (z);
-+                z = x_radians.sin1 (false);
-+            }
-+            else
-+            {
-+                x_radians = x_radians.multiply (z);
-+                z = x_radians.sin1 (true);
-+            }
-+        }
-+
-+        z.re_sign = xs;
-         return z;
-     }
- 
-     private Number cos_real (AngleUnit unit)
-     {
--        var x_radians = to_radians (unit);
--        var tmp = MPFloat.init2 ((Precision) precision);
--        tmp.cos (x_radians.re_num, Round.NEAREST);
--        var z = new Number.mpfloat (tmp);
--        return z;
-+        /* cos (0) = 1 */
-+        if (is_zero ())
-+            return new Number.integer (1);
-+
-+        /* Use power series if |x| <= 1 */
-+        var z = to_radians (unit).abs ();
-+        if (z.compare (new Number.integer (1)) <= 0)
-+            return z.sin1 (false);
-+        else
-+            /* cos (x) = sin (π/2 - |x|) */
-+            return new Number.pi ().divide_integer (2).subtract (z).sin (AngleUnit.RADIANS);
-     }
- 
-     private Number bitwise (Number y, BitwiseFunc bitwise_operator, int wordlen)
-@@ -1370,7 +2978,7 @@
-             offset_out = offset1 > offset2 ? offset1 : offset2;
-         if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2))
-         {
--            error = ("Overflow. Try a bigger word size");
-+            mperr ("Overflow. Try a bigger word size");
-             return new Number.integer (0);
-         }
- 
-@@ -1420,6 +3028,29 @@
- 
- // FIXME: Re-add overflow and underflow detection
- 
-+static string? mp_error = null;
-+
-+/*  THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
-+ *  AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
-+ */
-+public void mperr (string text)
-+{
-+    mp_error = text;
-+}
-+
-+/* Returns error string or null if no error */
-+// FIXME: Global variable
-+public string mp_get_error ()
-+{
-+    return mp_error;
-+}
-+
-+/* Clear any current error */
-+public void mp_clear_error ()
-+{
-+    mp_error = null;
-+}
-+
- /* Sets z from a string representation in 'text'. */
- public Number? mp_set_from_string (string str, int default_base = 10)
- {
-@@ -1468,7 +3099,6 @@
- 
-     /* Convert integer part */
-     var z = new Number.integer (0);
--
-     while (str.get_next_char (ref index, out c))
-     {
-         var i = char_val (c, number_base);
-@@ -1600,6 +3230,73 @@
-         return null;
- }
- 
-+/*  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
-+ */
-+public void mp_gcd (ref int64 k, ref int64 l)
-+{
-+    var i = k.abs ();
-+    var j = l.abs ();
-+    if (j == 0)
-+    {
-+        /* IF J = 0 RETURN (1, 0) UNLESS I = 0, THEN (0, 0) */
-+        k = 1;
-+        l = 0;
-+        if (i == 0)
-+            k = 0;
-+        return;
-+    }
-+
-+    /* EUCLIDEAN ALGORITHM LOOP */
-+    do
-+    {
-+        i %= j;
-+        if (i == 0)
-+        {
-+            k = k / j;
-+            l = l / j;
-+            return;
-+        }
-+        j %= i;
-+    } while (j != 0);
-+
-+    /* HERE J IS THE GCD OF K AND L */
-+    k = k / i;
-+    l = l / i;
-+}
-+
-+// FIXME: Is r.re_fraction large enough?  It seems to be in practise but it may be T+4 instead of 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)
-+public void mp_normalize (ref Number x)
-+{
-+    int start_index;
-+
-+    /* Find first non-zero digit */
-+    for (start_index = 0; start_index < SIZE && x.re_fraction[start_index] == 0; start_index++);
-+
-+    /* Mark as zero */
-+    if (start_index >= SIZE)
-+    {
-+        x.re_sign = 0;
-+        x.re_exponent = 0;
-+        return;
-+    }
-+
-+    /* Shift left so first digit is non-zero */
-+    if (start_index > 0)
-+    {
-+        x.re_exponent -= start_index;
-+        var i = 0;
-+        for (; (i + start_index) < SIZE; i++)
-+            x.re_fraction[i] = x.re_fraction[i + start_index];
-+        for (; i < SIZE; i++)
-+            x.re_fraction[i] = 0;
-+    }
-+}
-+
- /* Returns true if x is cannot be represented in a binary word of length 'wordlen' */
- public bool mp_is_overflow (Number x, int wordlen)
- {
-
---- gnome-calculator-3.18.2/configure.ac	2016-08-09 14:02:40.743464258 +0000
-+++ gnome-calculator-3.18.2/configure.ac	2016-08-09 14:02:52.623794159 +0000
-@@ -25,9 +25,6 @@
- 
- AC_SUBST([GLIB_REQUIRED])
- 
--# FIXME We link to it too, so this check needs to be better....
--AC_CHECK_HEADER([mpfr.h], [], [AC_MSG_ERROR([The mpfr header is missing. Please, install mpfr])])
--
- PKG_CHECK_MODULES(LIBCALCULATOR, [
-     glib-2.0 >= $GLIB_REQUIRED
-     gio-2.0 >= $GLIB_REQUIRED