[gnome-calculator] Use MPC for complex numbers



commit 476df143a6c31e52fc52ef266b84d0c6ee8ce0b3
Author: Phillip Wood <phillip wood dunelm org uk>
Date:   Thu Jan 14 12:24:14 2016 +0000

    Use MPC for complex numbers
    
    MPC is a library for complex numbers built on top of MPFR. Using it
    fixes a number of issues with GNOME Calculators incomplete support for
    complex numbers and simplifies the implementation of a number of
    functions.
    
    Thanks to Daniel Renninghoff this commit also reworks the MPFR bindings
    to use vala's automatic memory management. I've added a default rounding
    mode which makes the calling code cleaner.
    
    The use of MPFR.RealRef is not ideal but there doesn't seem to be a
    better way to deal with references to structs in vala.
    
    The lvalue_allowed = false annotation is necessary to make MPC.abs() and
    MPC.arg() work, otherwise vala stores the result in a copy of the target
    variable.
    
    The bindings for MPC and MPFR.RealRef are licensed GPL3+ as MPFR and
    MPC are LGPL3 so it doesn't make sense to license them as GPL2+ as the
    GPL2 is incompatible with LGPL3
    
    https://bugzilla.gnome.org/show_bug.cgi?id=759439

 configure.ac       |    1 +
 lib/Makefile.am    |    5 +-
 lib/mpc.vapi       |  123 +++++++++
 lib/mpfr-glue.vala |   28 ++
 lib/mpfr.vapi      |  123 ++++-----
 lib/number.vala    |  747 +++++++++++++++-------------------------------------
 6 files changed, 432 insertions(+), 595 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index f31f829..ac8f412 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,6 +28,7 @@ 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])])
+AC_CHECK_HEADER([mpc.h], [], [AC_MSG_ERROR([The mpc header is missing. Please, install mpc])])
 
 PKG_CHECK_MODULES(LIBCALCULATOR, [
     glib-2.0 >= $GLIB_REQUIRED
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 95634e7..6191dd6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,6 +7,8 @@ AM_CPPFLAGS = \
 
 libcalculator_la_SOURCES = \
        mpfr.vapi \
+       mpfr-glue.vala \
+       mpc.vapi \
        currency.vala \
        equation.vala \
        equation-lexer.vala \
@@ -35,7 +37,8 @@ libcalculator_la_LIBADD = \
        $(LIBCALCULATOR_LIBS) \
        -lgmp \
        -lm \
-       -lmpfr
+       -lmpfr \
+       -lmpc
 
 EXTRA_DIST = \
        libcalculator.h \
diff --git a/lib/mpc.vapi b/lib/mpc.vapi
new file mode 100644
index 0000000..d34521b
--- /dev/null
+++ b/lib/mpc.vapi
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Phillip Wood <phillip wood dunelm org uk>
+ *
+ * GNOME Calculator - mpc.vapi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Phillip Wood <phillip wood dunelm org uk>
+ */
+
+[CCode (cheader_filename="mpc.h")]
+namespace MPC {
+    [CCode (cname = "mpc_rnd_t", has_type_id = false)]
+    public enum Round {
+        [CCode (cname = "MPC_RNDNN")]
+        NEAREST,
+        [CCode (cname = "MPC_RNDZZ")]
+        ZERO,
+        [CCode (cname = "MPC_RNDUU")]
+        UP,
+        [CCode (cname = "MPC_RNDDD")]
+        DOWN
+    }
+
+    [CCode (cname="MPC_INEX_RE")]
+    public int inex_re (int inex);
+    [CCode (cname="MPC_INEX_IM")]
+    public int inex_im (int inex);
+    [CCode (cname="MPC_INEX1")]
+    public int inex1 (int inex);
+    [CCode (cname="MPC_INEX2")]
+    public int inex2 (int inex);
+
+    public int abs (MPFR.Real res, Complex op, MPFR.Round rnd = MPFR.Round.NEAREST);
+    public int arg (MPFR.Real res, Complex op, MPFR.Round rnd = MPFR.Round.NEAREST);
+
+    [CCode (cname = "__mpc_struct", cprefix = "mpc_", destroy_function = "mpc_clear", copy_function = "", 
lvalue_access = false, has_type_id = false)]
+    public struct Complex {
+        [CCode (cname="mpc_init2")]
+        public Complex (MPFR.Precision prec);
+        public int @set (Complex op, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_set_ui_ui")]
+        public int set_unsigned_integer (ulong re, ulong im = 0, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_set_si_si")]
+        public int set_signed_integer (long re, long im = 0, Round rnd = Round.NEAREST);
+        private int set_fr (MPFR.Real re, Round rnd);
+        private int set_fr_fr (MPFR.Real re, MPFR.Real im, Round rnd);
+        public int set_mpreal (MPFR.Real re, MPFR.Real? im = null, Round rnd = Round.NEAREST)
+        {
+            if (im == null)
+                return set_fr (re, rnd);
+
+            return set_fr_fr (re, im, rnd);
+        }
+        [CCode (cname="mpc_set_d_d")]
+        public int set_double (double re, double im = 0, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_realref")]
+        public unowned MPFR.RealRef get_real ();
+        [CCode (cname="mpc_imagref")]
+        public unowned MPFR.RealRef get_imag ();
+        public bool is_zero () { var res = cmp_si_si (0, 0); return inex_re (res) == 0 && inex_im (res) == 
0; }
+        public bool is_equal (Complex c) { var res = cmp (c); return inex_re (res) == 0 && inex_im (res) == 
0; }
+        public int cmp (Complex op2);
+        public int cmp_si_si (long re, long im);
+        public int conj (Complex op, Round rnd = Round.NEAREST);
+        public int sqrt (Complex op, Round rnd = Round.NEAREST);
+        public int neg (Complex op, Round rnd = Round.NEAREST);
+        public int add (Complex op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_sub")]
+        public int subtract (Complex op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_mul")]
+        public int multiply (Complex op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_div")]
+        public int divide (Complex op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_pow_si")]
+        public int power_signed_integer (Complex op1, long op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_mul_si")]
+        public int multiply_signed_integer (Complex op1, long op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_mul_fr")]
+        public int multiply_mpreal (Complex op1, MPFR.Real op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_div_ui")]
+        public int divide_unsigned_integer (Complex op1, ulong op2, Round rnd = Round.NEAREST);
+        // Divide a uint by a complex
+        [CCode (cname="mpc_ui_div")]
+        public int unsigned_integer_divide (ulong op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_div_fr")]
+        public int divide_mpreal (Complex op1, MPFR.Real op2, Round rnd = Round.NEAREST);
+        // Divide a real by a complex
+        [CCode (cname="mpc_fr_div")]
+        public int mpreal_divide (MPFR.Real op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_pow")]
+        public int power (Complex op1, Complex op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_pow_si")]
+        public int power_integer (Complex op1, long op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpc_pow_fr")]
+        public int power_mpreal (Complex op1, MPFR.Real op2, Round rnd = Round.NEAREST);
+        public int exp (Complex op, Round rnd = Round.NEAREST);
+        public int log (Complex op, Round rnd = Round.NEAREST);
+        public int sin (Complex op, Round rnd = Round.NEAREST);
+        public int cos (Complex op, Round rnd = Round.NEAREST);
+        public int tan (Complex op, Round rnd = Round.NEAREST);
+        public int asin (Complex op, Round rnd = Round.NEAREST);
+        public int acos (Complex op, Round rnd = Round.NEAREST);
+        public int atan (Complex op, Round rnd = Round.NEAREST);
+        public int sinh (Complex op, Round rnd = Round.NEAREST);
+        public int cosh (Complex op, Round rnd = Round.NEAREST);
+        public int tanh (Complex op, Round rnd = Round.NEAREST);
+        public int asinh (Complex op, Round rnd = Round.NEAREST);
+        public int acosh (Complex op, Round rnd = Round.NEAREST);
+        public int atanh (Complex op, Round rnd = Round.NEAREST);
+    }
+}
diff --git a/lib/mpfr-glue.vala b/lib/mpfr-glue.vala
new file mode 100644
index 0000000..e52c0f6
--- /dev/null
+++ b/lib/mpfr-glue.vala
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 Phillip Wood <phillip wood dunelm org uk>
+ *
+ * GNOME Calculator - mpfr-glue.vala
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Phillip Wood <phillip wood dunelm org uk>
+ */
+
+namespace MPFR
+{
+    [Compact]
+    public class RealRef {
+        public MPFR.Real val;
+    }
+}
diff --git a/lib/mpfr.vapi b/lib/mpfr.vapi
index 5baa4de..ec48491 100644
--- a/lib/mpfr.vapi
+++ b/lib/mpfr.vapi
@@ -8,23 +8,10 @@
  * license.
  */
 
-/* A small guide on using MPFR with gnome-calculator:
- * Using it is pretty much self-explanatory when you look at the code in
- * number.vala.
- * C syntax: mpfr_add (result, op1, op2, MPFR_RNDN);
- * Vala syntax: result.add (op1, op2, Round.NEAREST);
- *
- * The result has to be initialized with init2() before using it (same in C).
- * Since MPFR is a C library you have to do manual memory management. This means
- * that after init2()ing something, you have to clear() it at the end. Clearing
- * re_num and im_num is taken are of by the destructor of Number. Just make sure
- * to manually clear any temporary helper variables you use.
- */
-
 [CCode (cheader_filename="mpfr.h")]
 namespace MPFR {
     [SimpleType]
-    [IntegerType]
+    [IntegerType (rank = 9)]
     [CCode (cname = "mpfr_prec_t", has_type_id = false)]
     public struct Precision {}
 
@@ -46,83 +33,87 @@ namespace MPFR {
         NEARESTAWAY
     }
 
-    [CCode (cname = "__mpfr_struct", cprefix = "mpfr_", has_destroy_function = false, copy_function = "", 
has_type_id = false)]
-    public struct MPFloat {
+    [CCode (cname = "__mpfr_struct", cprefix = "mpfr_", destroy_function = "mpfr_clear", copy_function = "", 
lvalue_access = false, has_type_id = false)]
+    public struct Real {
         [CCode (cname="mpfr_init2")]
-        public MPFloat.init2 (Precision prec);
-
+        public Real (Precision prec);
+        public Precision get_precision ();
         [CCode (cname="mpfr_set_ui")]
-        public int set_unsigned_integer (ulong op, Round rnd);
+        public int set_unsigned_integer (ulong op, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_set_si")]
-        public int set_signed_integer (long op, Round rnd);
+        public int set_signed_integer (long op, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_set_flt")]
-        public int set_float (float op, Round rnd);
+        public int set_float (float op, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_set_d")]
-        public int set_double (double op, Round rnd);
+        public int set_double (double op, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_set")]
-        public int set (MPFloat op, Round rnd);
-
-        public void clear ();
-
-        public int add (MPFloat op1, MPFloat op2, Round rnd);
+        public int set (Real op, Round rnd = Round.NEAREST);
+        public int set_zero (Round rnd = Round.NEAREST);
+        public int add (Real op1, Real op2, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_sub")]
-        public int subtract (MPFloat op1, MPFloat op2, Round rnd);
+        public int subtract (Real op1, Real op2, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_mul")]
-        public int multiply (MPFloat op1, MPFloat op2, Round rnd);
+        public int multiply (Real op1, Real op2, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_div")]
-        public int divide (MPFloat op1, MPFloat op2, Round rnd);
+        public int divide (Real op1, Real op2, Round rnd = Round.NEAREST);
 
         [CCode (cname="mpfr_get_si")]
-        public long get_signed_integer (Round rnd);
+        public long get_signed_integer (Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_get_ui")]
-        public ulong get_unsigned_integer (Round rnd);
+        public ulong get_unsigned_integer (Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_get_flt")]
-        public float get_float (Round rnd);
+        public float get_float (Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_get_d")]
-        public double get_double (Round rnd);
+        public double get_double (Round rnd = Round.NEAREST);
 
-        public int const_pi (Round rnd);
+        public int const_pi (Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_zero_p")]
         public bool is_zero ();
         public int sgn ();
         [CCode (cname="mpfr_equal_p")]
-        public bool is_equal (MPFloat op2);
-        public int cmp (MPFloat op2);
-        public int sqrt (MPFloat op, Round rnd);
-        public int neg (MPFloat op, Round rnd);
+        public bool is_equal (Real op2);
+        public int cmp (Real op2);
+        public int sqrt (Real op, Round rnd = Round.NEAREST);
+        public int neg (Real op, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_pow_si")]
-        public int power_signed_integer (MPFloat op1, long op2, Round rnd);
+        public int power_signed_integer (Real op1, long op2, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_mul_si")]
-        public int multiply_signed_integer (MPFloat op1, long op2, Round rnd);
+        public int multiply_signed_integer (Real op1, long op2, Round rnd = Round.NEAREST);
         [CCode (cname="mpfr_div_si")]
-        public int divide_signed_integer (MPFloat op1, long op2, Round rnd);
-        public int floor (MPFloat op);
+        public int divide_signed_integer (Real op1, long op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpfr_si_div")]
+        public int signed_integer_divide (long op1, Real op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpfr_div_ui")]
+        public int divide_unsigned_integer (Real op1, ulong op2, Round rnd = Round.NEAREST);
+        [CCode (cname="mpfr_ui_div")]
+        public int unsigned_integer_divide (ulong op1, Real op2, Round rnd = Round.NEAREST);
+        public int floor (Real op);
         [CCode (cname="mpfr_pow")]
-        public int power (MPFloat op1, MPFloat op2, Round rnd);
-        public int exp (MPFloat op, Round rnd);
-        public int log (MPFloat op, Round rnd);
-        public int sin (MPFloat op, Round rnd);
-        public int cos (MPFloat op, Round rnd);
-        public int tan (MPFloat op, Round rnd);
-        public int asin (MPFloat op, Round rnd);
-        public int acos (MPFloat op, Round rnd);
-        public int atan (MPFloat op, Round rnd);
-        public int sinh (MPFloat op, Round rnd);
-        public int cosh (MPFloat op, Round rnd);
-        public int tanh (MPFloat op, Round rnd);
-        public int asinh (MPFloat op, Round rnd);
-        public int acosh (MPFloat op, Round rnd);
-        public int atanh (MPFloat op, Round rnd);
-        public int abs (MPFloat op, Round rnd);
-        public int root (MPFloat op, ulong k, Round rnd);
-        public int rint (MPFloat op, Round rnd);
-        public int frac (MPFloat op, Round rnd);
-        public int ceil (MPFloat op);
-        public int trunc (MPFloat op);
-        public int round (MPFloat op);
+        public int power (Real op1, Real op2, Round rnd = Round.NEAREST);
+        public int exp (Real op, Round rnd = Round.NEAREST);
+        public int log (Real op, Round rnd = Round.NEAREST);
+        public int sin (Real op, Round rnd = Round.NEAREST);
+        public int cos (Real op, Round rnd = Round.NEAREST);
+        public int tan (Real op, Round rnd = Round.NEAREST);
+        public int asin (Real op, Round rnd = Round.NEAREST);
+        public int acos (Real op, Round rnd = Round.NEAREST);
+        public int atan (Real op, Round rnd = Round.NEAREST);
+        public int sinh (Real op, Round rnd = Round.NEAREST);
+        public int cosh (Real op, Round rnd = Round.NEAREST);
+        public int tanh (Real op, Round rnd = Round.NEAREST);
+        public int asinh (Real op, Round rnd = Round.NEAREST);
+        public int acosh (Real op, Round rnd = Round.NEAREST);
+        public int atanh (Real op, Round rnd = Round.NEAREST);
+        public int abs (Real op, Round rnd = Round.NEAREST);
+        public int root (Real op, ulong k, Round rnd = Round.NEAREST);
+        public int rint (Real op, Round rnd = Round.NEAREST);
+        public int frac (Real op, Round rnd = Round.NEAREST);
+        public int ceil (Real op);
+        public int trunc (Real op);
+        public int round (Real op);
         [CCode (cname="mpfr_integer_p")]
         public int is_integer ();
-        public int gamma (MPFloat op, Round rnd);
+        public int gamma (Real op, Round rnd = Round.NEAREST);
     }
 
     [CCode (cname = "mpfr_underflow_p")]
diff --git a/lib/number.vala b/lib/number.vala
index bab6afc..8dc72d0 100644
--- a/lib/number.vala
+++ b/lib/number.vala
@@ -27,7 +27,7 @@
  *  THE MP USERS GUIDE.
  */
 
-using MPFR;
+using MPC;
 
 private delegate int BitwiseFunc (int v1, int v2);
 
@@ -42,32 +42,21 @@ public enum AngleUnit
 public class Number : Object
 {
     /* real and imaginary part of a Number */
-    private MPFloat re_num { get; set; }
-    private MPFloat im_num { get; set; }
+    private Complex num = Complex (precision);
 
-    public static ulong precision { get; set; default = 1000; }
+    public static MPFR.Precision precision { get; set; default = 1000; }
 
     /* Stores the error msg if an error occurs during calculation. Otherwise should be null */
     public static string? error { get; set; default = null; }
 
-    public Number.integer (int64 value)
+    public Number.integer (int64 real, int64 imag = 0)
     {
-        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;
+        num.set_signed_integer ((long) real, (long) imag);
     }
 
-    public Number.unsigned_integer (uint64 x)
+    public Number.unsigned_integer (uint64 real, uint64 imag = 0)
     {
-        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;
+        num.set_unsigned_integer ((ulong) real, (ulong) imag);
     }
 
     public Number.fraction (int64 numerator, int64 denominator)
@@ -81,39 +70,24 @@ public class Number : Object
         Number.integer (numerator);
         if (denominator != 1)
         {
-            var tmp = re_num;
-            tmp.divide_signed_integer (re_num, (long) denominator, Round.NEAREST);
-            re_num = tmp;
+            num.divide_unsigned_integer (num, (long) denominator);
         }
     }
 
-    /* Helper constructor. Creates new Number from already existing MPFloat. */
-    public Number.mpfloat (MPFloat value)
+    /* Helper constructor. Creates new Number from already existing MPFR.Real. */
+    public Number.mpreal (MPFR.Real real, MPFR.Real? imag = null)
     {
-        re_num = value;
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.set_unsigned_integer (0, Round.NEAREST);
-        im_num = tmp;
+        num.set_mpreal (real, imag);
     }
 
-    public Number.double (double value)
+    public Number.double (double real, double imag = 0)
     {
-        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;
+        num.set_double (real, imag);
     }
 
-    public Number.complex (Number x, Number y)
+    public Number.complex (Number r, Number i)
     {
-        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;
+        num.set_mpreal (r.num.get_real ().val, i.num.get_real ().val);
     }
 
     public Number.polar (Number r, Number theta, AngleUnit unit = AngleUnit.RADIANS)
@@ -125,35 +99,21 @@ public class Number : Object
 
     public Number.eulers ()
     {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        var tmp2 = MPFloat.init2 ((Precision) precision);
-        tmp2.set_unsigned_integer (1, Round.NEAREST);
+        num.get_real ().val.set_unsigned_integer (1);
         /* 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;
+        num.get_real ().val.exp (num.get_real ().val);
+        num.get_imag ().val.set_zero ();
     }
 
     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;
+        num.set_signed_integer (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;
+        num.get_real ().val.const_pi ();
+        num.get_imag ().val.set_zero ();
     }
 
     /* Sets z to be a uniform random number in the range [0, 1] */
@@ -162,42 +122,36 @@ public class Number : Object
         Number.double (Random.next_double ());
     }
 
-    ~Number ()
-    {
-        re_num.clear ();
-        im_num.clear ();
-    }
-
     public int64 to_integer ()
     {
-        return re_num.get_signed_integer (Round.NEAREST);
+        return num.get_real ().val.get_signed_integer ();
     }
 
     public uint64 to_unsigned_integer ()
     {
-        return re_num.get_unsigned_integer (Round.NEAREST);
+        return num.get_real ().val.get_unsigned_integer ();
     }
 
     public float to_float ()
     {
-        return re_num.get_float (Round.NEAREST);
+        return num.get_real ().val.get_float (MPFR.Round.NEAREST);
     }
 
     public double to_double ()
     {
-        return re_num.get_double (Round.NEAREST);
+        return num.get_real ().val.get_double (MPFR.Round.NEAREST);
     }
 
     /* Return true if the value is x == 0 */
     public bool is_zero ()
     {
-        return re_num.is_zero () && im_num.is_zero ();
+        return num.is_zero ();
     }
 
     /* Return true if x < 0 */
     public bool is_negative ()
     {
-        return re_num.sgn () < 0;
+        return num.get_real ().val.sgn () < 0;
     }
 
     /* Return true if x is integer */
@@ -206,7 +160,7 @@ public class Number : Object
         if (is_complex ())
             return false;
 
-        return re_num.is_integer () != 0;
+        return num.get_real ().val.is_integer () != 0;
     }
 
     /* Return true if x is a positive integer */
@@ -215,7 +169,7 @@ public class Number : Object
         if (is_complex ())
             return false;
         else
-            return re_num.sgn () >= 0 && is_integer ();
+            return num.get_real ().val.sgn () >= 0 && is_integer ();
     }
 
     /* Return true if x is a natural number (an integer ≥ 0) */
@@ -224,24 +178,24 @@ public class Number : Object
         if (is_complex ())
             return false;
         else
-            return re_num.sgn () > 0 && is_integer ();
+            return num.get_real ().val.sgn () > 0 && is_integer ();
     }
 
     /* Return true if x has an imaginary component */
     public bool is_complex ()
     {
-        return !im_num.is_zero ();
+        return !num.get_imag ().val.is_zero ();
     }
 
     /* Return error if overflow or underflow */
     public static void check_flags ()
     {
-        if (mpfr_is_underflow () != 0)
+        if (MPFR.mpfr_is_underflow () != 0)
         {
             /* Translators: Error displayed when underflow error occured */
             error = _("Underflow error");
         }
-        else if (mpfr_is_overflow () != 0)
+        else if (MPFR.mpfr_is_overflow () != 0)
         {
             /* Translators: Error displayed when overflow error occured */
             error = _("Overflow error");
@@ -251,7 +205,7 @@ public class Number : Object
     /* Return true if x == y */
     public bool equals (Number y)
     {
-        return re_num.is_equal (y.re_num);
+        return num.is_equal (y.num);
     }
 
     /* Returns:
@@ -261,48 +215,31 @@ public class Number : Object
      */
     public int compare (Number y)
     {
-        return re_num.cmp (y.re_num);
+        return num.get_real ().val.cmp (y.num.get_real ().val);
     }
 
     /* Sets z = sgn (x) */
     public Number sgn ()
     {
-        var z = new Number.integer (re_num.sgn ());
+        var z = new Number.integer (num.get_real ().val.sgn ());
         return z;
     }
 
     /* 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 = new Number ();
+        z.num.neg (num);
         return z;
     }
 
     /* Sets z = |x| */
     public Number abs ()
     {
-        if (is_complex ())
-        {
-            var x_real = real_component ();
-            var x_im = imaginary_component ();
-
-            x_real = x_real.multiply (x_real);
-            x_im = x_im.multiply (x_im);
-            var z = x_real.add (x_im);
-            return z.sqrt ();
-        }
-        else
-        {
-            var tmp = MPFloat.init2 ((Precision) precision);
-            tmp.abs (re_num, Round.NEAREST);
-            var z = new Number.mpfloat (tmp);
-            return z;
-        }
+      var z = new Number ();
+      z.num.get_imag ().val.set_zero ();
+      MPC.abs (z.num.get_real ().val, num);
+      return z;
     }
 
     /* Sets z = Arg (x) */
@@ -314,65 +251,33 @@ public class Number : Object
             error = _("Argument not defined for zero");
             return new Number.integer (0);
         }
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        MPC.arg (z.num.get_real ().val, num);
+        mpc_from_radians (z.num, z.num, unit);
+        // MPC returns -π for the argument of negative real numbers if
+        // their imaginary part is -0 (which it is in the numbers
+        // created by test-equation), we want +π for all real negative
+        // numbers
+        if (!is_complex () && is_negative ())
+            z.num.get_real ().val.abs (z.num.get_real ().val);
 
-        var x_real = real_component ();
-        var x_im = imaginary_component ();
-        var pi = new Number.pi ();
-
-        Number z;
-        if (x_im.is_zero ())
-        {
-            if (x_real.is_negative ())
-                z = pi;
-            else
-                return new Number.integer (0);
-        }
-        else if (x_real.is_zero ())
-        {
-            if (x_im.is_negative ())
-                z = pi.divide_integer (-2);
-            else
-                z = pi.divide_integer (2);
-        }
-        else if (x_real.is_negative ())
-        {
-            z = x_im.divide (x_real);
-            z = z.atan (AngleUnit.RADIANS);
-            if (x_im.is_negative ())
-                z = z.subtract (pi);
-            else
-                z = z.add (pi);
-        }
-        else
-        {
-            z = x_im.divide (x_real);
-            z = z.atan (AngleUnit.RADIANS);
-        }
-
-        return z.from_radians (unit);
+        return z;
     }
 
     /* 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;
+        var z = new Number ();
+        z.num.conj (num);
         return z;
     }
 
     /* Sets z = Re (x) */
     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;
+        var z = new Number ();
+        z.num.set_mpreal (num.get_real ().val);
         return z;
     }
 
@@ -380,30 +285,25 @@ public class Number : Object
     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.num.set_mpreal (num.get_imag ().val);
         return z;
     }
 
     public Number integer_component ()
     {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.trunc (re_num);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        z.num.get_real ().val.trunc (num.get_real ().val);
         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);
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        z.num.get_real ().val.frac (num.get_real ().val);
         return z;
     }
 
@@ -416,67 +316,45 @@ public class Number : Object
     /* Sets z = ⌊x⌋ */
     public Number floor ()
     {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.floor (re_num);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        z.num.get_real ().val.floor (num.get_real ().val);
         return z;
     }
 
     /* Sets z = ⌈x⌉ */
     public Number ceiling ()
     {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.ceil (re_num);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        z.num.get_real ().val.ceil (num.get_real ().val);
         return z;
     }
 
     /* Sets z = [x] */
     public Number round ()
     {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.round (re_num);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.get_imag ().val.set_zero ();
+        z.num.get_real ().val.round (num.get_real ().val);
         return z;
     }
 
     /* Sets z = 1 ÷ x */
     public Number reciprocal ()
     {
-        if (is_complex ())
-        {
-            var real_x = real_component ();
-            var im_x = imaginary_component ();
-
-            /* 1/(a+bi) = (a-bi)/(a+bi)(a-bi) = (a-bi)/(a²+b²) */
-            var t1 = real_x.multiply (real_x);
-            var t2 = im_x.multiply (im_x);
-            t1 = t1.add (t2);
-            var z = t1.reciprocal_real ();
-            return conjugate ().multiply (z);
-        }
-        else
-            return reciprocal_real ();
+        var z = new Number ();
+        z.num.set_signed_integer (1);
+        z.num.mpreal_divide (z.num.get_real ().val, num);
+        return z;
     }
 
     /* Sets z = e^x */
     public Number epowy ()
     {
-
-        /* e^0 = 1 */
-        if (is_zero ())
-            return new Number.integer (1);
-
-        if (is_complex ())
-        {
-            var x_real = real_component ();
-            var theta = imaginary_component ();
-
-            var r = x_real.epowy_real ();
-            return new Number.polar (r, theta);
-        }
-        else
-            return epowy_real ();
+        var z = new Number ();
+        z.num.exp (num);
+        return z;
     }
 
     /* Sets z = x^y */
@@ -497,43 +375,15 @@ public class Number : Object
             error = _("Zero raised to zero is undefined");
             return new Number.integer (0);
         }
-
-        /* base or exponent are complex */
-        if (is_complex () || y.is_complex ())
-        {
-            return pwr (y);
-        }
-
-        if (!y.is_integer ())
+        if (!is_complex () && !y.is_complex () && !y.is_integer ())
         {
             var reciprocal = y.reciprocal ();
-            if (reciprocal.is_integer () && !reciprocal.is_negative())
+            if (reciprocal.is_integer ())
                 return root (reciprocal.to_integer ());
-            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;
+        var z = new Number ();
+        z.num.power (num, y.num);
         return z;
     }
 
@@ -555,75 +405,39 @@ public class Number : Object
             error = _("Zero raised to zero is undefined");
             return new Number.integer (0);
         }
-
-        Number t;
-        if (n < 0)
-        {
-            t = reciprocal ();
-            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;
+        var z = new Number ();
+        z.num.power_integer (num, (long) n);
         return z;
     }
 
-    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.is_negative ())
-                error = _("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 ();
-    }
-
     /* Sets z = n√x */
     public Number root (int64 n)
     {
-        if (!is_complex () && is_negative () && n % 2 == 1)
+        uint64 p;
+        var z = new Number ();
+        if (n < 0)
         {
-            var z = abs ();
-            z = z.root_real (n);
-            z = z.invert_sign ();
-            return z;
+            z.num.unsigned_integer_divide (1, num);
+            if (n == int64.MIN)
+                p = (uint64) int64.MAX + 1;
+            else
+                p = -n;
+        } else {
+            z.num.@set (num);
+            p = n;
         }
-        else if (is_complex () || is_negative ())
-        {
-            var r = abs ();
-            var theta = arg ();
 
-            r = r.root_real (n);
-            theta = theta.divide_integer (n);
-            return new Number.polar (r, theta);
+        if (!is_complex () && (!is_negative () || (p & 1) == 1))
+        {
+            z.num.get_real ().val.root (z.num.get_real ().val, (ulong) p);
+            z.num.get_imag().val.set_zero();
+        } else {
+            var tmp = MPFR.Real (precision);
+            tmp.set_unsigned_integer ((ulong) p);
+            tmp.unsigned_integer_divide (1, tmp);
+            z.num.power_mpreal (z.num, tmp);
         }
-        else
-            return root_real (n);
+        return z;
     }
 
     /* Sets z = √x */
@@ -652,17 +466,15 @@ public class Number : Object
             return new Number.integer (0);
         }*/
 
-        if (is_complex () || is_negative ())
-        {
-            /* ln (re^iθ) = e^(ln (r)+iθ) */
-            var r = abs ();
-            var theta = arg ();
-            var z_real = r.ln_real ();
+        var z = new Number ();
+        z.num.log (num);
+        // MPC returns -π for the imaginary part of the log of
+        // negative real numbers if their imaginary part is -0 (which
+        // it is in the numbers created by test-equation), we want +π
+        if (!is_complex () && is_negative ())
+            z.num.get_imag ().val.abs (z.num.get_imag ().val);
 
-            return new Number.complex (z_real, theta);
-        }
-        else
-            return ln_real ();
+        return z;
     }
 
     /* Sets z = log_n x */
@@ -699,12 +511,12 @@ public class Number : Object
             }
 
             var tmp = add (new Number.integer (1));
-            var tmp2 = MPFloat.init2 ((Precision) precision);
+            var tmp2 = MPFR.Real (precision);
 
             /* Factorial(x) = Gamma(x+1) - This is the formula used to calculate Factorial.*/
-            tmp2.gamma (tmp.re_num, Round.NEAREST);
+            tmp2.gamma (tmp.num.get_real ().val);
 
-            return new Number.mpfloat (tmp2);
+            return new Number.mpreal (tmp2);
         }
 
         /* Convert to integer - if couldn't be converted then the factorial would be too big anyway */
@@ -719,80 +531,32 @@ public class Number : Object
     /* 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);
-    }
-
-    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);
+        var z = new Number ();
+        z.num.add (num, y.num);
         return z;
     }
 
     /* Sets z = x − y */
     public Number subtract (Number y)
     {
-        return add (y.invert_sign ());
+        var z = new Number ();
+        z.num.subtract (num, y.num);
+        return z;
     }
 
     /* Sets z = x × y */
     public Number multiply (Number y)
     {
-        if (is_complex () || y.is_complex ())
-        {
-            Number t1, t2, 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 ();
-
-            t1 = real_x.multiply_real (real_y);
-            t2 = im_x.multiply_real (im_y);
-            real_z = t1.subtract (t2);
-
-            t1 = real_x.multiply_real (im_y);
-            t2 = im_x.multiply_real (real_y);
-            im_z = t1.add (t2);
-
-            return new Number.complex (real_z, im_z);
-        }
-        else
-            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;
+        var z = new Number ();
+        z.num.multiply (num, y.num);
         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;
+        var z = new Number ();
+        z.num.multiply_signed_integer (num, (long) y);
         return z;
     }
 
@@ -806,27 +570,8 @@ public class Number : Object
             return new Number.integer (0);
         }
 
-        if (is_complex () || y.is_complex ())
-        {
-            var a = real_component ();
-            var b = imaginary_component ();
-            var c = y.real_component ();
-            var d = y.imaginary_component ();
-
-            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);
+        var z = new Number ();
+        z.num.divide (num, y.num);
         return z;
     }
 
@@ -884,46 +629,25 @@ public class Number : Object
     /* Sets z = sin x */
     public Number sin (AngleUnit unit = AngleUnit.RADIANS)
     {
+        var z = new Number ();
         if (is_complex ())
-        {
-            var x_real = real_component ();
-            var x_im = imaginary_component ();
-
-            var z_real = x_real.sin_real (unit);
-            var t = x_im.cosh ();
-            z_real = z_real.multiply (t);
-
-            var z_im = x_real.cos_real (unit);
-            t = x_im.sinh ();
-            z_im = z_im.multiply (t);
-
-            return new Number.complex (z_real, z_im);
-        }
+          z.num.@set (num);
         else
-            return sin_real (unit);
+          mpc_to_radians (z.num, num, unit);
+        z.num.sin (z.num);
+        return z;
     }
 
     /* Sets z = cos x */
     public Number cos (AngleUnit unit = AngleUnit.RADIANS)
     {
+        var z = new Number ();
         if (is_complex ())
-        {
-            var x_real = real_component ();
-            var x_im = imaginary_component ();
-
-            var z_real = x_real.cos_real (unit);
-            var t = x_im.cosh ();
-            z_real = z_real.multiply (t);
-
-            var z_im = x_real.sin_real (unit);
-            t = x_im.sinh ();
-            z_im = z_im.multiply (t);
-            z_im = z_im.invert_sign ();
-
-            return new Number.complex (z_real, z_im);
-        }
+          z.num.@set (num);
         else
-            return cos_real (unit);
+          mpc_to_radians (z.num, num, unit);
+        z.num.cos (z.num);
+        return z;
     }
 
     /* Sets z = tan x */
@@ -940,9 +664,12 @@ public class Number : Object
             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);
+        var z = new Number ();
+        if (is_complex ())
+          z.num.@set (num);
+        else
+          mpc_to_radians (z.num, num, unit);
+        z.num.tan (z.num);
         return z;
     }
 
@@ -956,10 +683,11 @@ public class Number : Object
             return new Number.integer (0);
         }
 
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.asin (re_num, Round.NEAREST);
-        var z = new Number.mpfloat (tmp);
-        return z.from_radians (unit);
+        var z = new Number ();
+        z.num.asin (num);
+        if (!z.is_complex ())
+          mpc_from_radians (z.num, z.num, unit);
+        return z;
     }
 
     /* Sets z = cos⁻¹ x */
@@ -972,54 +700,52 @@ public class Number : Object
             return new Number.integer (0);
         }
 
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.acos (re_num, Round.NEAREST);
-        var z = new Number.mpfloat (tmp);
-        return z.from_radians (unit);
+        var z = new Number ();
+        z.num.acos (num);
+        if (!z.is_complex ())
+          mpc_from_radians (z.num, z.num, unit);
+        return z;
     }
 
     /* 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);
-        return z.from_radians (unit);
+        var z = new Number ();
+        z.num.atan (num);
+        if (!z.is_complex ())
+          mpc_from_radians (z.num, z.num, unit);
+        return z;
     }
 
     /* 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);
+        var z = new Number ();
+        z.num.sinh (num);
         return z;
     }
 
     /* 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);
+        var z = new Number ();
+        z.num.cosh (num);
         return z;
     }
 
     /* 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);
+        var z = new Number ();
+        z.num.tanh (num);
         return z;
     }
 
     /* 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);
+        var z = new Number ();
+        z.num.asinh (num);
         return z;
     }
 
@@ -1035,9 +761,8 @@ public class Number : Object
             return new Number.integer (0);
         }
 
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.acosh (re_num, Round.NEAREST);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.acosh (num);
         return z;
     }
 
@@ -1052,9 +777,8 @@ public class Number : Object
             return new Number.integer (0);
         }
 
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.atanh (re_num, Round.NEAREST);
-        var z = new Number.mpfloat (tmp);
+        var z = new Number ();
+        z.num.atanh (num);
         return z;
     }
 
@@ -1256,109 +980,76 @@ public class Number : Object
     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.num.@set (num);
         return z;
     }
 
-    private Number epowy_real ()
+    private static void mpc_from_radians (Complex res, Complex op, AngleUnit unit)
     {
-        var z = copy ();
-        var tmp = z.re_num;
-        tmp.exp (re_num, Round.NEAREST);
-        z.re_num = tmp;
-        return z;
-    }
-
-    private Number root_real (int64 n)
-    {
-        var z = copy ();
-        var tmp = z.re_num;
-        tmp.root (re_num, (ulong) n, Round.NEAREST);
-        z.re_num = tmp;
-        return z;
-    }
-
-    private Number ln_real ()
-    {
-        var tmp = MPFloat.init2 ((Precision) precision);
-        tmp.log (re_num, Round.NEAREST);
-        var z = new Number.mpfloat (tmp);
-        return z;
-    }
-
-    private Number reciprocal_real ()
-    {
-        /* 1/0 invalid */
-        if (is_zero ())
-        {
-            error = _("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;
-    }
-
+        int i;
 
-    private Number from_radians (AngleUnit unit)
-    {
         switch (unit)
         {
-        default:
-        case AngleUnit.RADIANS:
-            return this;
+            default:
+            case AngleUnit.RADIANS:
+                if (res != op)
+                    res.@set (op);
+                return;
+
+            case AngleUnit.DEGREES:
+                i = 180;
+                break;
 
-        case AngleUnit.DEGREES:
-            return multiply_integer (180).divide (new Number.pi ());
+            case AngleUnit.GRADIANS:
+                i=200;
+                break;
 
-        case AngleUnit.GRADIANS:
-            return multiply_integer (200).divide (new Number.pi ());
         }
+        var scale = MPFR.Real (precision);
+        scale.const_pi ();
+        scale.signed_integer_divide (i, scale);
+        res.multiply_mpreal (op, scale);
     }
 
-    /* Convert x to radians */
-    private Number to_radians (AngleUnit unit)
+    private static void mpc_to_radians (Complex res, Complex op, AngleUnit unit)
     {
+        int i;
+
         switch (unit)
         {
-        default:
-        case AngleUnit.RADIANS:
-            return this;
+            default:
+            case AngleUnit.RADIANS:
+                if (res != op)
+                    res.@set (op);
+                return;
 
-        case AngleUnit.DEGREES:
-            return multiply (new Number.pi ()).divide_integer (180);
+            case AngleUnit.DEGREES:
+                i = 180;
+                break;
 
-        case AngleUnit.GRADIANS:
-            return multiply (new Number.pi ()).divide_integer (200);
+            case AngleUnit.GRADIANS:
+                i=200;
+                break;
         }
+        var scale = MPFR.Real (precision);
+        scale.const_pi ();
+        scale.divide_signed_integer (scale, i);
+        res.multiply_mpreal (op, scale);
     }
 
-    private Number sin_real (AngleUnit unit)
+    private Number from_radians (AngleUnit unit)
     {
-        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 z = new Number ();
+        mpc_from_radians (z.num, num, unit);
         return z;
     }
 
-    private Number cos_real (AngleUnit unit)
+
+    /* Convert x to radians */
+    private Number to_radians (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);
+        var z = new Number ();
+        mpc_to_radians (z.num, num, unit);
         return z;
     }
 


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