Import mpc-1.0.1 to new vendor branch avalon/vendor/MPC
authorJohn Marino <draco@marino.st>
Sat, 29 Sep 2012 19:03:54 +0000 (21:03 +0200)
committerJohn Marino <draco@marino.st>
Sat, 29 Sep 2012 19:03:54 +0000 (21:03 +0200)
This multiprecision library is required for gcc 4.6 and later.

85 files changed:
contrib/mpc/AUTHORS [new file with mode: 0644]
contrib/mpc/COPYING.LESSER [new file with mode: 0644]
contrib/mpc/README [new file with mode: 0644]
contrib/mpc/src/abs.c [new file with mode: 0644]
contrib/mpc/src/acos.c [new file with mode: 0644]
contrib/mpc/src/acosh.c [new file with mode: 0644]
contrib/mpc/src/add.c [new file with mode: 0644]
contrib/mpc/src/add_fr.c [new file with mode: 0644]
contrib/mpc/src/add_si.c [new file with mode: 0644]
contrib/mpc/src/add_ui.c [new file with mode: 0644]
contrib/mpc/src/arg.c [new file with mode: 0644]
contrib/mpc/src/asin.c [new file with mode: 0644]
contrib/mpc/src/asinh.c [new file with mode: 0644]
contrib/mpc/src/atan.c [new file with mode: 0644]
contrib/mpc/src/atanh.c [new file with mode: 0644]
contrib/mpc/src/clear.c [new file with mode: 0644]
contrib/mpc/src/cmp.c [new file with mode: 0644]
contrib/mpc/src/cmp_si_si.c [new file with mode: 0644]
contrib/mpc/src/conj.c [new file with mode: 0644]
contrib/mpc/src/cos.c [new file with mode: 0644]
contrib/mpc/src/cosh.c [new file with mode: 0644]
contrib/mpc/src/div.c [new file with mode: 0644]
contrib/mpc/src/div_2si.c [new file with mode: 0644]
contrib/mpc/src/div_2ui.c [new file with mode: 0644]
contrib/mpc/src/div_fr.c [new file with mode: 0644]
contrib/mpc/src/div_ui.c [new file with mode: 0644]
contrib/mpc/src/exp.c [new file with mode: 0644]
contrib/mpc/src/fma.c [new file with mode: 0644]
contrib/mpc/src/fr_div.c [new file with mode: 0644]
contrib/mpc/src/fr_sub.c [new file with mode: 0644]
contrib/mpc/src/get_prec.c [new file with mode: 0644]
contrib/mpc/src/get_prec2.c [new file with mode: 0644]
contrib/mpc/src/get_version.c [new file with mode: 0644]
contrib/mpc/src/get_x.c [new file with mode: 0644]
contrib/mpc/src/imag.c [new file with mode: 0644]
contrib/mpc/src/init2.c [new file with mode: 0644]
contrib/mpc/src/init3.c [new file with mode: 0644]
contrib/mpc/src/inp_str.c [new file with mode: 0644]
contrib/mpc/src/log.c [new file with mode: 0644]
contrib/mpc/src/log10.c [new file with mode: 0644]
contrib/mpc/src/logging.c [new file with mode: 0644]
contrib/mpc/src/mem.c [new file with mode: 0644]
contrib/mpc/src/mpc-impl.h [new file with mode: 0644]
contrib/mpc/src/mpc-log.h [new file with mode: 0644]
contrib/mpc/src/mpc.h [new file with mode: 0644]
contrib/mpc/src/mul.c [new file with mode: 0644]
contrib/mpc/src/mul_2si.c [new file with mode: 0644]
contrib/mpc/src/mul_2ui.c [new file with mode: 0644]
contrib/mpc/src/mul_fr.c [new file with mode: 0644]
contrib/mpc/src/mul_i.c [new file with mode: 0644]
contrib/mpc/src/mul_si.c [new file with mode: 0644]
contrib/mpc/src/mul_ui.c [new file with mode: 0644]
contrib/mpc/src/neg.c [new file with mode: 0644]
contrib/mpc/src/norm.c [new file with mode: 0644]
contrib/mpc/src/out_str.c [new file with mode: 0644]
contrib/mpc/src/pow.c [new file with mode: 0644]
contrib/mpc/src/pow_d.c [new file with mode: 0644]
contrib/mpc/src/pow_fr.c [new file with mode: 0644]
contrib/mpc/src/pow_ld.c [new file with mode: 0644]
contrib/mpc/src/pow_si.c [new file with mode: 0644]
contrib/mpc/src/pow_ui.c [new file with mode: 0644]
contrib/mpc/src/pow_z.c [new file with mode: 0644]
contrib/mpc/src/proj.c [new file with mode: 0644]
contrib/mpc/src/real.c [new file with mode: 0644]
contrib/mpc/src/set.c [new file with mode: 0644]
contrib/mpc/src/set_prec.c [new file with mode: 0644]
contrib/mpc/src/set_str.c [new file with mode: 0644]
contrib/mpc/src/set_x.c [new file with mode: 0644]
contrib/mpc/src/set_x_x.c [new file with mode: 0644]
contrib/mpc/src/sin.c [new file with mode: 0644]
contrib/mpc/src/sin_cos.c [new file with mode: 0644]
contrib/mpc/src/sinh.c [new file with mode: 0644]
contrib/mpc/src/sqr.c [new file with mode: 0644]
contrib/mpc/src/sqrt.c [new file with mode: 0644]
contrib/mpc/src/strtoc.c [new file with mode: 0644]
contrib/mpc/src/sub.c [new file with mode: 0644]
contrib/mpc/src/sub_fr.c [new file with mode: 0644]
contrib/mpc/src/sub_ui.c [new file with mode: 0644]
contrib/mpc/src/swap.c [new file with mode: 0644]
contrib/mpc/src/tan.c [new file with mode: 0644]
contrib/mpc/src/tanh.c [new file with mode: 0644]
contrib/mpc/src/uceil_log2.c [new file with mode: 0644]
contrib/mpc/src/ui_div.c [new file with mode: 0644]
contrib/mpc/src/ui_ui_sub.c [new file with mode: 0644]
contrib/mpc/src/urandom.c [new file with mode: 0644]

diff --git a/contrib/mpc/AUTHORS b/contrib/mpc/AUTHORS
new file mode 100644 (file)
index 0000000..04bb21b
--- /dev/null
@@ -0,0 +1,6 @@
+Main authors:
+   Andreas Enge
+   Philippe Théveny
+   Paul Zimmermann
+
+Mickaël Gastineau has contributed the file Makefile.vc.
diff --git a/contrib/mpc/COPYING.LESSER b/contrib/mpc/COPYING.LESSER
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/contrib/mpc/README b/contrib/mpc/README
new file mode 100644 (file)
index 0000000..55369db
--- /dev/null
@@ -0,0 +1,11 @@
+Copyright (C) INRIA 2003, 2005, 2008, 2009, 2011
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without any warranty.
+
+
+GNU MPC is a complex floating-point library with exact rounding.
+It is based on the GNU MPFR floating-point library (http://www.mpfr.org/),
+which is itself based on the GNU MP library (http://gmplib.org/).
diff --git a/contrib/mpc/src/abs.c b/contrib/mpc/src/abs.c
new file mode 100644 (file)
index 0000000..bf1e5fd
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_abs -- Absolute value of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* the rounding mode is mpfr_rnd_t here since we return an mpfr number */
+int
+mpc_abs (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+   return mpfr_hypot (a, mpc_realref(b), mpc_imagref(b), rnd);
+}
diff --git a/contrib/mpc/src/acos.c b/contrib/mpc/src/acos.c
new file mode 100644 (file)
index 0000000..e7a2691
--- /dev/null
@@ -0,0 +1,228 @@
+/* mpc_acos -- arccosine of a complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+int
+mpc_acos (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im, inex;
+  mpfr_prec_t p_re, p_im, p;
+  mpc_t z1;
+  mpfr_t pi_over_2;
+  mpfr_exp_t e1, e2;
+  mpfr_rnd_t rnd_im;
+  mpc_rnd_t rnd1;
+
+  inex_re = 0;
+  inex_im = 0;
+
+  /* special values */
+  if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+    {
+      if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+        {
+          mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? +1 : -1);
+          mpfr_set_nan (mpc_realref (rop));
+        }
+      else if (mpfr_zero_p (mpc_realref (op)))
+        {
+          inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+          mpfr_set_nan (mpc_imagref (rop));
+        }
+      else
+        {
+          mpfr_set_nan (mpc_realref (rop));
+          mpfr_set_nan (mpc_imagref (rop));
+        }
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+    {
+      if (mpfr_inf_p (mpc_realref (op)))
+        {
+          if (mpfr_inf_p (mpc_imagref (op)))
+            {
+              if (mpfr_sgn (mpc_realref (op)) > 0)
+                {
+                  inex_re =
+                    set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+                  mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN);
+                }
+              else
+                {
+
+                  /* the real part of the result is 3*pi/4
+                     a = o(pi)  error(a) < 1 ulp(a)
+                     b = o(3*a) error(b) < 2 ulp(b)
+                     c = b/4    exact
+                     thus 1 bit is lost */
+                  mpfr_t x;
+                  mpfr_prec_t prec;
+                  int ok;
+                  mpfr_init (x);
+                  prec = mpfr_get_prec (mpc_realref (rop));
+                  p = prec;
+
+                  do
+                    {
+                      p += mpc_ceil_log2 (p);
+                      mpfr_set_prec (x, p);
+                      mpfr_const_pi (x, GMP_RNDD);
+                      mpfr_mul_ui (x, x, 3, GMP_RNDD);
+                      ok =
+                        mpfr_can_round (x, p - 1, GMP_RNDD, MPC_RND_RE (rnd),
+                                        prec+(MPC_RND_RE (rnd) == GMP_RNDN));
+
+                    } while (ok == 0);
+                  inex_re =
+                    mpfr_div_2ui (mpc_realref (rop), x, 2, MPC_RND_RE (rnd));
+                  mpfr_clear (x);
+                }
+            }
+          else
+            {
+              if (mpfr_sgn (mpc_realref (op)) > 0)
+                mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+              else
+                inex_re = mpfr_const_pi (mpc_realref (rop), MPC_RND_RE (rnd));
+            }
+        }
+      else
+        inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+
+      mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? +1 : -1);
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  /* pure real argument */
+  if (mpfr_zero_p (mpc_imagref (op)))
+    {
+      int s_im;
+      s_im = mpfr_signbit (mpc_imagref (op));
+
+      if (mpfr_cmp_ui (mpc_realref (op), 1) > 0)
+        {
+          if (s_im)
+            inex_im = mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+                                  MPC_RND_IM (rnd));
+          else
+            inex_im = -mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+                                   INV_RND (MPC_RND_IM (rnd)));
+
+          mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+        }
+      else if (mpfr_cmp_si (mpc_realref (op), -1) < 0)
+        {
+          mpfr_t minus_op_re;
+          minus_op_re[0] = mpc_realref (op)[0];
+          MPFR_CHANGE_SIGN (minus_op_re);
+
+          if (s_im)
+            inex_im = mpfr_acosh (mpc_imagref (rop), minus_op_re,
+                                  MPC_RND_IM (rnd));
+          else
+            inex_im = -mpfr_acosh (mpc_imagref (rop), minus_op_re,
+                                   INV_RND (MPC_RND_IM (rnd)));
+          inex_re = mpfr_const_pi (mpc_realref (rop), MPC_RND_RE (rnd));
+        }
+      else
+        {
+          inex_re = mpfr_acos (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+          mpfr_set_ui (mpc_imagref (rop), 0, MPC_RND_IM (rnd));
+        }
+
+      if (!s_im)
+        mpc_conj (rop, rop, MPC_RNDNN);
+
+      return MPC_INEX (inex_re, inex_im);
+    }
+
+  /* pure imaginary argument */
+  if (mpfr_zero_p (mpc_realref (op)))
+    {
+      inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+      inex_im = -mpfr_asinh (mpc_imagref (rop), mpc_imagref (op),
+                             INV_RND (MPC_RND_IM (rnd)));
+      mpc_conj (rop,rop, MPC_RNDNN);
+
+      return MPC_INEX (inex_re, inex_im);
+    }
+
+  /* regular complex argument: acos(z) = Pi/2 - asin(z) */
+  p_re = mpfr_get_prec (mpc_realref(rop));
+  p_im = mpfr_get_prec (mpc_imagref(rop));
+  p = p_re;
+  mpc_init3 (z1, p, p_im); /* we round directly the imaginary part to p_im,
+                              with rounding mode opposite to rnd_im */
+  rnd_im = MPC_RND_IM(rnd);
+  /* the imaginary part of asin(z) has the same sign as Im(z), thus if
+     Im(z) > 0 and rnd_im = RNDZ, we want to round the Im(asin(z)) to -Inf
+     so that -Im(asin(z)) is rounded to zero */
+  if (rnd_im == GMP_RNDZ)
+    rnd_im = mpfr_sgn (mpc_imagref(op)) > 0 ? GMP_RNDD : GMP_RNDU;
+  else
+    rnd_im = rnd_im == GMP_RNDU ? GMP_RNDD
+      : rnd_im == GMP_RNDD ? GMP_RNDU
+      : rnd_im; /* both RNDZ and RNDA map to themselves for -asin(z) */
+  rnd1 = MPC_RND (GMP_RNDN, rnd_im);
+  mpfr_init2 (pi_over_2, p);
+  for (;;)
+    {
+      p += mpc_ceil_log2 (p) + 3;
+
+      mpfr_set_prec (mpc_realref(z1), p);
+      mpfr_set_prec (pi_over_2, p);
+
+      set_pi_over_2 (pi_over_2, +1, GMP_RNDN);
+      e1 = 1; /* Exp(pi_over_2) */
+      inex = mpc_asin (z1, op, rnd1); /* asin(z) */
+      MPC_ASSERT (mpfr_sgn (mpc_imagref(z1)) * mpfr_sgn (mpc_imagref(op)) > 0);
+      inex_im = MPC_INEX_IM(inex); /* inex_im is in {-1, 0, 1} */
+      e2 = mpfr_get_exp (mpc_realref(z1));
+      mpfr_sub (mpc_realref(z1), pi_over_2, mpc_realref(z1), GMP_RNDN);
+      if (!mpfr_zero_p (mpc_realref(z1)))
+        {
+          /* the error on x=Re(z1) is bounded by 1/2 ulp(x) + 2^(e1-p-1) +
+             2^(e2-p-1) */
+          e1 = e1 >= e2 ? e1 + 1 : e2 + 1;
+          /* the error on x is bounded by 1/2 ulp(x) + 2^(e1-p-1) */
+          e1 -= mpfr_get_exp (mpc_realref(z1));
+          /* the error on x is bounded by 1/2 ulp(x) [1 + 2^e1] */
+          e1 = e1 <= 0 ? 0 : e1;
+          /* the error on x is bounded by 2^e1 * ulp(x) */
+          mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN); /* exact */
+          inex_im = -inex_im;
+          if (mpfr_can_round (mpc_realref(z1), p - e1, GMP_RNDN, GMP_RNDZ,
+                              p_re + (MPC_RND_RE(rnd) == GMP_RNDN)))
+            break;
+        }
+    }
+  inex = mpc_set (rop, z1, rnd);
+  inex_re = MPC_INEX_RE(inex);
+  mpc_clear (z1);
+  mpfr_clear (pi_over_2);
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/acosh.c b/contrib/mpc/src/acosh.c
new file mode 100644 (file)
index 0000000..782f555
--- /dev/null
@@ -0,0 +1,76 @@
+/* mpc_acosh -- inverse hyperbolic cosine of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_acosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  /* acosh(z) =
+      NaN + i*NaN, if z=0+i*NaN
+     -i*acos(z), if sign(Im(z)) = -
+      i*acos(z), if sign(Im(z)) = +
+      http://functions.wolfram.com/ElementaryFunctions/ArcCosh/27/02/03/01/01/
+  */
+  mpc_t a;
+  mpfr_t tmp;
+  int inex;
+
+  if (mpfr_zero_p (mpc_realref (op)) && mpfr_nan_p (mpc_imagref (op)))
+    {
+      mpfr_set_nan (mpc_realref (rop));
+      mpfr_set_nan (mpc_imagref (rop));
+      return 0;
+    }
+
+  /* Note reversal of precisions due to later multiplication by i or -i */
+  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+  if (mpfr_signbit (mpc_imagref (op)))
+    {
+      inex = mpc_acos (a, op,
+                       MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+      /* change a to -i*a, i.e., -y+i*x to x+i*y */
+      tmp[0] = mpc_realref (a)[0];
+      mpc_realref (a)[0] = mpc_imagref (a)[0];
+      mpc_imagref (a)[0] = tmp[0];
+      MPFR_CHANGE_SIGN (mpc_imagref (a));
+      inex = MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+    }
+  else
+    {
+      inex = mpc_acos (a, op,
+                       MPC_RND (MPC_RND_IM (rnd), INV_RND(MPC_RND_RE (rnd))));
+
+      /* change a to i*a, i.e., y-i*x to x+i*y */
+      tmp[0] = mpc_realref (a)[0];
+      mpc_realref (a)[0] = mpc_imagref (a)[0];
+      mpc_imagref (a)[0] = tmp[0];
+      MPFR_CHANGE_SIGN (mpc_realref (a));
+      inex = MPC_INEX (-MPC_INEX_IM (inex), MPC_INEX_RE (inex));
+    }
+
+  mpc_set (rop, a, rnd);
+
+  mpc_clear (a);
+
+  return inex;
+}
diff --git a/contrib/mpc/src/add.c b/contrib/mpc/src/add.c
new file mode 100644 (file)
index 0000000..ee9ec19
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_add -- Add two complex numbers.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_add (mpc_realref(a), mpc_realref(b), mpc_realref(c), MPC_RND_RE(rnd));
+  inex_im = mpfr_add (mpc_imagref(a), mpc_imagref(b), mpc_imagref(c), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/add_fr.c b/contrib/mpc/src/add_fr.c
new file mode 100644 (file)
index 0000000..ea7b595
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_add_fr -- Add a complex number and a floating-point number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_add (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/add_si.c b/contrib/mpc/src/add_si.c
new file mode 100644 (file)
index 0000000..ba14803
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_add_si -- Add a complex number and a signed long int.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_add_si (mpc_ptr rop, mpc_srcptr op1, long int op2, mpc_rnd_t rnd)
+{
+   int inex_re, inex_im;
+
+   inex_re = mpfr_add_si (mpc_realref (rop), mpc_realref (op1), op2, MPC_RND_RE (rnd));
+   inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op1), MPC_RND_IM (rnd));
+
+   return MPC_INEX (inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/add_ui.c b/contrib/mpc/src/add_ui.c
new file mode 100644 (file)
index 0000000..85f4d13
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_add_ui -- Add a complex number and an unsigned long int.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_add_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/arg.c b/contrib/mpc/src/arg.c
new file mode 100644 (file)
index 0000000..20b5180
--- /dev/null
@@ -0,0 +1,27 @@
+/* mpc_arg -- Get the argument of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_arg (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+  return mpfr_atan2 (a, mpc_imagref (b), mpc_realref (b), rnd);
+}
diff --git a/contrib/mpc/src/asin.c b/contrib/mpc/src/asin.c
new file mode 100644 (file)
index 0000000..bd4e313
--- /dev/null
@@ -0,0 +1,226 @@
+/* mpc_asin -- arcsine of a complex number.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_asin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  mpfr_prec_t p, p_re, p_im, incr_p = 0;
+  mpfr_rnd_t rnd_re, rnd_im;
+  mpc_t z1;
+  int inex;
+
+  /* special values */
+  if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+    {
+      if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+        {
+          mpfr_set_nan (mpc_realref (rop));
+          mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? -1 : +1);
+        }
+      else if (mpfr_zero_p (mpc_realref (op)))
+        {
+          mpfr_set (mpc_realref (rop), mpc_realref (op), GMP_RNDN);
+          mpfr_set_nan (mpc_imagref (rop));
+        }
+      else
+        {
+          mpfr_set_nan (mpc_realref (rop));
+          mpfr_set_nan (mpc_imagref (rop));
+        }
+
+      return 0;
+    }
+
+  if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+    {
+      int inex_re;
+      if (mpfr_inf_p (mpc_realref (op)))
+        {
+          int inf_im = mpfr_inf_p (mpc_imagref (op));
+
+          inex_re = set_pi_over_2 (mpc_realref (rop),
+             (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+          mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));
+
+          if (inf_im)
+            mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN);
+        }
+      else
+        {
+          mpfr_set_zero (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1));
+          inex_re = 0;
+          mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));
+        }
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  /* pure real argument */
+  if (mpfr_zero_p (mpc_imagref (op)))
+    {
+      int inex_re;
+      int inex_im;
+      int s_im;
+      s_im = mpfr_signbit (mpc_imagref (op));
+
+      if (mpfr_cmp_ui (mpc_realref (op), 1) > 0)
+        {
+          if (s_im)
+            inex_im = -mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+                                   INV_RND (MPC_RND_IM (rnd)));
+          else
+            inex_im = mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+                                  MPC_RND_IM (rnd));
+          inex_re = set_pi_over_2 (mpc_realref (rop),
+             (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+          if (s_im)
+            mpc_conj (rop, rop, MPC_RNDNN);
+        }
+      else if (mpfr_cmp_si (mpc_realref (op), -1) < 0)
+        {
+          mpfr_t minus_op_re;
+          minus_op_re[0] = mpc_realref (op)[0];
+          MPFR_CHANGE_SIGN (minus_op_re);
+
+          if (s_im)
+            inex_im = -mpfr_acosh (mpc_imagref (rop), minus_op_re,
+                                   INV_RND (MPC_RND_IM (rnd)));
+          else
+            inex_im = mpfr_acosh (mpc_imagref (rop), minus_op_re,
+                                  MPC_RND_IM (rnd));
+          inex_re = set_pi_over_2 (mpc_realref (rop),
+             (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+          if (s_im)
+            mpc_conj (rop, rop, MPC_RNDNN);
+        }
+      else
+        {
+          inex_im = mpfr_set_ui (mpc_imagref (rop), 0, MPC_RND_IM (rnd));
+          if (s_im)
+            mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+          inex_re = mpfr_asin (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+        }
+
+      return MPC_INEX (inex_re, inex_im);
+    }
+
+  /* pure imaginary argument */
+  if (mpfr_zero_p (mpc_realref (op)))
+    {
+      int inex_im;
+      int s;
+      s = mpfr_signbit (mpc_realref (op));
+      mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+      if (s)
+        mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN);
+      inex_im = mpfr_asinh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+      return MPC_INEX (0, inex_im);
+    }
+
+  /* regular complex: asin(z) = -i*log(i*z+sqrt(1-z^2)) */
+  p_re = mpfr_get_prec (mpc_realref(rop));
+  p_im = mpfr_get_prec (mpc_imagref(rop));
+  rnd_re = MPC_RND_RE(rnd);
+  rnd_im = MPC_RND_IM(rnd);
+  p = p_re >= p_im ? p_re : p_im;
+  mpc_init2 (z1, p);
+  while (1)
+  {
+    mpfr_exp_t ex, ey, err;
+
+    p += mpc_ceil_log2 (p) + 3 + incr_p; /* incr_p is zero initially */
+    incr_p = p / 2;
+    mpfr_set_prec (mpc_realref(z1), p);
+    mpfr_set_prec (mpc_imagref(z1), p);
+
+    /* z1 <- z^2 */
+    mpc_sqr (z1, op, MPC_RNDNN);
+    /* err(x) <= 1/2 ulp(x), err(y) <= 1/2 ulp(y) */
+    /* z1 <- 1-z1 */
+    ex = mpfr_get_exp (mpc_realref(z1));
+    mpfr_ui_sub (mpc_realref(z1), 1, mpc_realref(z1), GMP_RNDN);
+    mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN);
+    ex = ex - mpfr_get_exp (mpc_realref(z1));
+    ex = (ex <= 0) ? 0 : ex;
+    /* err(x) <= 2^ex * ulp(x) */
+    ex = ex + mpfr_get_exp (mpc_realref(z1)) - p;
+    /* err(x) <= 2^ex */
+    ey = mpfr_get_exp (mpc_imagref(z1)) - p - 1;
+    /* err(y) <= 2^ey */
+    ex = (ex >= ey) ? ex : ey; /* err(x), err(y) <= 2^ex, i.e., the norm
+                                  of the error is bounded by |h|<=2^(ex+1/2) */
+    /* z1 <- sqrt(z1): if z1 = z + h, then sqrt(z1) = sqrt(z) + h/2/sqrt(t) */
+    ey = mpfr_get_exp (mpc_realref(z1)) >= mpfr_get_exp (mpc_imagref(z1))
+      ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+    /* we have |z1| >= 2^(ey-1) thus 1/|z1| <= 2^(1-ey) */
+    mpc_sqrt (z1, z1, MPC_RNDNN);
+    ex = (2 * ex + 1) - 2 - (ey - 1); /* |h^2/4/|t| <= 2^ex */
+    ex = (ex + 1) / 2; /* ceil(ex/2) */
+    /* express ex in terms of ulp(z1) */
+    ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1))
+      ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+    ex = ex - ey + p;
+    /* take into account the rounding error in the mpc_sqrt call */
+    err = (ex <= 0) ? 1 : ex + 1;
+    /* err(x) <= 2^err * ulp(x), err(y) <= 2^err * ulp(y) */
+    /* z1 <- i*z + z1 */
+    ex = mpfr_get_exp (mpc_realref(z1));
+    ey = mpfr_get_exp (mpc_imagref(z1));
+    mpfr_sub (mpc_realref(z1), mpc_realref(z1), mpc_imagref(op), GMP_RNDN);
+    mpfr_add (mpc_imagref(z1), mpc_imagref(z1), mpc_realref(op), GMP_RNDN);
+    if (mpfr_cmp_ui (mpc_realref(z1), 0) == 0 || mpfr_cmp_ui (mpc_imagref(z1), 0) == 0)
+      continue;
+    ex -= mpfr_get_exp (mpc_realref(z1)); /* cancellation in x */
+    ey -= mpfr_get_exp (mpc_imagref(z1)); /* cancellation in y */
+    ex = (ex >= ey) ? ex : ey; /* maximum cancellation */
+    err += ex;
+    err = (err <= 0) ? 1 : err + 1; /* rounding error in sub/add */
+    /* z1 <- log(z1): if z1 = z + h, then log(z1) = log(z) + h/t with
+       |t| >= min(|z1|,|z|) */
+    ex = mpfr_get_exp (mpc_realref(z1));
+    ey = mpfr_get_exp (mpc_imagref(z1));
+    ex = (ex >= ey) ? ex : ey;
+    err += ex - p; /* revert to absolute error <= 2^err */
+    mpc_log (z1, z1, GMP_RNDN);
+    err -= ex - 1; /* 1/|t| <= 1/|z| <= 2^(1-ex) */
+    /* express err in terms of ulp(z1) */
+    ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1))
+      ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+    err = err - ey + p;
+    /* take into account the rounding error in the mpc_log call */
+    err = (err <= 0) ? 1 : err + 1;
+    /* z1 <- -i*z1 */
+    mpfr_swap (mpc_realref(z1), mpc_imagref(z1));
+    mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN);
+    if (mpfr_can_round (mpc_realref(z1), p - err, GMP_RNDN, GMP_RNDZ,
+                        p_re + (rnd_re == GMP_RNDN)) &&
+        mpfr_can_round (mpc_imagref(z1), p - err, GMP_RNDN, GMP_RNDZ,
+                        p_im + (rnd_im == GMP_RNDN)))
+      break;
+  }
+
+  inex = mpc_set (rop, z1, rnd);
+  mpc_clear (z1);
+
+  return inex;
+}
diff --git a/contrib/mpc/src/asinh.c b/contrib/mpc/src/asinh.c
new file mode 100644 (file)
index 0000000..2807a8b
--- /dev/null
@@ -0,0 +1,55 @@
+/* mpc_asinh -- inverse hyperbolic sine of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_asinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  /* asinh(op) = -i*asin(i*op) */
+  int inex;
+  mpc_t z, a;
+  mpfr_t tmp;
+
+  /* z = i*op */
+  mpc_realref (z)[0] = mpc_imagref (op)[0];
+  mpc_imagref (z)[0] = mpc_realref (op)[0];
+  MPFR_CHANGE_SIGN (mpc_realref (z));
+
+  /* Note reversal of precisions due to later multiplication by -i */
+  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+  inex = mpc_asin (a, z,
+                   MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+  /* if a = asin(i*op) = x+i*y, and we want y-i*x */
+
+  /* change a to -i*a */
+  tmp[0] = mpc_realref (a)[0];
+  mpc_realref (a)[0] = mpc_imagref (a)[0];
+  mpc_imagref (a)[0] = tmp[0];
+  MPFR_CHANGE_SIGN (mpc_imagref (a));
+
+  mpc_set (rop, a, MPC_RNDNN);   /* exact */
+
+  mpc_clear (a);
+
+  return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+}
diff --git a/contrib/mpc/src/atan.c b/contrib/mpc/src/atan.c
new file mode 100644 (file)
index 0000000..c0b01a4
--- /dev/null
@@ -0,0 +1,367 @@
+/* mpc_atan -- arctangent of a complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>
+#include "mpc-impl.h"
+
+/* set rop to
+   -pi/2 if s < 0
+   +pi/2 else
+   rounded in the direction rnd
+*/
+int
+set_pi_over_2 (mpfr_ptr rop, int s, mpfr_rnd_t rnd)
+{
+  int inex;
+
+  inex = mpfr_const_pi (rop, s < 0 ? INV_RND (rnd) : rnd);
+  mpfr_div_2ui (rop, rop, 1, GMP_RNDN);
+  if (s < 0)
+    {
+      inex = -inex;
+      mpfr_neg (rop, rop, GMP_RNDN);
+    }
+
+  return inex;
+}
+
+int
+mpc_atan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  int s_re;
+  int s_im;
+  int inex_re;
+  int inex_im;
+  int inex;
+
+  inex_re = 0;
+  inex_im = 0;
+  s_re = mpfr_signbit (mpc_realref (op));
+  s_im = mpfr_signbit (mpc_imagref (op));
+
+  /* special values */
+  if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+    {
+      if (mpfr_nan_p (mpc_realref (op)))
+        {
+          mpfr_set_nan (mpc_realref (rop));
+          if (mpfr_zero_p (mpc_imagref (op)) || mpfr_inf_p (mpc_imagref (op)))
+            {
+              mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+              if (s_im)
+                mpc_conj (rop, rop, MPC_RNDNN);
+            }
+          else
+            mpfr_set_nan (mpc_imagref (rop));
+        }
+      else
+        {
+          if (mpfr_inf_p (mpc_realref (op)))
+            {
+              inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+              mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+            }
+          else
+            {
+              mpfr_set_nan (mpc_realref (rop));
+              mpfr_set_nan (mpc_imagref (rop));
+            }
+        }
+      return MPC_INEX (inex_re, 0);
+    }
+
+  if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+    {
+      inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+
+      mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+      if (s_im)
+        mpc_conj (rop, rop, GMP_RNDN);
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  /* pure real argument */
+  if (mpfr_zero_p (mpc_imagref (op)))
+    {
+      inex_re = mpfr_atan (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+
+      mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+      if (s_im)
+        mpc_conj (rop, rop, GMP_RNDN);
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  /* pure imaginary argument */
+  if (mpfr_zero_p (mpc_realref (op)))
+    {
+      int cmp_1;
+
+      if (s_im)
+        cmp_1 = -mpfr_cmp_si (mpc_imagref (op), -1);
+      else
+        cmp_1 = mpfr_cmp_ui (mpc_imagref (op), +1);
+
+      if (cmp_1 < 0)
+        {
+          /* atan(+0+iy) = +0 +i*atanh(y), if |y| < 1
+             atan(-0+iy) = -0 +i*atanh(y), if |y| < 1 */
+
+          mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+          if (s_re)
+            mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN);
+
+          inex_im = mpfr_atanh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+        }
+      else if (cmp_1 == 0)
+        {
+          /* atan(+/-0+i) = NaN +i*inf
+             atan(+/-0-i) = NaN -i*inf */
+          mpfr_set_nan (mpc_realref (rop));
+          mpfr_set_inf (mpc_imagref (rop), s_im ? -1 : +1);
+        }
+      else
+        {
+          /* atan(+0+iy) = +pi/2 +i*atanh(1/y), if |y| > 1
+             atan(-0+iy) = -pi/2 +i*atanh(1/y), if |y| > 1 */
+          mpfr_rnd_t rnd_im, rnd_away;
+          mpfr_t y;
+          mpfr_prec_t p, p_im;
+          int ok;
+
+          rnd_im = MPC_RND_IM (rnd);
+          mpfr_init (y);
+          p_im = mpfr_get_prec (mpc_imagref (rop));
+          p = p_im;
+
+          /* a = o(1/y)      with error(a) < 1 ulp(a)
+             b = o(atanh(a)) with error(b) < (1+2^{1+Exp(a)-Exp(b)}) ulp(b)
+
+             As |atanh (1/y)| > |1/y| we have Exp(a)-Exp(b) <=0 so, at most,
+             2 bits of precision are lost.
+
+             We round atanh(1/y) away from 0.
+          */
+          do
+            {
+              p += mpc_ceil_log2 (p) + 2;
+              mpfr_set_prec (y, p);
+              rnd_away = s_im == 0 ? GMP_RNDU : GMP_RNDD;
+              inex_im = mpfr_ui_div (y, 1, mpc_imagref (op), rnd_away);
+              /* FIXME: should we consider the case with unreasonably huge
+                 precision prec(y)>3*exp_min, where atanh(1/Im(op)) could be
+                 representable while 1/Im(op) underflows ?
+                 This corresponds to |y| = 0.5*2^emin, in which case the
+                 result may be wrong. */
+
+              /* atanh cannot underflow: |atanh(x)| > |x| for |x| < 1 */
+              inex_im |= mpfr_atanh (y, y, rnd_away);
+
+              ok = inex_im == 0
+                || mpfr_can_round (y, p - 2, rnd_away, GMP_RNDZ,
+                                   p_im + (rnd_im == GMP_RNDN));
+            } while (ok == 0);
+
+          inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+          inex_im = mpfr_set (mpc_imagref (rop), y, rnd_im);
+          mpfr_clear (y);
+        }
+      return MPC_INEX (inex_re, inex_im);
+    }
+
+  /* regular number argument */
+  {
+    mpfr_t a, b, x, y;
+    mpfr_prec_t prec, p;
+    mpfr_exp_t err, expo;
+    int ok = 0;
+    mpfr_t minus_op_re;
+    mpfr_exp_t op_re_exp, op_im_exp;
+    mpfr_rnd_t rnd1, rnd2;
+
+    mpfr_inits2 (MPFR_PREC_MIN, a, b, x, y, (mpfr_ptr) 0);
+
+    /* real part: Re(arctan(x+i*y)) = [arctan2(x,1-y) - arctan2(-x,1+y)]/2 */
+    minus_op_re[0] = mpc_realref (op)[0];
+    MPFR_CHANGE_SIGN (minus_op_re);
+    op_re_exp = mpfr_get_exp (mpc_realref (op));
+    op_im_exp = mpfr_get_exp (mpc_imagref (op));
+
+    prec = mpfr_get_prec (mpc_realref (rop)); /* result precision */
+
+    /* a = o(1-y)         error(a) < 1 ulp(a)
+       b = o(atan2(x,a))  error(b) < [1+2^{3+Exp(x)-Exp(a)-Exp(b)}] ulp(b)
+                                     = kb ulp(b)
+       c = o(1+y)         error(c) < 1 ulp(c)
+       d = o(atan2(-x,c)) error(d) < [1+2^{3+Exp(x)-Exp(c)-Exp(d)}] ulp(d)
+                                     = kd ulp(d)
+       e = o(b - d)       error(e) < [1 + kb*2^{Exp(b}-Exp(e)}
+                                        + kd*2^{Exp(d)-Exp(e)}] ulp(e)
+                          error(e) < [1 + 2^{4+Exp(x)-Exp(a)-Exp(e)}
+                                        + 2^{4+Exp(x)-Exp(c)-Exp(e)}] ulp(e)
+                          because |atan(u)| < |u|
+                                   < [1 + 2^{5+Exp(x)-min(Exp(a),Exp(c))
+                                             -Exp(e)}] ulp(e)
+       f = e/2            exact
+    */
+
+    /* p: working precision */
+    p = (op_im_exp > 0 || prec > SAFE_ABS (mpfr_prec_t, op_im_exp)) ? prec
+      : (prec - op_im_exp);
+    rnd1 = mpfr_sgn (mpc_realref (op)) > 0 ? GMP_RNDD : GMP_RNDU;
+    rnd2 = mpfr_sgn (mpc_realref (op)) < 0 ? GMP_RNDU : GMP_RNDD;
+
+    do
+      {
+        p += mpc_ceil_log2 (p) + 2;
+        mpfr_set_prec (a, p);
+        mpfr_set_prec (b, p);
+        mpfr_set_prec (x, p);
+
+        /* x = upper bound for atan (x/(1-y)). Since atan is increasing, we
+           need an upper bound on x/(1-y), i.e., a lower bound on 1-y for
+           x positive, and an upper bound on 1-y for x negative */
+        mpfr_ui_sub (a, 1, mpc_imagref (op), rnd1);
+        if (mpfr_sgn (a) == 0) /* y is near 1, thus 1+y is near 2, and
+                                  expo will be 1 or 2 below */
+          {
+            MPC_ASSERT (mpfr_cmp_ui (mpc_imagref(op), 1) == 0);
+               /* check for intermediate underflow */
+            err = 2; /* ensures err will be expo below */
+          }
+        else
+          err = mpfr_get_exp (a); /* err = Exp(a) with the notations above */
+        mpfr_atan2 (x, mpc_realref (op), a, GMP_RNDU);
+
+        /* b = lower bound for atan (-x/(1+y)): for x negative, we need a
+           lower bound on -x/(1+y), i.e., an upper bound on 1+y */
+        mpfr_add_ui (a, mpc_imagref(op), 1, rnd2);
+        /* if a is exactly zero, i.e., Im(op) = -1, then the error on a is 0,
+           and we can simply ignore the terms involving Exp(a) in the error */
+        if (mpfr_sgn (a) == 0)
+          {
+            MPC_ASSERT (mpfr_cmp_si (mpc_imagref(op), -1) == 0);
+               /* check for intermediate underflow */
+            expo = err; /* will leave err unchanged below */
+          }
+        else
+          expo = mpfr_get_exp (a); /* expo = Exp(c) with the notations above */
+        mpfr_atan2 (b, minus_op_re, a, GMP_RNDD);
+
+        err = err < expo ? err : expo; /* err = min(Exp(a),Exp(c)) */
+        mpfr_sub (x, x, b, GMP_RNDU);
+
+        err = 5 + op_re_exp - err - mpfr_get_exp (x);
+        /* error is bounded by [1 + 2^err] ulp(e) */
+        err = err < 0 ? 1 : err + 1;
+
+        mpfr_div_2ui (x, x, 1, GMP_RNDU);
+
+        /* Note: using RND2=RNDD guarantees that if x is exactly representable
+           on prec + ... bits, mpfr_can_round will return 0 */
+        ok = mpfr_can_round (x, p - err, GMP_RNDU, GMP_RNDD,
+                             prec + (MPC_RND_RE (rnd) == GMP_RNDN));
+      } while (ok == 0);
+
+    /* Imaginary part
+       Im(atan(x+I*y)) = 1/4 * [log(x^2+(1+y)^2) - log (x^2 +(1-y)^2)] */
+    prec = mpfr_get_prec (mpc_imagref (rop)); /* result precision */
+
+    /* a = o(1+y)    error(a) < 1 ulp(a)
+       b = o(a^2)    error(b) < 5 ulp(b)
+       c = o(x^2)    error(c) < 1 ulp(c)
+       d = o(b+c)    error(d) < 7 ulp(d)
+       e = o(log(d)) error(e) < [1 + 7*2^{2-Exp(e)}] ulp(e) = ke ulp(e)
+       f = o(1-y)    error(f) < 1 ulp(f)
+       g = o(f^2)    error(g) < 5 ulp(g)
+       h = o(c+f)    error(h) < 7 ulp(h)
+       i = o(log(h)) error(i) < [1 + 7*2^{2-Exp(i)}] ulp(i) = ki ulp(i)
+       j = o(e-i)    error(j) < [1 + ke*2^{Exp(e)-Exp(j)}
+                                   + ki*2^{Exp(i)-Exp(j)}] ulp(j)
+                     error(j) < [1 + 2^{Exp(e)-Exp(j)} + 2^{Exp(i)-Exp(j)}
+                                   + 7*2^{3-Exp(j)}] ulp(j)
+                              < [1 + 2^{max(Exp(e),Exp(i))-Exp(j)+1}
+                                   + 7*2^{3-Exp(j)}] ulp(j)
+       k = j/4       exact
+    */
+    err = 2;
+    p = prec; /* working precision */
+
+    do
+      {
+        p += mpc_ceil_log2 (p) + err;
+        mpfr_set_prec (a, p);
+        mpfr_set_prec (b, p);
+        mpfr_set_prec (y, p);
+
+        /* a = upper bound for log(x^2 + (1+y)^2) */
+        ROUND_AWAY (mpfr_add_ui (a, mpc_imagref (op), 1, MPFR_RNDA), a);
+        mpfr_sqr (a, a, GMP_RNDU);
+        mpfr_sqr (y, mpc_realref (op), GMP_RNDU);
+        mpfr_add (a, a, y, GMP_RNDU);
+        mpfr_log (a, a, GMP_RNDU);
+
+        /* b = lower bound for log(x^2 + (1-y)^2) */
+        mpfr_ui_sub (b, 1, mpc_imagref (op), GMP_RNDZ); /* round to zero */
+        mpfr_sqr (b, b, GMP_RNDZ);
+        /* we could write mpfr_sqr (y, mpc_realref (op), GMP_RNDZ) but it is
+           more efficient to reuse the value of y (x^2) above and subtract
+           one ulp */
+        mpfr_nextbelow (y);
+        mpfr_add (b, b, y, GMP_RNDZ);
+        mpfr_log (b, b, GMP_RNDZ);
+
+        mpfr_sub (y, a, b, GMP_RNDU);
+
+        if (mpfr_zero_p (y))
+           /* FIXME: happens when x and y have very different magnitudes;
+              could be handled more efficiently                           */
+          ok = 0;
+        else
+          {
+            expo = MPC_MAX (mpfr_get_exp (a), mpfr_get_exp (b));
+            expo = expo - mpfr_get_exp (y) + 1;
+            err = 3 - mpfr_get_exp (y);
+            /* error(j) <= [1 + 2^expo + 7*2^err] ulp(j) */
+            if (expo <= err) /* error(j) <= [1 + 2^{err+1}] ulp(j) */
+              err = (err < 0) ? 1 : err + 2;
+            else
+              err = (expo < 0) ? 1 : expo + 2;
+
+            mpfr_div_2ui (y, y, 2, GMP_RNDN);
+            MPC_ASSERT (!mpfr_zero_p (y));
+               /* FIXME: underflow. Since the main term of the Taylor series
+                  in y=0 is 1/(x^2+1) * y, this means that y is very small
+                  and/or x very large; but then the mpfr_zero_p (y) above
+                  should be true. This needs a proof, or better yet,
+                  special code.                                              */
+
+            ok = mpfr_can_round (y, p - err, GMP_RNDU, GMP_RNDD,
+                                 prec + (MPC_RND_IM (rnd) == GMP_RNDN));
+          }
+      } while (ok == 0);
+
+    inex = mpc_set_fr_fr (rop, x, y, rnd);
+
+    mpfr_clears (a, b, x, y, (mpfr_ptr) 0);
+    return inex;
+  }
+}
diff --git a/contrib/mpc/src/atanh.c b/contrib/mpc/src/atanh.c
new file mode 100644 (file)
index 0000000..e5716cc
--- /dev/null
@@ -0,0 +1,52 @@
+/* mpc_atanh -- inverse hyperbolic tangent of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_atanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  /* atanh(op) = -i*atan(i*op) */
+  int inex;
+  mpfr_t tmp;
+  mpc_t z, a;
+
+  mpc_realref (z)[0] = mpc_imagref (op)[0];
+  mpc_imagref (z)[0] = mpc_realref (op)[0];
+  MPFR_CHANGE_SIGN (mpc_realref (z));
+
+  /* Note reversal of precisions due to later multiplication by -i */
+  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+  inex = mpc_atan (a, z,
+                   MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+  /* change a to -i*a, i.e., x+i*y to y-i*x */
+  tmp[0] = mpc_realref (a)[0];
+  mpc_realref (a)[0] = mpc_imagref (a)[0];
+  mpc_imagref (a)[0] = tmp[0];
+  MPFR_CHANGE_SIGN (mpc_imagref (a));
+
+  mpc_set (rop, a, rnd);
+
+  mpc_clear (a);
+
+  return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+}
diff --git a/contrib/mpc/src/clear.c b/contrib/mpc/src/clear.c
new file mode 100644 (file)
index 0000000..f76b5db
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_clear -- Clear a complex variable.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_clear (mpc_t x)
+{
+  mpfr_clear (mpc_realref(x));
+  mpfr_clear (mpc_imagref(x));
+}
diff --git a/contrib/mpc/src/cmp.c b/contrib/mpc/src/cmp.c
new file mode 100644 (file)
index 0000000..ce1871c
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_cmp -- Compare two complex numbers.
+
+Copyright (C) 2002, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff a = b */
+int
+mpc_cmp (mpc_srcptr a, mpc_srcptr b)
+{
+  int cmp_re, cmp_im;
+
+  cmp_re = mpfr_cmp (mpc_realref(a), mpc_realref(b));
+  cmp_im = mpfr_cmp (mpc_imagref(a), mpc_imagref(b));
+
+  return MPC_INEX(cmp_re, cmp_im);
+}
diff --git a/contrib/mpc/src/cmp_si_si.c b/contrib/mpc/src/cmp_si_si.c
new file mode 100644 (file)
index 0000000..a50b758
--- /dev/null
@@ -0,0 +1,34 @@
+/* mpc_cmp_si_si -- Compare a complex number to a number of the form
+   b+c*i with b and c signed integers.
+
+Copyright (C) 2005, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff a = b */
+int
+mpc_cmp_si_si (mpc_srcptr a, long int b, long int c)
+{
+  int cmp_re, cmp_im;
+
+  cmp_re = mpfr_cmp_si (mpc_realref(a), b);
+  cmp_im = mpfr_cmp_si (mpc_imagref(a), c);
+
+  return MPC_INEX(cmp_re, cmp_im);
+}
diff --git a/contrib/mpc/src/conj.c b/contrib/mpc/src/conj.c
new file mode 100644 (file)
index 0000000..0905b1d
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_conj -- Conjugate of a complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_conj (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_set (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+  inex_im = mpfr_neg (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/cos.c b/contrib/mpc/src/cos.c
new file mode 100644 (file)
index 0000000..3810f3e
--- /dev/null
@@ -0,0 +1,27 @@
+/* mpc_cos -- cosine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_cos (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  return MPC_INEX2 (mpc_sin_cos (NULL, rop, op, 0, rnd));
+}
diff --git a/contrib/mpc/src/cosh.c b/contrib/mpc/src/cosh.c
new file mode 100644 (file)
index 0000000..0d4aab9
--- /dev/null
@@ -0,0 +1,35 @@
+/* mpc_cosh -- hyperbolic cosine of a complex number.
+
+Copyright (C)  2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_cosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  /* cosh(op) = cos(i*op) */
+  mpc_t z;
+
+  /* z = i*op without copying significand */
+  mpc_realref (z)[0] = mpc_imagref (op)[0];
+  mpc_imagref (z)[0] = mpc_realref (op)[0];
+  MPFR_CHANGE_SIGN (mpc_realref (z));
+
+  return mpc_cos (rop, z, rnd);
+}
diff --git a/contrib/mpc/src/div.c b/contrib/mpc/src/div.c
new file mode 100644 (file)
index 0000000..83584b8
--- /dev/null
@@ -0,0 +1,449 @@
+/* mpc_div -- Divide two complex numbers.
+
+Copyright (C) 2002, 2003, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* this routine deals with the case where w is zero */
+static int
+mpc_div_zero (mpc_ptr a, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes w==0, implementation according to C99 G.5.1.8 */
+{
+   int sign = MPFR_SIGNBIT (mpc_realref (w));
+   mpfr_t infty;
+
+   mpfr_init2 (infty, MPFR_PREC_MIN);
+   mpfr_set_inf (infty, sign);
+   mpfr_mul (mpc_realref (a), infty, mpc_realref (z), MPC_RND_RE (rnd));
+   mpfr_mul (mpc_imagref (a), infty, mpc_imagref (z), MPC_RND_IM (rnd));
+   mpfr_clear (infty);
+   return MPC_INEX (0, 0); /* exact */
+}
+
+/* this routine deals with the case where z is infinite and w finite */
+static int
+mpc_div_inf_fin (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
+/* Assumes w finite and non-zero and z infinite; implementation
+   according to C99 G.5.1.8                                     */
+{
+   int a, b, x, y;
+
+   a = (mpfr_inf_p (mpc_realref (z)) ? MPFR_SIGNBIT (mpc_realref (z)) : 0);
+   b = (mpfr_inf_p (mpc_imagref (z)) ? MPFR_SIGNBIT (mpc_imagref (z)) : 0);
+
+   /* a is -1 if Re(z) = -Inf, 1 if Re(z) = +Inf, 0 if Re(z) is finite
+      b is -1 if Im(z) = -Inf, 1 if Im(z) = +Inf, 0 if Im(z) is finite */
+
+   /* x = MPC_MPFR_SIGN (a * mpc_realref (w) + b * mpc_imagref (w)) */
+   /* y = MPC_MPFR_SIGN (b * mpc_realref (w) - a * mpc_imagref (w)) */
+   if (a == 0 || b == 0) {
+     /* only one of a or b can be zero, since z is infinite */
+      x = a * MPC_MPFR_SIGN (mpc_realref (w)) + b * MPC_MPFR_SIGN (mpc_imagref (w));
+      y = b * MPC_MPFR_SIGN (mpc_realref (w)) - a * MPC_MPFR_SIGN (mpc_imagref (w));
+   }
+   else {
+      /* Both parts of z are infinite; x could be determined by sign
+         considerations and comparisons. Since operations with non-finite
+         numbers are not considered time-critical, we let mpfr do the work. */
+      mpfr_t sign;
+
+      mpfr_init2 (sign, 2);
+      /* This is enough to determine the sign of sums and differences. */
+
+      if (a == 1)
+         if (b == 1) {
+            mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            x = MPC_MPFR_SIGN (sign);
+            mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            y = MPC_MPFR_SIGN (sign);
+         }
+         else { /* b == -1 */
+            mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            x = MPC_MPFR_SIGN (sign);
+            mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            y = -MPC_MPFR_SIGN (sign);
+         }
+      else /* a == -1 */
+         if (b == 1) {
+            mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
+            x = MPC_MPFR_SIGN (sign);
+            mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            y = MPC_MPFR_SIGN (sign);
+         }
+         else { /* b == -1 */
+            mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+            x = -MPC_MPFR_SIGN (sign);
+            mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
+            y = MPC_MPFR_SIGN (sign);
+         }
+      mpfr_clear (sign);
+   }
+
+   if (x == 0)
+      mpfr_set_nan (mpc_realref (rop));
+   else
+      mpfr_set_inf (mpc_realref (rop), x);
+   if (y == 0)
+      mpfr_set_nan (mpc_imagref (rop));
+   else
+      mpfr_set_inf (mpc_imagref (rop), y);
+
+   return MPC_INEX (0, 0); /* exact */
+}
+
+
+/* this routine deals with the case where z if finite and w infinite */
+static int
+mpc_div_fin_inf (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
+/* Assumes z finite and w infinite; implementation according to
+   C99 G.5.1.8                                                  */
+{
+   mpfr_t c, d, a, b, x, y, zero;
+
+   mpfr_init2 (c, 2); /* needed to hold a signed zero, +1 or -1 */
+   mpfr_init2 (d, 2);
+   mpfr_init2 (x, 2);
+   mpfr_init2 (y, 2);
+   mpfr_init2 (zero, 2);
+   mpfr_set_ui (zero, 0ul, GMP_RNDN);
+   mpfr_init2 (a, mpfr_get_prec (mpc_realref (z)));
+   mpfr_init2 (b, mpfr_get_prec (mpc_imagref (z)));
+
+   mpfr_set_ui (c, (mpfr_inf_p (mpc_realref (w)) ? 1 : 0), GMP_RNDN);
+   MPFR_COPYSIGN (c, c, mpc_realref (w), GMP_RNDN);
+   mpfr_set_ui (d, (mpfr_inf_p (mpc_imagref (w)) ? 1 : 0), GMP_RNDN);
+   MPFR_COPYSIGN (d, d, mpc_imagref (w), GMP_RNDN);
+
+   mpfr_mul (a, mpc_realref (z), c, GMP_RNDN); /* exact */
+   mpfr_mul (b, mpc_imagref (z), d, GMP_RNDN);
+   mpfr_add (x, a, b, GMP_RNDN);
+
+   mpfr_mul (b, mpc_imagref (z), c, GMP_RNDN);
+   mpfr_mul (a, mpc_realref (z), d, GMP_RNDN);
+   mpfr_sub (y, b, a, GMP_RNDN);
+
+   MPFR_COPYSIGN (mpc_realref (rop), zero, x, GMP_RNDN);
+   MPFR_COPYSIGN (mpc_imagref (rop), zero, y, GMP_RNDN);
+
+   mpfr_clear (c);
+   mpfr_clear (d);
+   mpfr_clear (x);
+   mpfr_clear (y);
+   mpfr_clear (zero);
+   mpfr_clear (a);
+   mpfr_clear (b);
+
+   return MPC_INEX (0, 0); /* exact */
+}
+
+
+static int
+mpc_div_real (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes z finite and w finite and non-zero, with imaginary part
+   of w a signed zero.                                             */
+{
+   int inex_re, inex_im;
+   /* save signs of operands in case there are overlaps */
+   int zrs = MPFR_SIGNBIT (mpc_realref (z));
+   int zis = MPFR_SIGNBIT (mpc_imagref (z));
+   int wrs = MPFR_SIGNBIT (mpc_realref (w));
+   int wis = MPFR_SIGNBIT (mpc_imagref (w));
+
+   /* warning: rop may overlap with z,w so treat the imaginary part first */
+   inex_im = mpfr_div (mpc_imagref(rop), mpc_imagref(z), mpc_realref(w), MPC_RND_IM(rnd));
+   inex_re = mpfr_div (mpc_realref(rop), mpc_realref(z), mpc_realref(w), MPC_RND_RE(rnd));
+
+   /* correct signs of zeroes if necessary, which does not affect the
+      inexact flags                                                    */
+   if (mpfr_zero_p (mpc_realref (rop)))
+      mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
+         GMP_RNDN); /* exact */
+   if (mpfr_zero_p (mpc_imagref (rop)))
+      mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
+         GMP_RNDN);
+
+   return MPC_INEX(inex_re, inex_im);
+}
+
+
+static int
+mpc_div_imag (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes z finite and w finite and non-zero, with real part
+   of w a signed zero.                                        */
+{
+   int inex_re, inex_im;
+   int overlap = (rop == z) || (rop == w);
+   int imag_z = mpfr_zero_p (mpc_realref (z));
+   mpfr_t wloc;
+   mpc_t tmprop;
+   mpc_ptr dest = (overlap) ? tmprop : rop;
+   /* save signs of operands in case there are overlaps */
+   int zrs = MPFR_SIGNBIT (mpc_realref (z));
+   int zis = MPFR_SIGNBIT (mpc_imagref (z));
+   int wrs = MPFR_SIGNBIT (mpc_realref (w));
+   int wis = MPFR_SIGNBIT (mpc_imagref (w));
+
+   if (overlap)
+      mpc_init3 (tmprop, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
+
+   wloc[0] = mpc_imagref(w)[0]; /* copies mpfr struct IM(w) into wloc */
+   inex_re = mpfr_div (mpc_realref(dest), mpc_imagref(z), wloc, MPC_RND_RE(rnd));
+   mpfr_neg (wloc, wloc, GMP_RNDN);
+   /* changes the sign only in wloc, not in w; no need to correct later */
+   inex_im = mpfr_div (mpc_imagref(dest), mpc_realref(z), wloc, MPC_RND_IM(rnd));
+
+   if (overlap) {
+      /* Note: we could use mpc_swap here, but this might cause problems
+         if rop and tmprop have been allocated using different methods, since
+         it will swap the significands of rop and tmprop. See
+         http://lists.gforge.inria.fr/pipermail/mpc-discuss/2009-August/000504.html */
+      mpc_set (rop, tmprop, MPC_RNDNN); /* exact */
+      mpc_clear (tmprop);
+   }
+
+   /* correct signs of zeroes if necessary, which does not affect the
+      inexact flags                                                    */
+   if (mpfr_zero_p (mpc_realref (rop)))
+      mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
+         GMP_RNDN); /* exact */
+   if (imag_z)
+      mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
+         GMP_RNDN);
+
+   return MPC_INEX(inex_re, inex_im);
+}
+
+
+int
+mpc_div (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+   int ok_re = 0, ok_im = 0;
+   mpc_t res, c_conj;
+   mpfr_t q;
+   mpfr_prec_t prec;
+   int inex, inexact_prod, inexact_norm, inexact_re, inexact_im, loops = 0;
+   int underflow_norm, overflow_norm, underflow_prod, overflow_prod;
+   int underflow_re = 0, overflow_re = 0, underflow_im = 0, overflow_im = 0;
+   mpfr_rnd_t rnd_re = MPC_RND_RE (rnd), rnd_im = MPC_RND_IM (rnd);
+   int saved_underflow, saved_overflow;
+   int tmpsgn;
+
+   /* According to the C standard G.3, there are three types of numbers:   */
+   /* finite (both parts are usual real numbers; contains 0), infinite     */
+   /* (at least one part is a real infinity) and all others; the latter    */
+   /* are numbers containing a nan, but no infinity, and could reasonably  */
+   /* be called nan.                                                       */
+   /* By G.5.1.4, infinite/finite=infinite; finite/infinite=0;             */
+   /* all other divisions that are not finite/finite return nan+i*nan.     */
+   /* Division by 0 could be handled by the following case of division by  */
+   /* a real; we handle it separately instead.                             */
+   if (mpc_zero_p (c))
+      return mpc_div_zero (a, b, c, rnd);
+   else if (mpc_inf_p (b) && mpc_fin_p (c))
+         return mpc_div_inf_fin (a, b, c);
+   else if (mpc_fin_p (b) && mpc_inf_p (c))
+         return mpc_div_fin_inf (a, b, c);
+   else if (!mpc_fin_p (b) || !mpc_fin_p (c)) {
+      mpc_set_nan (a);
+      return MPC_INEX (0, 0);
+   }
+   else if (mpfr_zero_p(mpc_imagref(c)))
+      return mpc_div_real (a, b, c, rnd);
+   else if (mpfr_zero_p(mpc_realref(c)))
+      return mpc_div_imag (a, b, c, rnd);
+      
+   prec = MPC_MAX_PREC(a);
+
+   mpc_init2 (res, 2);
+   mpfr_init (q);
+
+   /* create the conjugate of c in c_conj without allocating new memory */
+   mpc_realref (c_conj)[0] = mpc_realref (c)[0];
+   mpc_imagref (c_conj)[0] = mpc_imagref (c)[0];
+   MPFR_CHANGE_SIGN (mpc_imagref (c_conj));
+
+   /* save the underflow or overflow flags from MPFR */
+   saved_underflow = mpfr_underflow_p ();
+   saved_overflow = mpfr_overflow_p ();
+
+   do {
+      loops ++;
+      prec += loops <= 2 ? mpc_ceil_log2 (prec) + 5 : prec / 2;
+
+      mpc_set_prec (res, prec);
+      mpfr_set_prec (q, prec);
+
+      /* first compute norm(c) */
+      mpfr_clear_underflow ();
+      mpfr_clear_overflow ();
+      inexact_norm = mpc_norm (q, c, GMP_RNDU);
+      underflow_norm = mpfr_underflow_p ();
+      overflow_norm = mpfr_overflow_p ();
+      if (underflow_norm)
+         mpfr_set_ui (q, 0ul, GMP_RNDN);
+         /* to obtain divisions by 0 later on */
+
+      /* now compute b*conjugate(c) */
+      mpfr_clear_underflow ();
+      mpfr_clear_overflow ();
+      inexact_prod = mpc_mul (res, b, c_conj, MPC_RNDZZ);
+      inexact_re = MPC_INEX_RE (inexact_prod);
+      inexact_im = MPC_INEX_IM (inexact_prod);
+      underflow_prod = mpfr_underflow_p ();
+      overflow_prod = mpfr_overflow_p ();
+         /* unfortunately, does not distinguish between under-/overflow
+            in real or imaginary parts
+            hopefully, the side-effects of mpc_mul do indeed raise the
+            mpfr exceptions */
+      if (overflow_prod) {
+         int isinf = 0;
+         tmpsgn = mpfr_sgn (mpc_realref(res));
+         if (tmpsgn > 0)
+           {
+             mpfr_nextabove (mpc_realref(res));
+             isinf = mpfr_inf_p (mpc_realref(res));
+             mpfr_nextbelow (mpc_realref(res));
+           }
+         else if (tmpsgn < 0)
+           {
+             mpfr_nextbelow (mpc_realref(res));
+             isinf = mpfr_inf_p (mpc_realref(res));
+             mpfr_nextabove (mpc_realref(res));
+           }
+         if (isinf)
+           {
+             mpfr_set_inf (mpc_realref(res), tmpsgn);
+             overflow_re = 1;
+           }
+         tmpsgn = mpfr_sgn (mpc_imagref(res));
+         isinf = 0;
+         if (tmpsgn > 0)
+           {
+             mpfr_nextabove (mpc_imagref(res));
+             isinf = mpfr_inf_p (mpc_imagref(res));
+             mpfr_nextbelow (mpc_imagref(res));
+           }
+         else if (tmpsgn < 0)
+           {
+             mpfr_nextbelow (mpc_imagref(res));
+             isinf = mpfr_inf_p (mpc_imagref(res));
+             mpfr_nextabove (mpc_imagref(res));
+           }
+         if (isinf)
+           {
+             mpfr_set_inf (mpc_imagref(res), tmpsgn);
+             overflow_im = 1;
+           }
+         mpc_set (a, res, rnd);
+         goto end;
+      }
+
+      /* divide the product by the norm */
+      if (inexact_norm == 0 && (inexact_re == 0 || inexact_im == 0)) {
+         /* The division has good chances to be exact in at least one part.  */
+         /* Since this can cause problems when not rounding to the nearest,  */
+         /* we use the division code of mpfr, which handles the situation.   */
+         mpfr_clear_underflow ();
+         mpfr_clear_overflow ();
+         inexact_re |= mpfr_div (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
+         underflow_re = mpfr_underflow_p ();
+         overflow_re = mpfr_overflow_p ();
+         ok_re = !inexact_re || underflow_re || overflow_re
+                 || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
+                    GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
+
+         if (ok_re) /* compute imaginary part */ {
+            mpfr_clear_underflow ();
+            mpfr_clear_overflow ();
+            inexact_im |= mpfr_div (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
+            underflow_im = mpfr_underflow_p ();
+            overflow_im = mpfr_overflow_p ();
+            ok_im = !inexact_im || underflow_im || overflow_im
+                    || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
+                       GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
+         }
+      }
+      else {
+         /* The division is inexact, so for efficiency reasons we invert q */
+         /* only once and multiply by the inverse. */
+         if (mpfr_ui_div (q, 1ul, q, GMP_RNDZ) || inexact_norm) {
+             /* if 1/q is inexact, the approximations of the real and
+                imaginary part below will be inexact, unless RE(res)
+                or IM(res) is zero */
+             inexact_re |= ~mpfr_zero_p (mpc_realref (res));
+             inexact_im |= ~mpfr_zero_p (mpc_imagref (res));
+         }
+         mpfr_clear_underflow ();
+         mpfr_clear_overflow ();
+         inexact_re |= mpfr_mul (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
+         underflow_re = mpfr_underflow_p ();
+         overflow_re = mpfr_overflow_p ();
+         ok_re = !inexact_re || underflow_re || overflow_re
+                 || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
+                    GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
+
+         if (ok_re) /* compute imaginary part */ {
+            mpfr_clear_underflow ();
+            mpfr_clear_overflow ();
+            inexact_im |= mpfr_mul (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
+            underflow_im = mpfr_underflow_p ();
+            overflow_im = mpfr_overflow_p ();
+            ok_im = !inexact_im || underflow_im || overflow_im
+                    || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
+                       GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
+         }
+      }
+   } while ((!ok_re || !ok_im) && !underflow_norm && !overflow_norm
+                               && !underflow_prod && !overflow_prod);
+
+   inex = mpc_set (a, res, rnd);
+   inexact_re = MPC_INEX_RE (inex);
+   inexact_im = MPC_INEX_IM (inex);
+
+ end:
+   /* fix values and inexact flags in case of overflow/underflow */
+   /* FIXME: heuristic, certainly does not cover all cases */
+   if (overflow_re || (underflow_norm && !underflow_prod)) {
+      mpfr_set_inf (mpc_realref (a), mpfr_sgn (mpc_realref (res)));
+      inexact_re = mpfr_sgn (mpc_realref (res));
+   }
+   else if (underflow_re || (overflow_norm && !overflow_prod)) {
+      inexact_re = mpfr_signbit (mpc_realref (res)) ? 1 : -1;
+      mpfr_set_zero (mpc_realref (a), -inexact_re);
+   }
+   if (overflow_im || (underflow_norm && !underflow_prod)) {
+      mpfr_set_inf (mpc_imagref (a), mpfr_sgn (mpc_imagref (res)));
+      inexact_im = mpfr_sgn (mpc_imagref (res));
+   }
+   else if (underflow_im || (overflow_norm && !overflow_prod)) {
+      inexact_im = mpfr_signbit (mpc_imagref (res)) ? 1 : -1;
+      mpfr_set_zero (mpc_imagref (a), -inexact_im);
+   }
+
+   mpc_clear (res);
+   mpfr_clear (q);
+
+   /* restore underflow and overflow flags from MPFR */
+   if (saved_underflow)
+     mpfr_set_underflow ();
+   if (saved_overflow)
+     mpfr_set_overflow ();
+
+   return MPC_INEX (inexact_re, inexact_im);
+}
diff --git a/contrib/mpc/src/div_2si.c b/contrib/mpc/src/div_2si.c
new file mode 100644 (file)
index 0000000..511f2cb
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_div_2si -- Divide a complex number by 2^e.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_2si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_div_2si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_div_2si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/div_2ui.c b/contrib/mpc/src/div_2ui.c
new file mode 100644 (file)
index 0000000..cd53855
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_div_2ui -- Divide a complex number by 2^e.
+
+Copyright (C) 2002, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_2ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_div_2ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_div_2ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/div_fr.c b/contrib/mpc/src/div_fr.c
new file mode 100644 (file)
index 0000000..d5ea240
--- /dev/null
@@ -0,0 +1,39 @@
+/* mpc_div_fr -- Divide a complex number by a floating-point number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+  mpfr_t real;
+
+  /* We have to use temporary variable in case c=mpc_realref (a). */
+  mpfr_init2 (real, MPC_PREC_RE (a));
+
+  inex_re = mpfr_div (real, mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_div (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+  mpfr_set (mpc_realref (a), real, GMP_RNDN);
+
+  mpfr_clear (real);
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/div_ui.c b/contrib/mpc/src/div_ui.c
new file mode 100644 (file)
index 0000000..26debf7
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_div_ui -- Divide a complex number by a nonnegative integer.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_div_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_div_ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/exp.c b/contrib/mpc/src/exp.c
new file mode 100644 (file)
index 0000000..3646225
--- /dev/null
@@ -0,0 +1,202 @@
+/* mpc_exp -- exponential of a complex number.
+
+Copyright (C) 2002, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  mpfr_t x, y, z;
+  mpfr_prec_t prec;
+  int ok = 0;
+  int inex_re, inex_im;
+  int saved_underflow, saved_overflow;
+
+  /* special values */
+  if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+    /* NaNs
+       exp(nan +i*y) = nan -i*0   if y = -0,
+                       nan +i*0   if y = +0,
+                       nan +i*nan otherwise
+       exp(x+i*nan) =   +/-0 +/-i*0 if x=-inf,
+                      +/-inf +i*nan if x=+inf,
+                         nan +i*nan otherwise */
+    {
+      if (mpfr_zero_p (mpc_imagref (op)))
+        return mpc_set (rop, op, MPC_RNDNN);
+
+      if (mpfr_inf_p (mpc_realref (op)))
+        {
+          if (mpfr_signbit (mpc_realref (op)))
+            return mpc_set_ui_ui (rop, 0, 0, MPC_RNDNN);
+          else
+            {
+              mpfr_set_inf (mpc_realref (rop), +1);
+              mpfr_set_nan (mpc_imagref (rop));
+              return MPC_INEX(0, 0); /* Inf/NaN are exact */
+            }
+        }
+      mpfr_set_nan (mpc_realref (rop));
+      mpfr_set_nan (mpc_imagref (rop));
+      return MPC_INEX(0, 0); /* NaN is exact */
+    }
+
+
+  if (mpfr_zero_p (mpc_imagref(op)))
+    /* special case when the input is real
+       exp(x-i*0) = exp(x) -i*0, even if x is NaN
+       exp(x+i*0) = exp(x) +i*0, even if x is NaN */
+    {
+      inex_re = mpfr_exp (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd));
+      inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref(op), MPC_RND_IM(rnd));
+      return MPC_INEX(inex_re, inex_im);
+    }
+
+  if (mpfr_zero_p (mpc_realref (op)))
+    /* special case when the input is imaginary  */
+    {
+      inex_re = mpfr_cos (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE(rnd));
+      inex_im = mpfr_sin (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM(rnd));
+      return MPC_INEX(inex_re, inex_im);
+    }
+
+
+  if (mpfr_inf_p (mpc_realref (op)))
+    /* real part is an infinity,
+       exp(-inf +i*y) = 0*(cos y +i*sin y)
+       exp(+inf +i*y) = +/-inf +i*nan         if y = +/-inf
+                        +inf*(cos y +i*sin y) if 0 < |y| < inf */
+    {
+      mpfr_t n;
+
+      mpfr_init2 (n, 2);
+      if (mpfr_signbit (mpc_realref (op)))
+        mpfr_set_ui (n, 0, GMP_RNDN);
+      else
+        mpfr_set_inf (n, +1);
+
+      if (mpfr_inf_p (mpc_imagref (op)))
+        {
+          inex_re = mpfr_set (mpc_realref (rop), n, GMP_RNDN);
+          if (mpfr_signbit (mpc_realref (op)))
+            inex_im = mpfr_set (mpc_imagref (rop), n, GMP_RNDN);
+          else
+            {
+              mpfr_set_nan (mpc_imagref (rop));
+              inex_im = 0; /* NaN is exact */
+            }
+        }
+      else
+        {
+          mpfr_t c, s;
+          mpfr_init2 (c, 2);
+          mpfr_init2 (s, 2);
+
+          mpfr_sin_cos (s, c, mpc_imagref (op), GMP_RNDN);
+          inex_re = mpfr_copysign (mpc_realref (rop), n, c, GMP_RNDN);
+          inex_im = mpfr_copysign (mpc_imagref (rop), n, s, GMP_RNDN);
+
+          mpfr_clear (s);
+          mpfr_clear (c);
+        }
+
+      mpfr_clear (n);
+      return MPC_INEX(inex_re, inex_im);
+    }
+
+  if (mpfr_inf_p (mpc_imagref (op)))
+    /* real part is finite non-zero number, imaginary part is an infinity */
+    {
+      mpfr_set_nan (mpc_realref (rop));
+      mpfr_set_nan (mpc_imagref (rop));
+      return MPC_INEX(0, 0); /* NaN is exact */
+    }
+
+
+  /* from now on, both parts of op are regular numbers */
+
+  prec = MPC_MAX_PREC(rop)
+         + MPC_MAX (MPC_MAX (-mpfr_get_exp (mpc_realref (op)), 0),
+                   -mpfr_get_exp (mpc_imagref (op)));
+    /* When op is close to 0, then exp is close to 1+Re(op), while
+       cos is close to 1-Im(op); to decide on the ternary value of exp*cos,
+       we need a high enough precision so that none of exp or cos is
+       computed as 1. */
+  mpfr_init2 (x, 2);
+  mpfr_init2 (y, 2);
+  mpfr_init2 (z, 2);
+
+  /* save the underflow or overflow flags from MPFR */
+  saved_underflow = mpfr_underflow_p ();
+  saved_overflow = mpfr_overflow_p ();
+
+  do
+    {
+      prec += mpc_ceil_log2 (prec) + 5;
+
+      mpfr_set_prec (x, prec);
+      mpfr_set_prec (y, prec);
+      mpfr_set_prec (z, prec);
+
+      /* FIXME: x may overflow so x.y does overflow too, while Re(exp(op))
+         could be represented in the precision of rop. */
+      mpfr_clear_overflow ();
+      mpfr_clear_underflow ();
+      mpfr_exp (x, mpc_realref(op), GMP_RNDN); /* error <= 0.5ulp */
+      mpfr_sin_cos (z, y, mpc_imagref(op), GMP_RNDN); /* errors <= 0.5ulp */
+      mpfr_mul (y, y, x, GMP_RNDN); /* error <= 2ulp */
+      ok = mpfr_overflow_p () || mpfr_zero_p (x)
+        || mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ,
+                       MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == GMP_RNDN));
+      if (ok) /* compute imaginary part */
+        {
+          mpfr_mul (z, z, x, GMP_RNDN);
+          ok = mpfr_overflow_p () || mpfr_zero_p (x)
+            || mpfr_can_round (z, prec - 2, GMP_RNDN, GMP_RNDZ,
+                       MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == GMP_RNDN));
+        }
+    }
+  while (ok == 0);
+
+  inex_re = mpfr_set (mpc_realref(rop), y, MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(rop), z, MPC_RND_IM(rnd));
+  if (mpfr_overflow_p ()) {
+    /* overflow in real exponential, inex is sign of infinite result */
+    inex_re = mpfr_sgn (y);
+    inex_im = mpfr_sgn (z);
+  }
+  else if (mpfr_underflow_p ()) {
+    /* underflow in real exponential, inex is opposite of sign of 0 result */
+    inex_re = (mpfr_signbit (y) ? +1 : -1);
+    inex_im = (mpfr_signbit (z) ? +1 : -1);
+  }
+
+  mpfr_clear (x);
+  mpfr_clear (y);
+  mpfr_clear (z);
+
+  /* restore underflow and overflow flags from MPFR */
+  if (saved_underflow)
+    mpfr_set_underflow ();
+  if (saved_overflow)
+    mpfr_set_overflow ();
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/fma.c b/contrib/mpc/src/fma.c
new file mode 100644 (file)
index 0000000..7f5cd31
--- /dev/null
@@ -0,0 +1,191 @@
+/* mpc_fma -- Fused multiply-add of three complex numbers
+
+Copyright (C) 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return a bound on the precision needed to add or subtract x and y exactly */
+static mpfr_prec_t
+bound_prec_addsub (mpfr_srcptr x, mpfr_srcptr y)
+{
+  if (!mpfr_regular_p (x))
+    return mpfr_get_prec (y);
+  else if (!mpfr_regular_p (y))
+    return mpfr_get_prec (x);
+  else /* neither x nor y are NaN, Inf or zero */
+    {
+      mpfr_exp_t ex = mpfr_get_exp (x);
+      mpfr_exp_t ey = mpfr_get_exp (y);
+      mpfr_exp_t ulpx = ex - mpfr_get_prec (x);
+      mpfr_exp_t ulpy = ey - mpfr_get_prec (y);
+      return ((ex >= ey) ? ex : ey) + 1 - ((ulpx <= ulpy) ? ulpx : ulpy);
+    }
+}
+
+/* r <- a*b+c */
+int
+mpc_fma_naive (mpc_ptr r, mpc_srcptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+  mpfr_t rea_reb, rea_imb, ima_reb, ima_imb, tmp;
+  mpfr_prec_t pre12, pre13, pre23, pim12, pim13, pim23;
+  int inex_re, inex_im;
+
+  mpfr_init2 (rea_reb, mpfr_get_prec (mpc_realref(a)) + mpfr_get_prec (mpc_realref(b)));
+  mpfr_init2 (rea_imb, mpfr_get_prec (mpc_realref(a)) + mpfr_get_prec (mpc_imagref(b)));
+  mpfr_init2 (ima_reb, mpfr_get_prec (mpc_imagref(a)) + mpfr_get_prec (mpc_realref(b)));
+  mpfr_init2 (ima_imb, mpfr_get_prec (mpc_imagref(a)) + mpfr_get_prec (mpc_imagref(b)));
+
+  mpfr_mul (rea_reb, mpc_realref(a), mpc_realref(b), GMP_RNDZ); /* exact */
+  mpfr_mul (rea_imb, mpc_realref(a), mpc_imagref(b), GMP_RNDZ); /* exact */
+  mpfr_mul (ima_reb, mpc_imagref(a), mpc_realref(b), GMP_RNDZ); /* exact */
+  mpfr_mul (ima_imb, mpc_imagref(a), mpc_imagref(b), GMP_RNDZ); /* exact */
+
+  /* Re(r) <- rea_reb - ima_imb + Re(c) */
+
+  pre12 = bound_prec_addsub (rea_reb, ima_imb); /* bound on exact precision for
+                                                  rea_reb - ima_imb */
+  pre13 = bound_prec_addsub (rea_reb, mpc_realref(c));
+  /* bound for rea_reb + Re(c) */
+  pre23 = bound_prec_addsub (ima_imb, mpc_realref(c));
+  /* bound for ima_imb - Re(c) */
+  if (pre12 <= pre13 && pre12 <= pre23) /* (rea_reb - ima_imb) + Re(c) */
+    {
+      mpfr_init2 (tmp, pre12);
+      mpfr_sub (tmp, rea_reb, ima_imb, GMP_RNDZ); /* exact */
+      inex_re = mpfr_add (mpc_realref(r), tmp, mpc_realref(c), MPC_RND_RE(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the real part of both, it is ok */
+    }
+  else if (pre13 <= pre23) /* (rea_reb + Re(c)) - ima_imb */
+    {
+      mpfr_init2 (tmp, pre13);
+      mpfr_add (tmp, rea_reb, mpc_realref(c), GMP_RNDZ); /* exact */
+      inex_re = mpfr_sub (mpc_realref(r), tmp, ima_imb, MPC_RND_RE(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the real part of both, it is ok */
+    }
+  else /* rea_reb + (Re(c) - ima_imb) */
+    {
+      mpfr_init2 (tmp, pre23);
+      mpfr_sub (tmp, mpc_realref(c), ima_imb, GMP_RNDZ); /* exact */
+      inex_re = mpfr_add (mpc_realref(r), tmp, rea_reb, MPC_RND_RE(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the real part of both, it is ok */
+    }
+
+  /* Im(r) <- rea_imb + ima_reb + Im(c) */
+  pim12 = bound_prec_addsub (rea_imb, ima_reb); /* bound on exact precision for
+                                                  rea_imb + ima_reb */
+  pim13 = bound_prec_addsub (rea_imb, mpc_imagref(c));
+  /* bound for rea_imb + Im(c) */
+  pim23 = bound_prec_addsub (ima_reb, mpc_imagref(c));
+  /* bound for ima_reb + Im(c) */
+  if (pim12 <= pim13 && pim12 <= pim23) /* (rea_imb + ima_reb) + Im(c) */
+    {
+      mpfr_set_prec (tmp, pim12);
+      mpfr_add (tmp, rea_imb, ima_reb, GMP_RNDZ); /* exact */
+      inex_im = mpfr_add (mpc_imagref(r), tmp, mpc_imagref(c), MPC_RND_IM(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the imaginary part of both, it is ok */
+    }
+  else if (pim13 <= pim23) /* (rea_imb + Im(c)) + ima_reb */
+    {
+      mpfr_set_prec (tmp, pim13);
+      mpfr_add (tmp, rea_imb, mpc_imagref(c), GMP_RNDZ); /* exact */
+      inex_im = mpfr_add (mpc_imagref(r), tmp, ima_reb, MPC_RND_IM(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the imaginary part of both, it is ok */
+    }
+  else /* rea_imb + (Im(c) + ima_reb) */
+    {
+      mpfr_set_prec (tmp, pre23);
+      mpfr_add (tmp, mpc_imagref(c), ima_reb, GMP_RNDZ); /* exact */
+      inex_im = mpfr_add (mpc_imagref(r), tmp, rea_imb, MPC_RND_IM(rnd));
+      /* the only possible bad overlap is between r and c, but since we are
+        only touching the imaginary part of both, it is ok */
+    }
+
+  mpfr_clear (rea_reb);
+  mpfr_clear (rea_imb);
+  mpfr_clear (ima_reb);
+  mpfr_clear (ima_imb);
+  mpfr_clear (tmp);
+
+  return MPC_INEX(inex_re, inex_im);
+}
+
+/* The algorithm is as follows:
+   - in a first pass, we use the target precision + some extra bits
+   - if it fails, we add the number of cancelled bits when adding
+     Re(a*b) and Re(c) [similarly for the imaginary part]
+   - it is fails again, we call the mpc_fma_naive function, which also
+     deals with the special cases */
+int
+mpc_fma (mpc_ptr r, mpc_srcptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+  mpc_t ab;
+  mpfr_prec_t pre, pim, wpre, wpim;
+  mpfr_exp_t diffre, diffim;
+  int i, inex = 0, okre = 0, okim = 0;
+
+  if (mpc_fin_p (a) == 0 || mpc_fin_p (b) == 0 || mpc_fin_p (c) == 0)
+    return mpc_fma_naive (r, a, b, c, rnd);
+
+  pre = mpfr_get_prec (mpc_realref(r));
+  pim = mpfr_get_prec (mpc_imagref(r));
+  wpre = pre + mpc_ceil_log2 (pre) + 10;
+  wpim = pim + mpc_ceil_log2 (pim) + 10;
+  mpc_init3 (ab, wpre, wpim);
+  for (i = 0; i < 2; ++i)
+    {
+      mpc_mul (ab, a, b, MPC_RNDZZ);
+      if (mpfr_zero_p (mpc_realref(ab)) || mpfr_zero_p (mpc_imagref(ab)))
+        break;
+      diffre = mpfr_get_exp (mpc_realref(ab));
+      diffim = mpfr_get_exp (mpc_imagref(ab));
+      mpc_add (ab, ab, c, MPC_RNDZZ);
+      if (mpfr_zero_p (mpc_realref(ab)) || mpfr_zero_p (mpc_imagref(ab)))
+        break;
+      diffre -= mpfr_get_exp (mpc_realref(ab));
+      diffim -= mpfr_get_exp (mpc_imagref(ab));
+      diffre = (diffre > 0 ? diffre + 1 : 1);
+      diffim = (diffim > 0 ? diffim + 1 : 1);
+      okre = diffre > (mpfr_exp_t) wpre ? 0 : mpfr_can_round (mpc_realref(ab),
+                                 wpre - diffre, GMP_RNDN, GMP_RNDZ,
+                                 pre + (MPC_RND_RE (rnd) == GMP_RNDN));
+      okim = diffim > (mpfr_exp_t) wpim ? 0 : mpfr_can_round (mpc_imagref(ab),
+                                 wpim - diffim, GMP_RNDN, GMP_RNDZ,
+                                 pim + (MPC_RND_IM (rnd) == GMP_RNDN));
+      if (okre && okim)
+        {
+          inex = mpc_set (r, ab, rnd);
+          break;
+        }
+      if (i == 1)
+        break;
+      if (okre == 0 && diffre > 1)
+        wpre += diffre;
+      if (okim == 0 && diffim > 1)
+        wpim += diffim;
+      mpfr_set_prec (mpc_realref(ab), wpre);
+      mpfr_set_prec (mpc_imagref(ab), wpim);
+    }
+  mpc_clear (ab);
+  return okre && okim ? inex : mpc_fma_naive (r, a, b, c, rnd);
+}
diff --git a/contrib/mpc/src/fr_div.c b/contrib/mpc/src/fr_div.c
new file mode 100644 (file)
index 0000000..e57eced
--- /dev/null
@@ -0,0 +1,39 @@
+/* mpc_fr_div -- Divide a floating-point number by a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_fr_div (mpc_ptr a, mpfr_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+   mpc_t bc;
+   int inexact;
+
+   mpc_realref (bc)[0] = b [0];
+   mpfr_init (mpc_imagref (bc));
+   /* we consider the operand b to have imaginary part +0 */
+   mpfr_set_ui (mpc_imagref (bc), 0, GMP_RNDN);
+
+   inexact = mpc_div (a, bc, c, rnd);
+
+   mpfr_clear (mpc_imagref (bc));
+
+   return inexact;
+}
diff --git a/contrib/mpc/src/fr_sub.c b/contrib/mpc/src/fr_sub.c
new file mode 100644 (file)
index 0000000..91338a4
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_fr_sub -- Substract a complex number from a floating-point number.
+
+Copyright (C) 2008, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_fr_sub (mpc_ptr a, mpfr_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_sub (mpc_realref (a), b, mpc_realref (c), MPC_RND_RE (rnd));
+  inex_im = mpfr_neg (mpc_imagref (a), mpc_imagref (c), MPC_RND_IM (rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/get_prec.c b/contrib/mpc/src/get_prec.c
new file mode 100644 (file)
index 0000000..f1fe856
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_get_prec -- returns the common precision of real and imaginary part, or 0 if they differ
+
+Copyright (C) 2007, 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+mpfr_prec_t
+mpc_get_prec (mpc_srcptr x)
+{
+  mpfr_prec_t precre = MPC_PREC_RE (x);
+  return (MPC_PREC_IM (x) == precre ? precre : 0);
+}
diff --git a/contrib/mpc/src/get_prec2.c b/contrib/mpc/src/get_prec2.c
new file mode 100644 (file)
index 0000000..79015c8
--- /dev/null
@@ -0,0 +1,29 @@
+/* mpc_get_prec2 -- returns the precisions of the real and of the imaginary
+   part through the first two arguments
+
+Copyright (C) 2007, 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_get_prec2 (mpfr_prec_t *pr, mpfr_prec_t *pi, mpc_srcptr x)
+{
+   *pr = MPC_PREC_RE (x);
+   *pi = MPC_PREC_IM (x);
+}
diff --git a/contrib/mpc/src/get_version.c b/contrib/mpc/src/get_version.c
new file mode 100644 (file)
index 0000000..07c4264
--- /dev/null
@@ -0,0 +1,48 @@
+/* mpc_get_version -- MPC version
+
+Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+#if MPFR_VERSION_MAJOR < 3
+/* The following are functions defined for compatibility with mpfr < 3;
+   logically, they should be defined in a separate file, but then gcc
+   complains about an empty translation unit with mpfr >= 3.            */
+
+void
+mpfr_set_zero (mpfr_ptr z, int s)
+{
+   mpfr_set_ui (z, 0ul, GMP_RNDN);
+   if (s < 0)
+      mpfr_neg (z, z, GMP_RNDN);
+}
+
+int
+mpfr_regular_p (mpfr_srcptr z)
+{
+   return (mpfr_number_p (z) && !mpfr_zero_p (z));
+}
+#endif /* mpfr < 3 */
+
+
+const char *
+mpc_get_version (void)
+{
+  return "1.0.1";
+}
diff --git a/contrib/mpc/src/get_x.c b/contrib/mpc/src/get_x.c
new file mode 100644 (file)
index 0000000..31610ac
--- /dev/null
@@ -0,0 +1,236 @@
+/* mpc_get_dc, mpc_get_ldc -- Transform mpc number into C complex number
+   mpc_get_str -- Convert a complex number into a string.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_COMPLEX_H
+#include <complex.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <stdio.h> /* for sprintf, fprintf */
+#include <ctype.h>
+#include <string.h>
+#include "mpc-impl.h"
+
+#ifdef HAVE_COMPLEX_H
+double _Complex
+mpc_get_dc (mpc_srcptr op, mpc_rnd_t rnd) {
+   return I * mpfr_get_d (mpc_imagref (op), MPC_RND_IM (rnd))
+          + mpfr_get_d (mpc_realref (op), MPC_RND_RE (rnd));
+}
+
+long double _Complex
+mpc_get_ldc (mpc_srcptr op, mpc_rnd_t rnd) {
+   return I * mpfr_get_ld (mpc_imagref (op), MPC_RND_IM (rnd))
+          + mpfr_get_ld (mpc_realref (op), MPC_RND_RE (rnd));
+}
+#endif
+
+
+/* Code for mpc_get_str. The output format is "(real imag)", the decimal point
+   of the locale is used. */
+
+/* mpfr_prec_t can be either int or long int */
+#if (__GMP_MP_SIZE_T_INT == 1)
+#define MPC_EXP_FORMAT_SPEC "i"
+#elif (__GMP_MP_SIZE_T_INT == 0)
+#define MPC_EXP_FORMAT_SPEC "li"
+#else
+#error "mpfr_exp_t size not supported"
+#endif
+
+static char *
+pretty_zero (mpfr_srcptr zero)
+{
+  char *pretty;
+
+  pretty = mpc_alloc_str (3);
+
+  pretty[0] = mpfr_signbit (zero) ? '-' : '+';
+  pretty[1] = '0';
+  pretty[2] = '\0';
+
+  return pretty;
+}
+
+static char *
+prettify (const char *str, const mp_exp_t expo, int base, int special)
+{
+  size_t sz;
+  char *pretty;
+  char *p;
+  const char *s;
+  mp_exp_t x;
+  int sign;
+
+  sz = strlen (str) + 1; /* + terminal '\0' */
+
+  if (special)
+    {
+      /* special number: nan or inf */
+      pretty = mpc_alloc_str (sz);
+      strcpy (pretty, str);
+
+      return pretty;
+    }
+
+  /* regular number */
+
+  sign = (str[0] == '-' || str[0] == '+');
+
+  x = expo - 1; /* expo is the exponent value with decimal point BEFORE
+                   the first digit, we wants decimal point AFTER the first
+                   digit */
+  if (base == 16)
+    x <<= 2; /* the output exponent is a binary exponent */
+
+  ++sz; /* + decimal point */
+
+  if (x != 0)
+    {
+      /* augment sz with the size needed for an exponent written in base
+         ten */
+      mp_exp_t xx;
+
+      sz += 3; /* + exponent char + sign + 1 digit */
+
+      if (x < 0)
+        {
+          /* avoid overflow when changing sign (assuming that, for the
+             mp_exp_t type, (max value) is greater than (- min value / 10)) */
+          if (x < -10)
+            {
+              xx = - (x / 10);
+              sz++;
+            }
+          else
+            xx = -x;
+        }
+      else
+        xx = x;
+
+      /* compute sz += floor(log(expo)/log(10)) without using libm
+         functions */
+      while (xx > 9)
+        {
+          sz++;
+          xx /= 10;
+        }
+    }
+
+  pretty = mpc_alloc_str (sz);
+  p = pretty;
+
+  /* 1. optional sign plus first digit */
+  s = str;
+  *p++ = *s++;
+  if (sign)
+    *p++ = *s++;
+
+  /* 2. decimal point */
+#ifdef HAVE_LOCALECONV
+  *p++ = *localeconv ()->decimal_point;
+#else
+  *p++ = '.';
+#endif
+  *p = '\0';
+
+  /* 3. other significant digits */
+  strcat (pretty, s);
+
+  /* 4. exponent (in base ten) */
+  if (x == 0)
+    return pretty;
+
+  p = pretty + strlen (str) + 1;
+
+  switch (base)
+    {
+    case 10:
+      *p++ = 'e';
+      break;
+    case 2:
+    case 16:
+      *p++ = 'p';
+      break;
+    default:
+      *p++ = '@';
+    }
+
+  *p = '\0';
+
+  sprintf (p, "%+"MPC_EXP_FORMAT_SPEC, x);
+
+  return pretty;
+}
+
+static char *
+get_pretty_str (const int base, const size_t n, mpfr_srcptr x, mpfr_rnd_t rnd)
+{
+  mp_exp_t expo;
+  char *ugly;
+  char *pretty;
+
+  if (mpfr_zero_p (x))
+    return pretty_zero (x);
+
+  ugly = mpfr_get_str (NULL, &expo, base, n, x, rnd);
+  MPC_ASSERT (ugly != NULL);
+  pretty = prettify (ugly, expo, base, !mpfr_number_p (x));
+  mpfr_free_str (ugly);
+
+  return pretty;
+}
+
+char *
+mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  size_t needed_size;
+  char *real_str;
+  char *imag_str;
+  char *complex_str = NULL;
+
+  if (base < 2 || base > 36)
+    return NULL;
+
+  real_str = get_pretty_str (base, n, mpc_realref (op), MPC_RND_RE (rnd));
+  imag_str = get_pretty_str (base, n, mpc_imagref (op), MPC_RND_IM (rnd));
+
+  needed_size = strlen (real_str) + strlen (imag_str) + 4;
+
+  complex_str = mpc_alloc_str (needed_size);
+MPC_ASSERT (complex_str != NULL);
+
+  strcpy (complex_str, "(");
+  strcat (complex_str, real_str);
+  strcat (complex_str, " ");
+  strcat (complex_str, imag_str);
+  strcat (complex_str, ")");
+
+  mpc_free_str (real_str);
+  mpc_free_str (imag_str);
+
+  return complex_str;
+}
diff --git a/contrib/mpc/src/imag.c b/contrib/mpc/src/imag.c
new file mode 100644 (file)
index 0000000..5f3b3a5
--- /dev/null
@@ -0,0 +1,27 @@
+/* mpc_imag -- Get the imaginary part of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_imag (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+  return mpfr_set (a, mpc_imagref (b), rnd);
+}
diff --git a/contrib/mpc/src/init2.c b/contrib/mpc/src/init2.c
new file mode 100644 (file)
index 0000000..ce4173e
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_init2 -- Initialize a complex variable with a given precision.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_init2 (mpc_t x, mpfr_prec_t prec)
+{
+  mpfr_init2 (mpc_realref(x), prec);
+  mpfr_init2 (mpc_imagref(x), prec);
+}
diff --git a/contrib/mpc/src/init3.c b/contrib/mpc/src/init3.c
new file mode 100644 (file)
index 0000000..69f91b2
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_init3 -- Initialize a complex variable with given precisions.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_init3 (mpc_t x, mpfr_prec_t prec_re, mpfr_prec_t prec_im)
+{
+  mpfr_init2 (mpc_realref(x), prec_re);
+  mpfr_init2 (mpc_imagref(x), prec_im);
+}
diff --git a/contrib/mpc/src/inp_str.c b/contrib/mpc/src/inp_str.c
new file mode 100644 (file)
index 0000000..695a3ad
--- /dev/null
@@ -0,0 +1,239 @@
+/* mpc_inp_str -- Input a complex number from a given stream.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for FILE */
+#include <ctype.h>
+#include <string.h>
+#include "mpc-impl.h"
+
+static size_t
+skip_whitespace (FILE *stream)
+{
+   int c = getc (stream);
+   size_t size = 0;
+   while (c != EOF && isspace ((unsigned char) c)) {
+      c = getc (stream);
+      size++;
+   }
+   if (c != EOF)
+      ungetc (c, stream);
+   return size;
+}
+
+/* Extract from stream the longest string made up of alphanumeric char and
+   '_' (i.e. n-char-sequence).
+   The user must free the returned string. */
+static char *
+extract_suffix (FILE *stream)
+{
+  int c;
+  size_t nread = 0;
+  size_t strsize = 100;
+  char *str = mpc_alloc_str (strsize);
+
+  c = getc (stream);
+  while (isalnum ((unsigned char) c) || c == '_') {
+    str [nread] = (char) c;
+    nread++;
+    if (nread == strsize) {
+      str = mpc_realloc_str (str, strsize, 2 * strsize);
+      strsize *= 2;
+         }
+    c = getc (stream);
+  }
+
+  str = mpc_realloc_str (str, strsize, nread + 1);
+  strsize = nread + 1;
+  str [nread] = '\0';
+
+  if (c != EOF)
+    ungetc (c, stream);
+  return str;
+}
+
+
+/* Extract from the stream the longest string of characters which are neither
+   whitespace nor brackets (except for an optional bracketed n-char_sequence
+   directly following nan or @nan@ independently of case).
+   The user must free the returned string.                                    */
+static char *
+extract_string (FILE *stream)
+{
+  int c;
+  size_t nread = 0;
+  size_t strsize = 100;
+  char *str = mpc_alloc_str (strsize);
+  size_t lenstr;
+
+  c = getc (stream);
+  while (c != EOF && c != '\n'
+         && !isspace ((unsigned char) c)
+         && c != '(' && c != ')') {
+    str [nread] = (char) c;
+    nread++;
+    if (nread == strsize) {
+      str = mpc_realloc_str (str, strsize, 2 * strsize);
+      strsize *= 2;
+    }
+    c = getc (stream);
+  }
+
+  str = mpc_realloc_str (str, strsize, nread + 1);
+  strsize = nread + 1;
+  str [nread] = '\0';
+
+  if (nread == 0)
+    return str;
+
+  lenstr = nread;
+
+  if (c == '(') {
+    size_t n;
+    char *suffix;
+    int ret;
+
+    /* (n-char-sequence) only after a NaN */
+    if ((nread != 3
+         || tolower ((unsigned char) (str[0])) != 'n'
+         || tolower ((unsigned char) (str[1])) != 'a'
+         || tolower ((unsigned char) (str[2])) != 'n')
+        && (nread != 5
+            || str[0] != '@'
+            || tolower ((unsigned char) (str[1])) != 'n'
+            || tolower ((unsigned char) (str[2])) != 'a'
+            || tolower ((unsigned char) (str[3])) != 'n'
+            || str[4] != '@')) {
+      ungetc (c, stream);
+      return str;
+    }
+
+    suffix = extract_suffix (stream);
+    nread += strlen (suffix) + 1;
+    if (nread >= strsize) {
+      str = mpc_realloc_str (str, strsize, nread + 1);
+      strsize = nread + 1;
+    }
+
+    /* Warning: the sprintf does not allow overlap between arguments. */
+    ret = sprintf (str + lenstr, "(%s", suffix);
+    MPC_ASSERT (ret >= 0);
+    n = lenstr + (size_t) ret;
+    MPC_ASSERT (n == nread);
+
+    c = getc (stream);
+    if (c == ')') {
+      str = mpc_realloc_str (str, strsize, nread + 2);
+      strsize = nread + 2;
+      str [nread] = (char) c;
+      str [nread+1] = '\0';
+      nread++;
+    }
+    else if (c != EOF)
+      ungetc (c, stream);
+
+    mpc_free_str (suffix);
+  }
+  else if (c != EOF)
+    ungetc (c, stream);
+
+  return str;
+}
+
+
+int
+mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base,
+mpc_rnd_t rnd_mode)
+{
+   size_t white, nread = 0;
+   int inex = -1;
+   int c;
+   char *str;
+
+   if (stream == NULL)
+      stream = stdin;
+
+   white = skip_whitespace (stream);
+   c = getc (stream);
+   if (c != EOF) {
+     if (c == '(') {
+       char *real_str;
+       char *imag_str;
+       size_t n;
+       int ret;
+
+       nread++; /* the opening parenthesis */
+       white = skip_whitespace (stream);
+       real_str = extract_string (stream);
+       nread += strlen(real_str);
+
+       c = getc (stream);
+       if (!isspace ((unsigned int) c)) {
+         if (c != EOF)
+           ungetc (c, stream);
+         mpc_free_str (real_str);
+         goto error;
+       }
+       else
+         ungetc (c, stream);
+
+       white += skip_whitespace (stream);
+       imag_str = extract_string (stream);
+       nread += strlen (imag_str);
+
+       str = mpc_alloc_str (nread + 2);
+       ret = sprintf (str, "(%s %s", real_str, imag_str);
+       MPC_ASSERT (ret >= 0);
+       n = (size_t) ret;
+       MPC_ASSERT (n == nread + 1);
+       mpc_free_str (real_str);
+       mpc_free_str (imag_str);
+
+       white += skip_whitespace (stream);
+       c = getc (stream);
+       if (c == ')') {
+         str = mpc_realloc_str (str, nread +2, nread + 3);
+         str [nread+1] = (char) c;
+         str [nread+2] = '\0';
+         nread++;
+       }
+       else if (c != EOF)
+         ungetc (c, stream);
+     }
+     else {
+       if (c != EOF)
+         ungetc (c, stream);
+       str = extract_string (stream);
+       nread += strlen (str);
+     }
+
+     inex = mpc_set_str (rop, str, base, rnd_mode);
+
+     mpc_free_str (str);
+   }
+
+error:
+   if (inex == -1) {
+      mpfr_set_nan (mpc_realref(rop));
+      mpfr_set_nan (mpc_imagref(rop));
+   }
+   if (read != NULL)
+     *read = white + nread;
+   return inex;
+}
diff --git a/contrib/mpc/src/log.c b/contrib/mpc/src/log.c
new file mode 100644 (file)
index 0000000..ad1d448
--- /dev/null
@@ -0,0 +1,217 @@
+/* mpc_log -- Take the logarithm of a complex number.
+
+Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+int
+mpc_log (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd){
+   int ok, underflow = 0;
+   mpfr_srcptr x, y;
+   mpfr_t v, w;
+   mpfr_prec_t prec;
+   int loops;
+   int re_cmp, im_cmp;
+   int inex_re, inex_im;
+   int err;
+   mpfr_exp_t expw;
+   int sgnw;
+
+   /* special values: NaN and infinities */
+   if (!mpc_fin_p (op)) {
+      if (mpfr_nan_p (mpc_realref (op))) {
+         if (mpfr_inf_p (mpc_imagref (op)))
+            mpfr_set_inf (mpc_realref (rop), +1);
+         else
+            mpfr_set_nan (mpc_realref (rop));
+         mpfr_set_nan (mpc_imagref (rop));
+         inex_im = 0; /* Inf/NaN is exact */
+      }
+      else if (mpfr_nan_p (mpc_imagref (op))) {
+         if (mpfr_inf_p (mpc_realref (op)))
+            mpfr_set_inf (mpc_realref (rop), +1);
+         else
+            mpfr_set_nan (mpc_realref (rop));
+         mpfr_set_nan (mpc_imagref (rop));
+         inex_im = 0; /* Inf/NaN is exact */
+      }
+      else /* We have an infinity in at least one part. */ {
+         inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+                               MPC_RND_IM (rnd));
+         mpfr_set_inf (mpc_realref (rop), +1);
+      }
+      return MPC_INEX(0, inex_im);
+   }
+
+   /* special cases: real and purely imaginary numbers */
+   re_cmp = mpfr_cmp_ui (mpc_realref (op), 0);
+   im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0);
+   if (im_cmp == 0) {
+      if (re_cmp == 0) {
+         inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+                               MPC_RND_IM (rnd));
+         mpfr_set_inf (mpc_realref (rop), -1);
+         inex_re = 0; /* -Inf is exact */
+      }
+      else if (re_cmp > 0) {
+         inex_re = mpfr_log (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+         inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+      }
+      else {
+         /* op = x + 0*y; let w = -x = |x| */
+         int negative_zero;
+         mpfr_rnd_t rnd_im;
+
+         negative_zero = mpfr_signbit (mpc_imagref (op));
+         if (negative_zero)
+            rnd_im = INV_RND (MPC_RND_IM (rnd));
+         else
+            rnd_im = MPC_RND_IM (rnd);
+         w [0] = *mpc_realref (op);
+         MPFR_CHANGE_SIGN (w);
+         inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd));
+         inex_im = mpfr_const_pi (mpc_imagref (rop), rnd_im);
+         if (negative_zero) {
+            mpc_conj (rop, rop, MPC_RNDNN);
+            inex_im = -inex_im;
+         }
+      }
+      return MPC_INEX(inex_re, inex_im);
+   }
+   else if (re_cmp == 0) {
+      if (im_cmp > 0) {
+         inex_re = mpfr_log (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd));
+         inex_im = mpfr_const_pi (mpc_imagref (rop), MPC_RND_IM (rnd));
+         /* division by 2 does not change the ternary flag */
+         mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+      }
+      else {
+         w [0] = *mpc_imagref (op);
+         MPFR_CHANGE_SIGN (w);
+         inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd));
+         inex_im = mpfr_const_pi (mpc_imagref (rop), INV_RND (MPC_RND_IM (rnd)));
+         /* division by 2 does not change the ternary flag */
+         mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+         mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+         inex_im = -inex_im; /* negate the ternary flag */
+      }
+      return MPC_INEX(inex_re, inex_im);
+   }
+
+   prec = MPC_PREC_RE(rop);
+   mpfr_init2 (w, 2);
+   /* let op = x + iy; log = 1/2 log (x^2 + y^2) + i atan2 (y, x)   */
+   /* loop for the real part: 1/2 log (x^2 + y^2), fast, but unsafe */
+   /* implementation                                                */
+   ok = 0;
+   for (loops = 1; !ok && loops <= 2; loops++) {
+      prec += mpc_ceil_log2 (prec) + 4;
+      mpfr_set_prec (w, prec);
+
+      mpc_abs (w, op, GMP_RNDN);
+         /* error 0.5 ulp */
+      if (mpfr_inf_p (w))
+         /* intermediate overflow; the logarithm may be representable.
+            Intermediate underflow is impossible.                      */
+         break;
+
+      mpfr_log (w, w, GMP_RNDN);
+         /* generic error of log: (2^(- exp(w)) + 0.5) ulp */
+
+      if (mpfr_zero_p (w))
+         /* impossible to round, switch to second algorithm */
+         break;
+
+      err = MPC_MAX (-mpfr_get_exp (w), 0) + 1;
+         /* number of lost digits */
+      ok = mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ,
+         mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN));
+   }
+
+   if (!ok) {
+      prec = MPC_PREC_RE(rop);
+      mpfr_init2 (v, 2);
+      /* compute 1/2 log (x^2 + y^2) = log |x| + 1/2 * log (1 + (y/x)^2)
+            if |x| >= |y|; otherwise, exchange x and y                   */
+      if (mpfr_cmpabs (mpc_realref (op), mpc_imagref (op)) >= 0) {
+         x = mpc_realref (op);
+         y = mpc_imagref (op);
+      }
+      else {
+         x = mpc_imagref (op);
+         y = mpc_realref (op);
+      }
+
+      do {
+         prec += mpc_ceil_log2 (prec) + 4;
+         mpfr_set_prec (v, prec);
+         mpfr_set_prec (w, prec);
+
+         mpfr_div (v, y, x, GMP_RNDD); /* error 1 ulp */
+         mpfr_sqr (v, v, GMP_RNDD);
+            /* generic error of multiplication:
+               1 + 2*1*(2+1*2^(1-prec)) <= 5.0625 since prec >= 6 */
+         mpfr_log1p (v, v, GMP_RNDD);
+            /* error 1 + 4*5.0625 = 21.25 , see algorithms.tex */
+         mpfr_div_2ui (v, v, 1, GMP_RNDD);
+            /* If the result is 0, then there has been an underflow somewhere. */
+
+         mpfr_abs (w, x, GMP_RNDN); /* exact */
+         mpfr_log (w, w, GMP_RNDN); /* error 0.5 ulp */
+         expw = mpfr_get_exp (w);
+         sgnw = mpfr_signbit (w);
+
+         mpfr_add (w, w, v, GMP_RNDN);
+         if (!sgnw) /* v is positive, so no cancellation;
+                       error 22.25 ulp; error counts lost bits */
+            err = 5;
+         else
+            err =   MPC_MAX (5 + mpfr_get_exp (v),
+                  /* 21.25 ulp (v) rewritten in ulp (result, now in w) */
+                           -1 + expw             - mpfr_get_exp (w)
+                  /* 0.5 ulp (previous w), rewritten in ulp (result) */
+                  ) + 2;
+
+         /* handle one special case: |x|=1, and (y/x)^2 underflows;
+            then 1/2*log(x^2+y^2) \approx 1/2*y^2 also underflows.  */
+         if (   (mpfr_cmp_si (x, -1) == 0 || mpfr_cmp_ui (x, 1) == 0)
+             && mpfr_zero_p (w))
+            underflow = 1;
+
+      } while (!underflow &&
+               !mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ,
+               mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN)));
+      mpfr_clear (v);
+   }
+
+   /* imaginary part */
+   inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+                         MPC_RND_IM (rnd));
+
+   /* set the real part; cannot be done before if rop==op */
+   if (underflow)
+      /* create underflow in result */
+      inex_re = mpfr_set_ui_2exp (mpc_realref (rop), 1,
+                                  mpfr_get_emin_min () - 2, MPC_RND_RE (rnd));
+   else
+      inex_re = mpfr_set (mpc_realref (rop), w, MPC_RND_RE (rnd));
+   mpfr_clear (w);
+   return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/log10.c b/contrib/mpc/src/log10.c
new file mode 100644 (file)
index 0000000..a6fc86c
--- /dev/null
@@ -0,0 +1,297 @@
+/* mpc_log10 -- Take the base-10 logarithm of a complex number.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <limits.h> /* for CHAR_BIT */
+#include "mpc-impl.h"
+
+/* Auxiliary functions which implement Ziv's strategy for special cases.
+   if flag = 0: compute only real part
+   if flag = 1: compute only imaginary
+   Exact cases should be dealt with separately. */
+static int
+mpc_log10_aux (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd, int flag, int nb)
+{
+  mp_prec_t prec = (MPFR_PREC_MIN > 4) ? MPFR_PREC_MIN : 4;
+  mpc_t tmp;
+  mpfr_t log10;
+  int ok = 0, ret;
+
+  prec = mpfr_get_prec ((flag == 0) ? mpc_realref (rop) : mpc_imagref (rop));
+  prec += 10;
+  mpc_init2 (tmp, prec);
+  mpfr_init2 (log10, prec);
+  while (ok == 0)
+    {
+      mpfr_set_ui (log10, 10, GMP_RNDN); /* exact since prec >= 4 */
+      mpfr_log (log10, log10, GMP_RNDN);
+      /* In each case we have two roundings, thus the final value is
+         x * (1+u)^2 where x is the exact value, and |u| <= 2^(-prec-1).
+         Thus the error is always less than 3 ulps. */
+      switch (nb)
+        {
+        case 0: /* imag <- atan2(y/x) */
+          mpfr_atan2 (mpc_imagref (tmp), mpc_imagref (op), mpc_realref (op),
+                      MPC_RND_IM (rnd));
+          mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN);
+          ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN,
+                               GMP_RNDZ, MPC_PREC_IM(rop) +
+                               (MPC_RND_IM (rnd) == GMP_RNDN));
+          if (ok)
+            ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp),
+                            MPC_RND_IM (rnd));
+          break;
+        case 1: /* real <- log(x) */
+          mpfr_log (mpc_realref (tmp), mpc_realref (op), MPC_RND_RE (rnd));
+          mpfr_div (mpc_realref (tmp), mpc_realref (tmp), log10, GMP_RNDN);
+          ok = mpfr_can_round (mpc_realref (tmp), prec - 2, GMP_RNDN,
+                               GMP_RNDZ, MPC_PREC_RE(rop) +
+                               (MPC_RND_RE (rnd) == GMP_RNDN));
+          if (ok)
+            ret = mpfr_set (mpc_realref (rop), mpc_realref (tmp),
+                            MPC_RND_RE (rnd));
+          break;
+        case 2: /* imag <- pi */
+          mpfr_const_pi (mpc_imagref (tmp), MPC_RND_IM (rnd));
+          mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN);
+          ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN,
+                               GMP_RNDZ, MPC_PREC_IM(rop) +
+                               (MPC_RND_IM (rnd) == GMP_RNDN));
+          if (ok)
+            ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp),
+                            MPC_RND_IM (rnd));
+          break;
+        case 3: /* real <- log(y) */
+          mpfr_log (mpc_realref (tmp), mpc_imagref (op), MPC_RND_RE (rnd));
+          mpfr_div (mpc_realref (tmp), mpc_realref (tmp), log10, GMP_RNDN);
+          ok = mpfr_can_round (mpc_realref (tmp), prec - 2, GMP_RNDN,
+                               GMP_RNDZ, MPC_PREC_RE(rop) +
+                               (MPC_RND_RE (rnd) == GMP_RNDN));
+          if (ok)
+            ret = mpfr_set (mpc_realref (rop), mpc_realref (tmp),
+                            MPC_RND_RE (rnd));
+          break;
+        }
+      prec += prec / 2;
+      mpc_set_prec (tmp, prec);
+      mpfr_set_prec (log10, prec);
+    }
+  mpc_clear (tmp);
+  mpfr_clear (log10);
+  return ret;
+}
+
+int
+mpc_log10 (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  int ok = 0, loops = 0, re_cmp, im_cmp, inex_re, inex_im, negative_zero;
+  mpfr_t w;
+  mpfr_prec_t prec;
+  mpfr_rnd_t rnd_im;
+  mpc_t ww;
+  mpc_rnd_t invrnd;
+
+  /* special values: NaN and infinities: same as mpc_log */
+  if (!mpc_fin_p (op)) /* real or imaginary parts are NaN or Inf */
+    {
+      if (mpfr_nan_p (mpc_realref (op)))
+        {
+          if (mpfr_inf_p (mpc_imagref (op)))
+            /* (NaN, Inf) -> (+Inf, NaN) */
+            mpfr_set_inf (mpc_realref (rop), +1);
+          else
+            /* (NaN, xxx) -> (NaN, NaN) */
+            mpfr_set_nan (mpc_realref (rop));
+         mpfr_set_nan (mpc_imagref (rop));
+         inex_im = 0; /* Inf/NaN is exact */
+        }
+      else if (mpfr_nan_p (mpc_imagref (op)))
+        {
+          if (mpfr_inf_p (mpc_realref (op)))
+            /* (Inf, NaN) -> (+Inf, NaN) */
+            mpfr_set_inf (mpc_realref (rop), +1);
+          else
+            /* (xxx, NaN) -> (NaN, NaN) */
+            mpfr_set_nan (mpc_realref (rop));
+          mpfr_set_nan (mpc_imagref (rop));
+          inex_im = 0; /* Inf/NaN is exact */
+        }
+      else /* We have an infinity in at least one part. */
+        {
+          /* (+Inf, y) -> (+Inf, 0) for finite positive-signed y */
+          if (mpfr_inf_p (mpc_realref (op)) && mpfr_signbit (mpc_realref (op))
+              == 0 && mpfr_number_p (mpc_imagref (op)))
+            inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op),
+                                  mpc_realref (op), MPC_RND_IM (rnd));
+          else
+            /* (xxx, Inf) -> (+Inf, atan2(Inf/xxx))
+               (Inf, yyy) -> (+Inf, atan2(yyy/Inf)) */
+            inex_im = mpc_log10_aux (rop, op, rnd, 1, 0);
+          mpfr_set_inf (mpc_realref (rop), +1);
+        }
+      return MPC_INEX(0, inex_im);
+    }
+
+   /* special cases: real and purely imaginary numbers */
+  re_cmp = mpfr_cmp_ui (mpc_realref (op), 0);
+  im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0);
+  if (im_cmp == 0) /* Im(op) = 0 */
+    {
+      if (re_cmp == 0) /* Re(op) = 0 */
+        {
+          if (mpfr_signbit (mpc_realref (op)) == 0)
+            inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op),
+                                  mpc_realref (op), MPC_RND_IM (rnd));
+          else
+            inex_im = mpc_log10_aux (rop, op, rnd, 1, 0);
+          mpfr_set_inf (mpc_realref (rop), -1);
+          inex_re = 0; /* -Inf is exact */
+        }
+      else if (re_cmp > 0)
+        {
+          inex_re = mpfr_log10 (mpc_realref (rop), mpc_realref (op),
+                                MPC_RND_RE (rnd));
+          inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op),
+                              MPC_RND_IM (rnd));
+        }
+      else /* log10(x + 0*i) for negative x */
+        { /* op = x + 0*i; let w = -x = |x| */
+          negative_zero = mpfr_signbit (mpc_imagref (op));
+          if (negative_zero)
+            rnd_im = INV_RND (MPC_RND_IM (rnd));
+          else
+            rnd_im = MPC_RND_IM (rnd);
+          ww->re[0] = *mpc_realref (op);
+          MPFR_CHANGE_SIGN (ww->re);
+          ww->im[0] = *mpc_imagref (op);
+          if (mpfr_cmp_ui (ww->re, 1) == 0)
+            inex_re = mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+          else
+            inex_re = mpc_log10_aux (rop, ww, rnd, 0, 1);
+          inex_im = mpc_log10_aux (rop, op, MPC_RND (0,rnd_im), 1, 2);
+          if (negative_zero)
+            {
+              mpc_conj (rop, rop, MPC_RNDNN);
+              inex_im = -inex_im;
+            }
+        }
+      return MPC_INEX(inex_re, inex_im);
+    }
+   else if (re_cmp == 0)
+     {
+       if (im_cmp > 0)
+         {
+           inex_re = mpc_log10_aux (rop, op, rnd, 0, 3);
+           inex_im = mpc_log10_aux (rop, op, rnd, 1, 2);
+           /* division by 2 does not change the ternary flag */
+           mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+         }
+       else
+         {
+           ww->re[0] = *mpc_realref (op);
+           ww->im[0] = *mpc_imagref (op);
+           MPFR_CHANGE_SIGN (ww->im);
+           inex_re = mpc_log10_aux (rop, ww, rnd, 0, 3);
+           invrnd = MPC_RND (0, INV_RND (MPC_RND_IM (rnd)));
+           inex_im = mpc_log10_aux (rop, op, invrnd, 1, 2);
+           /* division by 2 does not change the ternary flag */
+           mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+           mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+           inex_im = -inex_im; /* negate the ternary flag */
+         }
+       return MPC_INEX(inex_re, inex_im);
+     }
+
+  /* generic case: neither Re(op) nor Im(op) is NaN, Inf or zero */
+  prec = MPC_PREC_RE(rop);
+  mpfr_init2 (w, prec);
+  mpc_init2 (ww, prec);
+  /* let op = x + iy; compute log(op)/log(10) */
+  while (ok == 0)
+    {
+      loops ++;
+      prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
+      mpfr_set_prec (w, prec);
+      mpc_set_prec (ww, prec);
+
+      mpc_log (ww, op, MPC_RNDNN);
+      mpfr_set_ui (w, 10, GMP_RNDN); /* exact since prec >= 4 */
+      mpfr_log (w, w, GMP_RNDN);
+      mpc_div_fr (ww, ww, w, MPC_RNDNN);
+
+      ok = mpfr_can_round (mpc_realref (ww), prec - 2, GMP_RNDN, GMP_RNDZ,
+                           MPC_PREC_RE(rop) + (MPC_RND_RE (rnd) == GMP_RNDN));
+
+      /* Special code to deal with cases where the real part of log10(x+i*y)
+         is exact, like x=3 and y=1. Since Re(log10(x+i*y)) = log10(x^2+y^2)/2
+         this happens whenever x^2+y^2 is a nonnegative power of 10.
+         Indeed x^2+y^2 cannot equal 10^(a/2^b) for a, b integers, a odd, b>0,
+         since x^2+y^2 is rational, and 10^(a/2^b) is irrational.
+         Similarly, for b=0, x^2+y^2 cannot equal 10^a for a < 0 since x^2+y^2
+         is a rational with denominator a power of 2.
+         Now let x^2+y^2 = 10^s. Without loss of generality we can assume
+         x = u/2^e and y = v/2^e with u, v, e integers: u^2+v^2 = 10^s*2^(2e)
+         thus u^2+v^2 = 0 mod 2^(2e). By recurrence on e, necessarily
+         u = v = 0 mod 2^e, thus x and y are necessarily integers.
+      */
+      if ((ok == 0) && (loops == 1) && mpfr_integer_p (mpc_realref (op)) &&
+          mpfr_integer_p (mpc_imagref (op)))
+        {
+          mpz_t x, y;
+          unsigned long s, v;
+
+          mpz_init (x);
+          mpz_init (y);
+          mpfr_get_z (x, mpc_realref (op), GMP_RNDN); /* exact */
+          mpfr_get_z (y, mpc_imagref (op), GMP_RNDN); /* exact */
+          mpz_mul (x, x, x);
+          mpz_mul (y, y, y);
+          mpz_add (x, x, y); /* x^2+y^2 */
+          v = mpz_scan1 (x, 0);
+          /* if x = 10^s then necessarily s = v */
+          s = mpz_sizeinbase (x, 10);
+          /* since s is either the number of digits of x or one more,
+             then x = 10^(s-1) or 10^(s-2) */
+          if (s == v + 1 || s == v + 2)
+            {
+              mpz_div_2exp (x, x, v);
+              mpz_ui_pow_ui (y, 5, v);
+              if (mpz_cmp (y, x) == 0) /* Re(log10(x+i*y)) is exactly v/2 */
+                {
+                  /* we reset the precision of Re(ww) so that v can be
+                     represented exactly */
+                  mpfr_set_prec (mpc_realref (ww), sizeof(unsigned long)*CHAR_BIT);
+                  mpfr_set_ui_2exp (mpc_realref (ww), v, -1, GMP_RNDN); /* exact */
+                  ok = 1;
+                }
+            }
+          mpz_clear (x);
+          mpz_clear (y);
+        }
+
+      ok = ok && mpfr_can_round (mpc_imagref (ww), prec-2, GMP_RNDN, GMP_RNDZ,
+                            MPC_PREC_IM(rop) + (MPC_RND_IM (rnd) == GMP_RNDN));
+    }
+
+  inex_re = mpfr_set (mpc_realref(rop), mpc_realref (ww), MPC_RND_RE (rnd));
+  inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref (ww), MPC_RND_IM (rnd));
+  mpfr_clear (w);
+  mpc_clear (ww);
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/logging.c b/contrib/mpc/src/logging.c
new file mode 100644 (file)
index 0000000..79ed033
--- /dev/null
@@ -0,0 +1,147 @@
+/* logging.c -- "Dummy" functions logging calls to real mpc functions.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+#include <stdio.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#define __MPC_LIBRARY_BUILD
+   /* to indicate we are inside the library build; needed here since mpc-log.h
+      includes mpc.h and not mpc-impl.h */
+#include "mpc-log.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+typedef int (*c_c_func_ptr) (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*c_cc_func_ptr) (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*c_ccc_func_ptr) (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*cc_c_func_ptr) (mpc_ptr, mpc_ptr, mpc_srcptr, mpc_rnd_t, mpc_rnd_t);
+
+#define MPC_LOGGING_OUT_PREC(z) \
+   do { \
+      fprintf (stderr, " %li %li", (long) mpfr_get_prec (mpc_realref (z)),  \
+                                (long) mpfr_get_prec (mpc_imagref (z))); \
+   } while (0);
+
+#define MPC_LOGGING_OUT_C(z) \
+   do { \
+      MPC_LOGGING_OUT_PREC (z); \
+      fprintf (stderr, " "); \
+      mpc_out_str (stderr, 16, 0, z, MPC_RNDNN); \
+   } while (0);
+
+#define MPC_LOGGING_FUNC_TYPE(funcname, type) \
+   do { \
+      fprintf (stderr, "mpc_"#funcname" "#type); \
+   } while (0);
+
+#define MPC_LOGGING_C_C(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) \
+{ \
+   static c_c_func_ptr func = NULL; \
+   if (func == NULL) \
+      func = (c_c_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+   MPC_LOGGING_FUNC_TYPE (funcname, c_c); \
+   MPC_LOGGING_OUT_PREC (rop); \
+   MPC_LOGGING_OUT_C (op); \
+   fprintf (stderr, "\n"); \
+   return func (rop, op, rnd); \
+}
+
+#define MPC_LOGGING_C_CC(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd) \
+{ \
+   static c_cc_func_ptr func = NULL; \
+   if (func == NULL) \
+      func = (c_cc_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+   MPC_LOGGING_FUNC_TYPE (funcname, c_cc); \
+   MPC_LOGGING_OUT_PREC (rop); \
+   MPC_LOGGING_OUT_C (op1); \
+   MPC_LOGGING_OUT_C (op2); \
+   fprintf (stderr, "\n"); \
+   return func (rop, op1, op2, rnd); \
+}
+
+#define MPC_LOGGING_C_CCC(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_srcptr op3, mpc_rnd_t rnd) \
+{ \
+   static c_ccc_func_ptr func = NULL; \
+   if (func == NULL) \
+      func = (c_ccc_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+   MPC_LOGGING_FUNC_TYPE (funcname, c_ccc); \
+   MPC_LOGGING_OUT_PREC (rop); \
+   MPC_LOGGING_OUT_C (op1); \
+   MPC_LOGGING_OUT_C (op2); \
+   MPC_LOGGING_OUT_C (op3); \
+   fprintf (stderr, "\n"); \
+   return func (rop, op1, op2, op3, rnd); \
+}
+
+#define MPC_LOGGING_CC_C(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop1, mpc_ptr rop2, mpc_srcptr op, mpc_rnd_t rnd1, mpc_rnd_t rnd2) \
+{ \
+   static cc_c_func_ptr func = NULL; \
+   if (func == NULL) \
+      func = (cc_c_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+   MPC_LOGGING_FUNC_TYPE (funcname, cc_c); \
+   MPC_LOGGING_OUT_PREC (rop1); \
+   MPC_LOGGING_OUT_PREC (rop2); \
+   MPC_LOGGING_OUT_C (op); \
+   fprintf (stderr, "\n"); \
+   return func (rop1, rop2, op, rnd1, rnd2); \
+}
+
+MPC_LOGGING_C_C (sqr)
+MPC_LOGGING_C_C (conj)
+MPC_LOGGING_C_C (neg)
+MPC_LOGGING_C_C (sqrt)
+MPC_LOGGING_C_C (proj)
+MPC_LOGGING_C_C (exp)
+MPC_LOGGING_C_C (log)
+MPC_LOGGING_C_C (sin)
+MPC_LOGGING_C_C (cos)
+MPC_LOGGING_C_C (tan)
+MPC_LOGGING_C_C (sinh)
+MPC_LOGGING_C_C (cosh)
+MPC_LOGGING_C_C (tanh)
+MPC_LOGGING_C_C (asin)
+MPC_LOGGING_C_C (acos)
+MPC_LOGGING_C_C (atan)
+MPC_LOGGING_C_C (asinh)
+MPC_LOGGING_C_C (acosh)
+MPC_LOGGING_C_C (atanh)
+
+MPC_LOGGING_C_CC (add)
+MPC_LOGGING_C_CC (sub)
+MPC_LOGGING_C_CC (mul)
+MPC_LOGGING_C_CC (div)
+MPC_LOGGING_C_CC (pow)
+
+MPC_LOGGING_C_CCC (fma)
+
+MPC_LOGGING_CC_C (sin_cos)
diff --git a/contrib/mpc/src/mem.c b/contrib/mpc/src/mem.c
new file mode 100644 (file)
index 0000000..b4c327c
--- /dev/null
@@ -0,0 +1,46 @@
+/* wrapper functions to allocate, reallocate and free memory
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <string.h>   /* for strlen */
+#include "mpc-impl.h"
+
+char *
+mpc_alloc_str (size_t len)
+{
+  void * (*allocfunc) (size_t);
+  mp_get_memory_functions (&allocfunc, NULL, NULL);
+  return (char *) ((*allocfunc) (len));
+}
+
+char *
+mpc_realloc_str (char * str, size_t oldlen, size_t newlen)
+{
+  void * (*reallocfunc) (void *, size_t, size_t);
+  mp_get_memory_functions (NULL, &reallocfunc, NULL);
+  return (char *) ((*reallocfunc) (str, oldlen, newlen));
+}
+
+void
+mpc_free_str (char *str)
+{
+  void (*freefunc) (void *, size_t);
+  mp_get_memory_functions (NULL, NULL, &freefunc);
+  (*freefunc) (str, strlen (str) + 1);
+}
diff --git a/contrib/mpc/src/mpc-impl.h b/contrib/mpc/src/mpc-impl.h
new file mode 100644 (file)
index 0000000..b2aaa90
--- /dev/null
@@ -0,0 +1,194 @@
+/* mpc-impl.h -- Internal include file for mpc.
+
+Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#ifndef __MPC_IMPL_H
+#define __MPC_IMPL_H
+#define __MPC_LIBRARY_BUILD
+   /* to indicate we are inside the library build */
+
+#include "config.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "mpc.h"
+
+/*
+ * Miscellaneous useful macros
+ */
+
+#define MPC_MIN(h,i) ((h) < (i) ? (h) : (i))
+#define MPC_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+/* Safe absolute value (to avoid possible integer overflow) */
+/* type is the target (unsigned) type (copied from mpfr-impl.h) */
+#ifdef SAFE_ABS
+#undef SAFE_ABS
+#endif
+#define SAFE_ABS(type,x) ((x) >= 0 ? (type)(x) : -(type)(x))
+
+
+/*
+ * MPFR constants and macros
+ */
+
+#ifndef BITS_PER_MP_LIMB
+#define BITS_PER_MP_LIMB mp_bits_per_limb
+#endif
+
+#define MPFR_SIGNBIT(x) (mpfr_signbit (x) ? -1 : 1)
+#define MPC_MPFR_SIGN(x) (mpfr_zero_p (x) ? 0 : MPFR_SIGNBIT (x))
+   /* should be called MPFR_SIGN, but this is taken in mpfr.h */
+#define MPFR_CHANGE_SIGN(x) mpfr_neg(x,x,GMP_RNDN)
+#define MPFR_COPYSIGN(x,y,z,rnd) (mpfr_nan_p (z) ? \
+   mpfr_setsign (x, y, 0, rnd) : \
+   mpfr_copysign (x, y, z, rnd))
+   /* work around spurious signs in nan */
+#define MPFR_ADD_ONE_ULP(x) mpfr_add_one_ulp (x, GMP_RNDN)
+#define MPFR_SUB_ONE_ULP(x) mpfr_sub_one_ulp (x, GMP_RNDN)
+   /* drop unused rounding mode from macroes */
+#define MPFR_SWAP(a,b) do { mpfr_srcptr tmp; tmp = a; a = b; b = tmp; } while (0)
+
+
+/*
+ * Macro implementing rounding away from zero, to ease compatibility with
+ * mpfr < 3. f is the complete function call with a rounding mode of
+ * MPFR_RNDA, rop the name of the variable containing the result; it is
+ * already contained in f, but needs to be repeated so that the macro can
+ * modify the variable.
+ * Usage: replace each call to a function such as
+ *    mpfr_add (rop, a, b, MPFR_RNDA)
+ * by
+ *    ROUND_AWAY (mpfr_add (rop, a, b, MPFR_RNDA), rop)
+*/
+#if MPFR_VERSION_MAJOR < 3
+   /* round towards zero, add 1 ulp if not exact */
+#define MPFR_RNDA GMP_RNDZ
+#define ROUND_AWAY(f,rop)                            \
+   ((f) ? MPFR_ADD_ONE_ULP (rop), MPFR_SIGNBIT (rop) : 0)
+#else
+#define ROUND_AWAY(f,rop) \
+   (f)
+#endif /* mpfr < 3 */
+
+#if MPFR_VERSION_MAJOR < 3
+/* declare missing functions, defined in get_version.c */
+__MPC_DECLSPEC void mpfr_set_zero (mpfr_ptr, int);
+__MPC_DECLSPEC int mpfr_regular_p (mpfr_srcptr);
+#endif /* mpfr < 3 */
+
+
+/*
+ * MPC macros
+ */
+
+#define MPC_PREC_RE(x) (mpfr_get_prec(mpc_realref(x)))
+#define MPC_PREC_IM(x) (mpfr_get_prec(mpc_imagref(x)))
+#define MPC_MAX_PREC(x) MPC_MAX(MPC_PREC_RE(x), MPC_PREC_IM(x))
+
+#define INV_RND(r) \
+   (((r) == GMP_RNDU) ? GMP_RNDD : (((r) == GMP_RNDD) ? GMP_RNDU : (r)))
+
+#define mpc_inf_p(z) (mpfr_inf_p(mpc_realref(z))||mpfr_inf_p(mpc_imagref(z)))
+   /* Convention in C99 (G.3): z is regarded as an infinity if at least one of
+      its parts is infinite */
+#define mpc_zero_p(z) (mpfr_zero_p(mpc_realref(z))&&mpfr_zero_p(mpc_imagref(z)))
+   /* Convention in C99 (G.3): z is regarded as a zero if each of its parts is
+      a zero */
+#define mpc_fin_p(z) (mpfr_number_p(mpc_realref(z))&&mpfr_number_p(mpc_imagref(z)))
+   /* Convention in C99 (G.3): z is regarded as finite if both its parts are */
+#define mpc_nan_p(z) ((mpfr_nan_p(mpc_realref(z)) && !mpfr_inf_p(mpc_imagref(z))) || (mpfr_nan_p(mpc_imagref(z)) && !mpfr_inf_p(mpc_realref(z))))
+   /* Consider as NaN all other numbers containing at least one NaN */
+
+
+/*
+ * ASSERT macros
+ */
+
+#ifdef NDEBUG
+#define MPC_ASSERT(expr) \
+  do {                   \
+  } while (0)
+#else
+#define MPC_ASSERT(expr)                                        \
+  do {                                                          \
+    if (!(expr))                                                \
+      {                                                         \
+        fprintf (stderr, "%s:%d: MPC assertion failed: %s\n",   \
+                 __FILE__, __LINE__, #expr);                    \
+        abort();                                                \
+      }                                                         \
+  } while (0)
+#endif
+
+
+/*
+ * Debug macros
+ */
+
+#define MPC_OUT(x)                                              \
+do {                                                            \
+  printf (#x "[%lu,%lu]=", (unsigned long int) MPC_PREC_RE (x), \
+      (unsigned long int) MPC_PREC_IM (x));                     \
+  mpc_out_str (stdout, 2, 0, x, MPC_RNDNN);                     \
+  printf ("\n");                                                \
+} while (0)
+
+#define MPFR_OUT(x)                                             \
+do {                                                            \
+  printf (#x "[%lu]=", (unsigned long int) mpfr_get_prec (x));  \
+  mpfr_out_str (stdout, 2, 0, x, GMP_RNDN);                     \
+  printf ("\n");                                                \
+} while (0)
+
+
+/*
+ * Constants
+ */
+
+#ifndef MUL_KARATSUBA_THRESHOLD
+#define MUL_KARATSUBA_THRESHOLD 23
+#endif
+
+
+/*
+ * Define internal functions
+ */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+__MPC_DECLSPEC int  mpc_mul_naive (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_karatsuba (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_fma_naive (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_usi (mpc_ptr, mpc_srcptr, unsigned long, int, mpc_rnd_t);
+__MPC_DECLSPEC char* mpc_alloc_str (size_t);
+__MPC_DECLSPEC char* mpc_realloc_str (char*, size_t, size_t);
+__MPC_DECLSPEC void mpc_free_str (char*);
+__MPC_DECLSPEC mpfr_prec_t mpc_ceil_log2 (mpfr_prec_t);
+__MPC_DECLSPEC int set_pi_over_2 (mpfr_ptr, int, mpfr_rnd_t);
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+#endif
diff --git a/contrib/mpc/src/mpc-log.h b/contrib/mpc/src/mpc-log.h
new file mode 100644 (file)
index 0000000..78c98d2
--- /dev/null
@@ -0,0 +1,51 @@
+/* mpc-log.h -- Include file to enable function call logging; replaces mpc.h.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#define mpc_sqr mpc_log_sqr
+#define mpc_conj mpc_log_conj
+#define mpc_neg mpc_log_neg
+#define mpc_sqrt mpc_log_sqrt
+#define mpc_proj mpc_log_proj
+#define mpc_exp mpc_log_exp
+#define mpc_log mpc_log_log
+#define mpc_sin mpc_log_sin
+#define mpc_cos mpc_log_cos
+#define mpc_tan mpc_log_tan
+#define mpc_sinh mpc_log_sinh
+#define mpc_cosh mpc_log_cosh
+#define mpc_tanh mpc_log_tanh
+#define mpc_asin mpc_log_asin
+#define mpc_acos mpc_log_acos
+#define mpc_atan mpc_log_atan
+#define mpc_asinh mpc_log_asinh
+#define mpc_acosh mpc_log_acosh
+#define mpc_atanh mpc_log_atanh
+
+#define mpc_add mpc_log_add
+#define mpc_sub mpc_log_sub
+#define mpc_mul mpc_log_mul
+#define mpc_div mpc_log_div
+#define mpc_pow mpc_log_pow
+
+#define mpc_fma mpc_log_fma
+
+#define mpc_sin_cos mpc_log_sin_cos
+
+#include "mpc.h"
diff --git a/contrib/mpc/src/mpc.h b/contrib/mpc/src/mpc.h
new file mode 100644 (file)
index 0000000..02c1943
--- /dev/null
@@ -0,0 +1,269 @@
+/* mpc.h -- Include file for mpc.
+
+Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#ifndef __MPC_H
+#define __MPC_H
+
+#include "gmp.h"
+#include "mpfr.h"
+
+/* Backwards compatibility with mpfr<3.0.0 */
+#ifndef mpfr_exp_t
+#define mpfr_exp_t mp_exp_t
+#endif
+
+/* Define MPC version number */
+#define MPC_VERSION_MAJOR 1
+#define MPC_VERSION_MINOR 0
+#define MPC_VERSION_PATCHLEVEL 1
+#define MPC_VERSION_STRING "1.0.1"
+
+/* Macros dealing with MPC VERSION */
+#define MPC_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c))
+#define MPC_VERSION                                                     \
+  MPC_VERSION_NUM(MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCHLEVEL)
+
+/* Check if stdint.h/inttypes.h is included */
+#if defined (INTMAX_C) && defined (UINTMAX_C)
+#define _MPC_H_HAVE_INTMAX_T 1
+#endif
+
+/* Return values */
+
+/* Transform negative to 2, positive to 1, leave 0 unchanged */
+#define MPC_INEX_POS(inex) (((inex) < 0) ? 2 : ((inex) == 0) ? 0 : 1)
+/* Transform 2 to negative, 1 to positive, leave 0 unchanged */
+#define MPC_INEX_NEG(inex) (((inex) == 2) ? -1 : ((inex) == 0) ? 0 : 1)
+
+/* The global inexact flag is made of (real flag) + 4 * (imaginary flag), where
+   each of the real and imaginary inexact flag are:
+   0 when the result is exact (no rounding error)
+   1 when the result is larger than the exact value
+   2 when the result is smaller than the exact value */
+#define MPC_INEX(inex_re, inex_im) \
+        (MPC_INEX_POS(inex_re) | (MPC_INEX_POS(inex_im) << 2))
+#define MPC_INEX_RE(inex) MPC_INEX_NEG((inex) & 3)
+#define MPC_INEX_IM(inex) MPC_INEX_NEG((inex) >> 2)
+
+/* For functions computing two results, the return value is
+   inexact1+16*inexact2, which is 0 iif both results are exact. */
+#define MPC_INEX12(inex1, inex2) (inex1 | (inex2 << 4))
+#define MPC_INEX1(inex) (inex & 15)
+#define MPC_INEX2(inex) (inex >> 4)
+
+/* Definition of rounding modes */
+
+/* a complex rounding mode is just a pair of two real rounding modes
+   we reserve four bits for a real rounding mode.  */
+typedef int mpc_rnd_t;
+
+#define MPC_RND(r1,r2) (((int)(r1)) + ((int)(r2) << 4))
+#define MPC_RND_RE(x) ((mpfr_rnd_t)((x) & 0x0F))
+#define MPC_RND_IM(x) ((mpfr_rnd_t)((x) >> 4))
+
+#define MPC_RNDNN MPC_RND (GMP_RNDN,GMP_RNDN)
+#define MPC_RNDNZ MPC_RND (GMP_RNDN,GMP_RNDZ)
+#define MPC_RNDNU MPC_RND (GMP_RNDN,GMP_RNDU)
+#define MPC_RNDND MPC_RND (GMP_RNDN,GMP_RNDD)
+
+#define MPC_RNDZN MPC_RND (GMP_RNDZ,GMP_RNDN)
+#define MPC_RNDZZ MPC_RND (GMP_RNDZ,GMP_RNDZ)
+#define MPC_RNDZU MPC_RND (GMP_RNDZ,GMP_RNDU)
+#define MPC_RNDZD MPC_RND (GMP_RNDZ,GMP_RNDD)
+
+#define MPC_RNDUN MPC_RND (GMP_RNDU,GMP_RNDN)
+#define MPC_RNDUZ MPC_RND (GMP_RNDU,GMP_RNDZ)
+#define MPC_RNDUU MPC_RND (GMP_RNDU,GMP_RNDU)
+#define MPC_RNDUD MPC_RND (GMP_RNDU,GMP_RNDD)
+
+#define MPC_RNDDN MPC_RND (GMP_RNDD,GMP_RNDN)
+#define MPC_RNDDZ MPC_RND (GMP_RNDD,GMP_RNDZ)
+#define MPC_RNDDU MPC_RND (GMP_RNDD,GMP_RNDU)
+#define MPC_RNDDD MPC_RND (GMP_RNDD,GMP_RNDD)
+
+
+/* Definitions of types and their semantics */
+
+typedef struct {
+  mpfr_t re;
+  mpfr_t im;
+}
+__mpc_struct;
+
+typedef __mpc_struct mpc_t[1];
+typedef __mpc_struct *mpc_ptr;
+typedef const __mpc_struct *mpc_srcptr;
+
+/* Support for WINDOWS DLL, see
+   http://lists.gforge.inria.fr/pipermail/mpc-discuss/2011-November/000990.html;
+   when building the DLL, export symbols, otherwise behave as GMP           */
+#if defined (__MPC_LIBRARY_BUILD) && __GMP_LIBGMP_DLL
+#define __MPC_DECLSPEC __GMP_DECLSPEC_EXPORT
+#else
+#define __MPC_DECLSPEC __GMP_DECLSPEC
+#endif
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+__MPC_DECLSPEC int  mpc_add       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_add_fr    (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_add_si    (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_add_ui    (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sub       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sub_fr    (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_fr_sub    (mpc_ptr, mpfr_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sub_ui    (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_ui_ui_sub (mpc_ptr, unsigned long int, unsigned long int, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_fr    (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_ui    (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_si    (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_i     (mpc_ptr, mpc_srcptr, int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sqr       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_div       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_fr    (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_ld    (mpc_ptr, mpc_srcptr, long double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_d     (mpc_ptr, mpc_srcptr, double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_si    (mpc_ptr, mpc_srcptr, long, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_ui    (mpc_ptr, mpc_srcptr, unsigned long, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_pow_z     (mpc_ptr, mpc_srcptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_div_fr    (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_fr_div    (mpc_ptr, mpfr_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_div_ui    (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_ui_div    (mpc_ptr, unsigned long int, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_div_2ui   (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_2ui   (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_div_2si   (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_mul_2si   (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_conj      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_neg       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_norm      (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int  mpc_abs       (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int  mpc_sqrt      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_d     (mpc_ptr, double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_d_d   (mpc_ptr, double, double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_ld    (mpc_ptr, long double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_ld_ld (mpc_ptr, long double, long double, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_f     (mpc_ptr, mpf_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_f_f   (mpc_ptr, mpf_srcptr, mpf_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_fr    (mpc_ptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_fr_fr (mpc_ptr, mpfr_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_q     (mpc_ptr, mpq_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_q_q   (mpc_ptr, mpq_srcptr, mpq_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_si    (mpc_ptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_si_si (mpc_ptr, long int, long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_ui    (mpc_ptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_ui_ui (mpc_ptr, unsigned long int, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_z     (mpc_ptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_z_z   (mpc_ptr, mpz_srcptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_swap      (mpc_ptr, mpc_ptr);
+__MPC_DECLSPEC int  mpc_fma       (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+
+__MPC_DECLSPEC void mpc_set_nan   (mpc_ptr);
+
+__MPC_DECLSPEC int  mpc_real      (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int  mpc_imag      (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int  mpc_arg       (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int  mpc_proj      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_cmp       (mpc_srcptr, mpc_srcptr);
+__MPC_DECLSPEC int  mpc_cmp_si_si (mpc_srcptr, long int, long int);
+__MPC_DECLSPEC int  mpc_exp       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_log       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_log10     (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sin       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_cos       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sin_cos   (mpc_ptr, mpc_ptr, mpc_srcptr, mpc_rnd_t, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_tan       (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_sinh      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_cosh      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_tanh      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_asin      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_acos      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_atan      (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_asinh     (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_acosh     (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_atanh     (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_clear     (mpc_ptr);
+__MPC_DECLSPEC int  mpc_urandom   (mpc_ptr, gmp_randstate_t);
+__MPC_DECLSPEC void mpc_init2     (mpc_ptr, mpfr_prec_t);
+__MPC_DECLSPEC void mpc_init3     (mpc_ptr, mpfr_prec_t, mpfr_prec_t);
+__MPC_DECLSPEC mpfr_prec_t mpc_get_prec (mpc_srcptr x);
+__MPC_DECLSPEC void mpc_get_prec2 (mpfr_prec_t *pr, mpfr_prec_t *pi, mpc_srcptr x);
+__MPC_DECLSPEC void mpc_set_prec  (mpc_ptr, mpfr_prec_t);
+__MPC_DECLSPEC const char * mpc_get_version (void);
+
+__MPC_DECLSPEC int  mpc_strtoc    (mpc_ptr, const char *, char **, int, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_str   (mpc_ptr, const char *, int, mpc_rnd_t);
+__MPC_DECLSPEC char * mpc_get_str (int, size_t, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_free_str  (char *);
+
+/* declare certain functions only if appropriate headers have been included */
+#ifdef _MPC_H_HAVE_INTMAX_T
+__MPC_DECLSPEC int  mpc_set_sj    (mpc_ptr, intmax_t, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_uj    (mpc_ptr, uintmax_t,  mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_sj_sj (mpc_ptr, intmax_t, intmax_t, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_uj_uj (mpc_ptr, uintmax_t, uintmax_t, mpc_rnd_t);
+#endif
+
+#ifdef _Complex_I
+__MPC_DECLSPEC int  mpc_set_dc    (mpc_ptr, double _Complex, mpc_rnd_t);
+__MPC_DECLSPEC int  mpc_set_ldc   (mpc_ptr, long double _Complex, mpc_rnd_t);
+__MPC_DECLSPEC double _Complex mpc_get_dc (mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC long double _Complex mpc_get_ldc (mpc_srcptr, mpc_rnd_t);
+#endif
+
+#ifdef _GMP_H_HAVE_FILE
+__MPC_DECLSPEC int mpc_inp_str    (mpc_ptr, FILE *, size_t *, int, mpc_rnd_t);
+__MPC_DECLSPEC size_t mpc_out_str (FILE *, int, size_t, mpc_srcptr, mpc_rnd_t);
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+#define mpc_realref(x) ((x)->re)
+#define mpc_imagref(x) ((x)->im)
+
+#define mpc_cmp_si(x, y) \
+ ( mpc_cmp_si_si ((x), (y), 0l) )
+#define mpc_ui_sub(x, y, z, r) mpc_ui_ui_sub (x, y, 0ul, z, r)
+
+/*
+   Define a fake mpfr_set_fr so that, for instance, mpc_set_fr_z would
+   be defined as follows:
+   mpc_set_fr_z (mpc_t rop, mpfr_t x, mpz_t y, mpc_rnd_t rnd)
+       MPC_SET_X_Y (fr, z, rop, x, y, rnd)
+*/
+#ifndef mpfr_set_fr
+#define mpfr_set_fr mpfr_set
+#endif
+#define MPC_SET_X_Y(real_t, imag_t, z, real_value, imag_value, rnd)     \
+  {                                                                     \
+    int _inex_re, _inex_im;                                             \
+    _inex_re = (mpfr_set_ ## real_t) (mpc_realref (z), (real_value), MPC_RND_RE (rnd)); \
+    _inex_im = (mpfr_set_ ## imag_t) (mpc_imagref (z), (imag_value), MPC_RND_IM (rnd)); \
+    return MPC_INEX (_inex_re, _inex_im);                               \
+  }
+
+#endif /* ifndef __MPC_H */
diff --git a/contrib/mpc/src/mul.c b/contrib/mpc/src/mul.c
new file mode 100644 (file)
index 0000000..2be9b8d
--- /dev/null
@@ -0,0 +1,639 @@
+/* mpc_mul -- Multiply two complex numbers
+
+Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+#define mpz_add_si(z,x,y) do { \
+   if (y >= 0) \
+      mpz_add_ui (z, x, (long int) y); \
+   else \
+      mpz_sub_ui (z, x, (long int) (-y)); \
+   } while (0);
+
+/* compute z=x*y when x has an infinite part */
+static int
+mul_infinite (mpc_ptr z, mpc_srcptr x, mpc_srcptr y)
+{
+   /* Let x=xr+i*xi and y=yr+i*yi; extract the signs of the operands */
+   int xrs = mpfr_signbit (mpc_realref (x)) ? -1 : 1;
+   int xis = mpfr_signbit (mpc_imagref (x)) ? -1 : 1;
+   int yrs = mpfr_signbit (mpc_realref (y)) ? -1 : 1;
+   int yis = mpfr_signbit (mpc_imagref (y)) ? -1 : 1;
+
+   int u, v;
+
+   /* compute the sign of
+      u = xrs * yrs * xr * yr - xis * yis * xi * yi
+      v = xrs * yis * xr * yi + xis * yrs * xi * yr
+      +1 if positive, -1 if negatiye, 0 if NaN */
+   if (  mpfr_nan_p (mpc_realref (x)) || mpfr_nan_p (mpc_imagref (x))
+      || mpfr_nan_p (mpc_realref (y)) || mpfr_nan_p (mpc_imagref (y))) {
+      u = 0;
+      v = 0;
+   }
+   else if (mpfr_inf_p (mpc_realref (x))) {
+      /* x = (+/-inf) xr + i*xi */
+      u = (   mpfr_zero_p (mpc_realref (y))
+           || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_imagref (y)))
+           || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_imagref (y)))
+           || (   (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (y)))
+              && xrs*yrs == xis*yis)
+           ? 0 : xrs * yrs);
+      v = (   mpfr_zero_p (mpc_imagref (y))
+           || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_realref (y)))
+           || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_realref (y)))
+           || (   (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (x)))
+               && xrs*yis != xis*yrs)
+           ? 0 : xrs * yis);
+   }
+   else {
+      /* x = xr + i*(+/-inf) with |xr| != inf */
+      u = (   mpfr_zero_p (mpc_imagref (y))
+           || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_realref (y)))
+           || (mpfr_inf_p (mpc_realref (y)) && xrs*yrs == xis*yis)
+           ? 0 : -xis * yis);
+      v = (   mpfr_zero_p (mpc_realref (y))
+           || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_imagref (y)))
+           || (mpfr_inf_p (mpc_imagref (y)) && xrs*yis != xis*yrs)
+           ? 0 : xis * yrs);
+   }
+
+   if (u == 0 && v == 0) {
+      /* Naive result is NaN+i*NaN. Obtain an infinity using the algorithm
+         given in Annex G.5.1 of the ISO C99 standard */
+      int xr = (mpfr_zero_p (mpc_realref (x)) || mpfr_nan_p (mpc_realref (x)) ? 0
+                : (mpfr_inf_p (mpc_realref (x)) ? 1 : 0));
+      int xi = (mpfr_zero_p (mpc_imagref (x)) || mpfr_nan_p (mpc_imagref (x)) ? 0
+                : (mpfr_inf_p (mpc_imagref (x)) ? 1 : 0));
+      int yr = (mpfr_zero_p (mpc_realref (y)) || mpfr_nan_p (mpc_realref (y)) ? 0 : 1);
+      int yi = (mpfr_zero_p (mpc_imagref (y)) || mpfr_nan_p (mpc_imagref (y)) ? 0 : 1);
+      if (mpc_inf_p (y)) {
+         yr = mpfr_inf_p (mpc_realref (y)) ? 1 : 0;
+         yi = mpfr_inf_p (mpc_imagref (y)) ? 1 : 0;
+      }
+
+      u = xrs * xr * yrs * yr - xis * xi * yis * yi;
+      v = xrs * xr * yis * yi + xis * xi * yrs * yr;
+   }
+
+   if (u == 0)
+      mpfr_set_nan (mpc_realref (z));
+   else
+      mpfr_set_inf (mpc_realref (z), u);
+
+   if (v == 0)
+      mpfr_set_nan (mpc_imagref (z));
+   else
+      mpfr_set_inf (mpc_imagref (z), v);
+
+   return MPC_INEX (0, 0); /* exact */
+}
+
+
+/* compute z = x*y for Im(y) == 0 */
+static int
+mul_real (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+   int xrs, xis, yrs, yis;
+   int inex;
+
+   /* save signs of operands */
+   xrs = MPFR_SIGNBIT (mpc_realref (x));
+   xis = MPFR_SIGNBIT (mpc_imagref (x));
+   yrs = MPFR_SIGNBIT (mpc_realref (y));
+   yis = MPFR_SIGNBIT (mpc_imagref (y));
+
+   inex = mpc_mul_fr (z, x, mpc_realref (y), rnd);
+   /* Signs of zeroes may be wrong. Their correction does not change the
+      inexact flag. */
+   if (mpfr_zero_p (mpc_realref (z)))
+      mpfr_setsign (mpc_realref (z), mpc_realref (z), MPC_RND_RE(rnd) == GMP_RNDD
+                     || (xrs != yrs && xis == yis), GMP_RNDN);
+   if (mpfr_zero_p (mpc_imagref (z)))
+      mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == GMP_RNDD
+                     || (xrs != yis && xis != yrs), GMP_RNDN);
+
+   return inex;
+}
+
+
+/* compute z = x*y for Re(y) == 0, and Im(x) != 0 and Im(y) != 0 */
+static int
+mul_imag (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+   int sign;
+   int inex_re, inex_im;
+   int overlap = z == x || z == y;
+   mpc_t rop;
+
+   if (overlap)
+      mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
+   else
+      rop [0] = z[0];
+
+   sign =    (MPFR_SIGNBIT (mpc_realref (y)) != MPFR_SIGNBIT (mpc_imagref (x)))
+          && (MPFR_SIGNBIT (mpc_imagref (y)) != MPFR_SIGNBIT (mpc_realref (x)));
+
+   inex_re = -mpfr_mul (mpc_realref (rop), mpc_imagref (x), mpc_imagref (y),
+                        INV_RND (MPC_RND_RE (rnd)));
+   mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN); /* exact */
+   inex_im = mpfr_mul (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y),
+                       MPC_RND_IM (rnd));
+   mpc_set (z, rop, MPC_RNDNN);
+
+   /* Sign of zeroes may be wrong (note that Re(z) cannot be zero) */
+   if (mpfr_zero_p (mpc_imagref (z)))
+      mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == GMP_RNDD
+                     || sign, GMP_RNDN);
+
+   if (overlap)
+      mpc_clear (rop);
+
+   return MPC_INEX (inex_re, inex_im);
+}
+
+
+static int
+mpfr_fmma (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpfr_srcptr c,
+           mpfr_srcptr d, int sign, mpfr_rnd_t rnd)
+{
+   /* Computes z = ab+cd if sign >= 0, or z = ab-cd if sign < 0.
+      Assumes that a, b, c, d are finite and non-zero; so any multiplication
+      of two of them yielding an infinity is an overflow, and a
+      multiplication yielding 0 is an underflow.
+      Assumes further that z is distinct from a, b, c, d. */
+
+   int inex;
+   mpfr_t u, v;
+
+   /* u=a*b, v=sign*c*d exactly */
+   mpfr_init2 (u, mpfr_get_prec (a) + mpfr_get_prec (b));
+   mpfr_init2 (v, mpfr_get_prec (c) + mpfr_get_prec (d));
+   mpfr_mul (u, a, b, GMP_RNDN);
+   mpfr_mul (v, c, d, GMP_RNDN);
+   if (sign < 0)
+      mpfr_neg (v, v, GMP_RNDN);
+
+   /* tentatively compute z as u+v; here we need z to be distinct
+      from a, b, c, d to not lose the latter */
+   inex = mpfr_add (z, u, v, rnd);
+
+   if (mpfr_inf_p (z)) {
+      /* replace by "correctly rounded overflow" */
+      mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), GMP_RNDN);
+      inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd);
+   }
+   else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) {
+      /* exactly u underflowed, determine inexact flag */
+      inex = (mpfr_signbit (u) ? 1 : -1);
+   }
+   else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) {
+      /* exactly v underflowed, determine inexact flag */
+      inex = (mpfr_signbit (v) ? 1 : -1);
+   }
+   else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) {
+      /* In the first case, u and v are infinities with opposite signs.
+         In the second case, u and v are zeroes; their sum may be 0 or the
+         least representable number, with a sign to be determined.
+         Redo the computations with mpz_t exponents */
+      mpfr_exp_t ea, eb, ec, ed;
+      mpz_t eu, ev;
+         /* cheat to work around the const qualifiers */
+
+      /* Normalise the input by shifting and keep track of the shifts in
+         the exponents of u and v */
+      ea = mpfr_get_exp (a);
+      eb = mpfr_get_exp (b);
+      ec = mpfr_get_exp (c);
+      ed = mpfr_get_exp (d);
+
+      mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0);
+      mpfr_set_exp ((mpfr_ptr) b, (mpfr_prec_t) 0);
+      mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0);
+      mpfr_set_exp ((mpfr_ptr) d, (mpfr_prec_t) 0);
+
+      mpz_init (eu);
+      mpz_init (ev);
+      mpz_set_si (eu, (long int) ea);
+      mpz_add_si (eu, eu, (long int) eb);
+      mpz_set_si (ev, (long int) ec);
+      mpz_add_si (ev, ev, (long int) ed);
+
+      /* recompute u and v and move exponents to eu and ev */
+      mpfr_mul (u, a, b, GMP_RNDN);
+      /* exponent of u is non-positive */
+      mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u)));
+      mpfr_set_exp (u, (mpfr_prec_t) 0);
+      mpfr_mul (v, c, d, GMP_RNDN);
+      if (sign < 0)
+         mpfr_neg (v, v, GMP_RNDN);
+      mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v)));
+      mpfr_set_exp (v, (mpfr_prec_t) 0);
+
+      if (mpfr_nan_p (z)) {
+         mpfr_exp_t emax = mpfr_get_emax ();
+         int overflow;
+         /* We have a = ma * 2^ea with 1/2 <= |ma| < 1 and ea <= emax, and
+            analogously for b. So eu <= 2*emax, and eu > emax since we have
+            an overflow. The same holds for ev. Shift u and v by as much as
+            possible so that one of them has exponent emax and the
+            remaining exponents in eu and ev are the same. Then carry out
+            the addition. Shifting u and v prevents an underflow. */
+         if (mpz_cmp (eu, ev) >= 0) {
+            mpfr_set_exp (u, emax);
+            mpz_sub_ui (eu, eu, (long int) emax);
+            mpz_sub (ev, ev, eu);
+            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev));
+               /* remaining common exponent is now in eu */
+         }
+         else {
+            mpfr_set_exp (v, emax);
+            mpz_sub_ui (ev, ev, (long int) emax);
+            mpz_sub (eu, eu, ev);
+            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu));
+            mpz_set (eu, ev);
+               /* remaining common exponent is now also in eu */
+         }
+         inex = mpfr_add (z, u, v, rnd);
+            /* Result is finite since u and v have different signs. */
+         overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd);
+         if (overflow)
+            inex = overflow;
+      }
+      else {
+         int underflow;
+         /* Addition of two zeroes with same sign. We have a = ma * 2^ea
+            with 1/2 <= |ma| < 1 and ea >= emin and similarly for b.
+            So 2*emin < 2*emin+1 <= eu < emin < 0, and analogously for v. */
+         mpfr_exp_t emin = mpfr_get_emin ();
+         if (mpz_cmp (eu, ev) <= 0) {
+            mpfr_set_exp (u, emin);
+            mpz_add_ui (eu, eu, (unsigned long int) (-emin));
+            mpz_sub (ev, ev, eu);
+            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev));
+         }
+         else {
+            mpfr_set_exp (v, emin);
+            mpz_add_ui (ev, ev, (unsigned long int) (-emin));
+            mpz_sub (eu, eu, ev);
+            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu));
+            mpz_set (eu, ev);
+         }
+         inex = mpfr_add (z, u, v, rnd);
+         mpz_neg (eu, eu);
+         underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd);
+         if (underflow)
+            inex = underflow;
+      }
+
+      mpz_clear (eu);
+      mpz_clear (ev);
+
+      mpfr_set_exp ((mpfr_ptr) a, ea);
+      mpfr_set_exp ((mpfr_ptr) b, eb);
+      mpfr_set_exp ((mpfr_ptr) c, ec);
+      mpfr_set_exp ((mpfr_ptr) d, ed);
+         /* works also when some of a, b, c, d are not all distinct */
+   }
+
+   mpfr_clear (u);
+   mpfr_clear (v);
+
+   return inex;
+}
+
+
+int
+mpc_mul_naive (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+   /* computes z=x*y by the schoolbook method, where x and y are assumed
+      to be finite and without zero parts                                */
+   int overlap, inex;
+   mpc_t rop;
+
+   MPC_ASSERT (   mpfr_regular_p (mpc_realref (x)) && mpfr_regular_p (mpc_imagref (x))
+               && mpfr_regular_p (mpc_realref (y)) && mpfr_regular_p (mpc_imagref (y)));
+   overlap = (z == x) || (z == y);
+   if (overlap)
+      mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
+   else
+      rop [0] = z [0];
+
+   inex = MPC_INEX (mpfr_fmma (mpc_realref (rop), mpc_realref (x), mpc_realref (y), mpc_imagref (x),
+                               mpc_imagref (y), -1, MPC_RND_RE (rnd)),
+                    mpfr_fmma (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y), mpc_imagref (x),
+                               mpc_realref (y), +1, MPC_RND_IM (rnd)));
+
+   mpc_set (z, rop, MPC_RNDNN);
+   if (overlap)
+      mpc_clear (rop);
+
+   return inex;
+}
+
+
+int
+mpc_mul_karatsuba (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd)
+{
+   /* computes rop=op1*op2 by a Karatsuba algorithm, where op1 and op2
+      are assumed to be finite and without zero parts                  */
+  mpfr_srcptr a, b, c, d;
+  int mul_i, ok, inexact, mul_a, mul_c, inex_re = 0, inex_im = 0, sign_x, sign_u;
+  mpfr_t u, v, w, x;
+  mpfr_prec_t prec, prec_re, prec_u, prec_v, prec_w;
+  mpfr_rnd_t rnd_re, rnd_u;
+  int overlap;
+     /* true if rop == op1 or rop == op2 */
+  mpc_t result;
+     /* overlap is quite difficult to handle, because we have to tentatively
+        round the variable u in the end to either the real or the imaginary
+        part of rop (it is not possible to tell now whether the real or
+        imaginary part is used). If this fails, we have to start again and
+        need the correct values of op1 and op2.
+        So we just create a new variable for the result in this case. */
+  int loop;
+  const int MAX_MUL_LOOP = 1;
+
+  overlap = (rop == op1) || (rop == op2);
+  if (overlap)
+     mpc_init3 (result, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
+  else
+     result [0] = rop [0];
+
+  a = mpc_realref(op1);
+  b = mpc_imagref(op1);
+  c = mpc_realref(op2);
+  d = mpc_imagref(op2);
+
+  /* (a + i*b) * (c + i*d) = [ac - bd] + i*[ad + bc] */
+
+  mul_i = 0; /* number of multiplications by i */
+  mul_a = 1; /* implicit factor for a */
+  mul_c = 1; /* implicit factor for c */
+
+  if (mpfr_cmp_abs (a, b) < 0)
+    {
+      MPFR_SWAP (a, b);
+      mul_i ++;
+      mul_a = -1; /* consider i * (a+i*b) = -b + i*a */
+    }
+
+  if (mpfr_cmp_abs (c, d) < 0)
+    {
+      MPFR_SWAP (c, d);
+      mul_i ++;
+      mul_c = -1; /* consider -d + i*c instead of c + i*d */
+    }
+
+  /* find the precision and rounding mode for the new real part */
+  if (mul_i % 2)
+    {
+      prec_re = MPC_PREC_IM(rop);
+      rnd_re = MPC_RND_IM(rnd);
+    }
+  else /* mul_i = 0 or 2 */
+    {
+      prec_re = MPC_PREC_RE(rop);
+      rnd_re = MPC_RND_RE(rnd);
+    }
+
+  if (mul_i)
+    rnd_re = INV_RND(rnd_re);
+
+  /* now |a| >= |b| and |c| >= |d| */
+  prec = MPC_MAX_PREC(rop);
+
+  mpfr_init2 (v, prec_v = mpfr_get_prec (a) + mpfr_get_prec (d));
+  mpfr_init2 (w, prec_w = mpfr_get_prec (b) + mpfr_get_prec (c));
+  mpfr_init2 (u, 2);
+  mpfr_init2 (x, 2);
+
+  inexact = mpfr_mul (v, a, d, GMP_RNDN);
+  if (inexact) {
+     /* over- or underflow */
+    ok = 0;
+    goto clear;
+  }
+  if (mul_a == -1)
+    mpfr_neg (v, v, GMP_RNDN);
+
+  inexact = mpfr_mul (w, b, c, GMP_RNDN);
+  if (inexact) {
+     /* over- or underflow */
+     ok = 0;
+     goto clear;
+  }
+  if (mul_c == -1)
+    mpfr_neg (w, w, GMP_RNDN);
+
+  /* compute sign(v-w) */
+  sign_x = mpfr_cmp_abs (v, w);
+  if (sign_x > 0)
+    sign_x = 2 * mpfr_sgn (v) - mpfr_sgn (w);
+  else if (sign_x == 0)
+    sign_x = mpfr_sgn (v) - mpfr_sgn (w);
+  else
+    sign_x = mpfr_sgn (v) - 2 * mpfr_sgn (w);
+
+   sign_u = mul_a * mpfr_sgn (a) * mul_c * mpfr_sgn (c);
+
+   if (sign_x * sign_u < 0)
+    {  /* swap inputs */
+      MPFR_SWAP (a, c);
+      MPFR_SWAP (b, d);
+      mpfr_swap (v, w);
+      { int tmp; tmp = mul_a; mul_a = mul_c; mul_c = tmp; }
+      sign_x = - sign_x;
+    }
+
+   /* now sign_x * sign_u >= 0 */
+   loop = 0;
+   do
+     {
+        loop++;
+         /* the following should give failures with prob. <= 1/prec */
+         prec += mpc_ceil_log2 (prec) + 3;
+
+         mpfr_set_prec (u, prec_u = prec);
+         mpfr_set_prec (x, prec);
+
+         /* first compute away(b +/- a) and store it in u */
+         inexact = (mul_a == -1 ?
+                    ROUND_AWAY (mpfr_sub (u, b, a, MPFR_RNDA), u) :
+                    ROUND_AWAY (mpfr_add (u, b, a, MPFR_RNDA), u));
+
+         /* then compute away(+/-c - d) and store it in x */
+         inexact |= (mul_c == -1 ?
+                     ROUND_AWAY (mpfr_add (x, c, d, MPFR_RNDA), x) :
+                     ROUND_AWAY (mpfr_sub (x, c, d, MPFR_RNDA), x));
+         if (mul_c == -1)
+           mpfr_neg (x, x, GMP_RNDN);
+
+         if (inexact == 0)
+            mpfr_prec_round (u, prec_u = 2 * prec, GMP_RNDN);
+
+         /* compute away(u*x) and store it in u */
+         inexact |= ROUND_AWAY (mpfr_mul (u, u, x, MPFR_RNDA), u);
+            /* (a+b)*(c-d) */
+
+        /* if all computations are exact up to here, it may be that
+           the real part is exact, thus we need if possible to
+           compute v - w exactly */
+        if (inexact == 0)
+          {
+            mpfr_prec_t prec_x;
+             /* v and w are different from 0, so mpfr_get_exp is safe to use */
+             prec_x = SAFE_ABS (mpfr_exp_t, mpfr_get_exp (v) - mpfr_get_exp (w))
+                      + MPC_MAX (prec_v, prec_w) + 1;
+                      /* +1 is necessary for a potential carry */
+            /* ensure we do not use a too large precision */
+            if (prec_x > prec_u)
+               prec_x = prec_u;
+            if (prec_x > prec)
+              mpfr_prec_round (x, prec_x, GMP_RNDN);
+          }
+
+         rnd_u = (sign_u > 0) ? GMP_RNDU : GMP_RNDD;
+         inexact |= mpfr_sub (x, v, w, rnd_u); /* ad - bc */
+
+         /* in case u=0, ensure that rnd_u rounds x away from zero */
+         if (mpfr_sgn (u) == 0)
+           rnd_u = (mpfr_sgn (x) > 0) ? GMP_RNDU : GMP_RNDD;
+         inexact |= mpfr_add (u, u, x, rnd_u); /* ac - bd */
+
+         ok = inexact == 0 ||
+           mpfr_can_round (u, prec_u - 3, rnd_u, GMP_RNDZ,
+                           prec_re + (rnd_re == GMP_RNDN));
+         /* this ensures both we can round correctly and determine the correct
+            inexact flag (for rounding to nearest) */
+     }
+   while (!ok && loop <= MAX_MUL_LOOP);
+      /* after MAX_MUL_LOOP rounds, use mpc_naive instead */
+
+   if (ok) {
+      /* if inexact is zero, then u is exactly ac-bd, otherwise fix the sign
+         of the inexact flag for u, which was rounded away from ac-bd */
+      if (inexact != 0)
+      inexact = mpfr_sgn (u);
+
+      if (mul_i == 0)
+      {
+         inex_re = mpfr_set (mpc_realref(result), u, MPC_RND_RE(rnd));
+         if (inex_re == 0)
+            {
+            inex_re = inexact; /* u is rounded away from 0 */
+            inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
+            }
+         else
+            inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
+      }
+      else if (mul_i == 1) /* (x+i*y)/i = y - i*x */
+      {
+         inex_im = mpfr_neg (mpc_imagref(result), u, MPC_RND_IM(rnd));
+         if (inex_im == 0)
+            {
+            inex_im = -inexact; /* u is rounded away from 0 */
+            inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
+            }
+         else
+            inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
+      }
+      else /* mul_i = 2, z/i^2 = -z */
+      {
+         inex_re = mpfr_neg (mpc_realref(result), u, MPC_RND_RE(rnd));
+         if (inex_re == 0)
+            {
+            inex_re = -inexact; /* u is rounded away from 0 */
+            inex_im = -mpfr_add (mpc_imagref(result), v, w,
+                                 INV_RND(MPC_RND_IM(rnd)));
+            mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
+            }
+         else
+            {
+            inex_im = -mpfr_add (mpc_imagref(result), v, w,
+                                 INV_RND(MPC_RND_IM(rnd)));
+            mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
+            }
+      }
+
+      mpc_set (rop, result, MPC_RNDNN);
+   }
+
+clear:
+   mpfr_clear (u);
+   mpfr_clear (v);
+   mpfr_clear (w);
+   mpfr_clear (x);
+   if (overlap)
+      mpc_clear (result);
+
+   if (ok)
+      return MPC_INEX(inex_re, inex_im);
+   else
+      return mpc_mul_naive (rop, op1, op2, rnd);
+}
+
+
+int
+mpc_mul (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+   /* Conforming to ISO C99 standard (G.5.1 multiplicative operators),
+      infinities are treated specially if both parts are NaN when computed
+      naively. */
+   if (mpc_inf_p (b))
+      return mul_infinite (a, b, c);
+   if (mpc_inf_p (c))
+      return mul_infinite (a, c, b);
+
+   /* NaN contamination of both parts in result */
+   if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b))
+       || mpfr_nan_p (mpc_realref (c)) || mpfr_nan_p (mpc_imagref (c))) {
+      mpfr_set_nan (mpc_realref (a));
+      mpfr_set_nan (mpc_imagref (a));
+      return MPC_INEX (0, 0);
+   }
+
+   /* check for real multiplication */
+   if (mpfr_zero_p (mpc_imagref (b)))
+      return mul_real (a, c, b, rnd);
+   if (mpfr_zero_p (mpc_imagref (c)))
+      return mul_real (a, b, c, rnd);
+
+   /* check for purely imaginary multiplication */
+   if (mpfr_zero_p (mpc_realref (b)))
+      return mul_imag (a, c, b, rnd);
+   if (mpfr_zero_p (mpc_realref (c)))
+      return mul_imag (a, b, c, rnd);
+
+   /* If the real and imaginary part of one argument have a very different */
+   /* exponent, it is not reasonable to use Karatsuba multiplication.      */
+   if (   SAFE_ABS (mpfr_exp_t,
+                     mpfr_get_exp (mpc_realref (b)) - mpfr_get_exp (mpc_imagref (b)))
+         > (mpfr_exp_t) MPC_MAX_PREC (b) / 2
+      || SAFE_ABS (mpfr_exp_t,
+                     mpfr_get_exp (mpc_realref (c)) - mpfr_get_exp (mpc_imagref (c)))
+         > (mpfr_exp_t) MPC_MAX_PREC (c) / 2)
+      return mpc_mul_naive (a, b, c, rnd);
+   else
+      return ((MPC_MAX_PREC(a)
+               <= (mpfr_prec_t) MUL_KARATSUBA_THRESHOLD * BITS_PER_MP_LIMB)
+            ? mpc_mul_naive : mpc_mul_karatsuba) (a, b, c, rnd);
+}
diff --git a/contrib/mpc/src/mul_2si.c b/contrib/mpc/src/mul_2si.c
new file mode 100644 (file)
index 0000000..14d0ca2
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_mul_2si -- Multiply a complex number by 2^e.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_2si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_mul_2si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_mul_2si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/mul_2ui.c b/contrib/mpc/src/mul_2ui.c
new file mode 100644 (file)
index 0000000..46aa788
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_mul_2ui -- Multiply a complex number by 2^e.
+
+Copyright (C) 2002, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_2ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_mul_2ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_mul_2ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/mul_fr.c b/contrib/mpc/src/mul_fr.c
new file mode 100644 (file)
index 0000000..bd3574d
--- /dev/null
@@ -0,0 +1,43 @@
+/* mpc_mul_fr -- Multiply a complex number by a floating-point number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+  mpfr_t real;
+
+  if (c == mpc_realref (a))
+    /* We have to use a temporary variable. */
+    mpfr_init2 (real, MPC_PREC_RE (a));
+  else
+    real [0] = mpc_realref (a) [0];
+
+  inex_re = mpfr_mul (real, mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_mul (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+  mpfr_set (mpc_realref (a), real, GMP_RNDN); /* exact */
+
+  if (c == mpc_realref (a))
+    mpfr_clear (real);
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/mul_i.c b/contrib/mpc/src/mul_i.c
new file mode 100644 (file)
index 0000000..591b0c6
--- /dev/null
@@ -0,0 +1,80 @@
+/* mpc_mul_i -- Multiply a complex number by plus or minus i.
+
+Copyright (C) 2005, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_i (mpc_ptr a, mpc_srcptr b, int sign, mpc_rnd_t rnd)
+/* if sign is >= 0, multiply by i, otherwise by -i */
+{
+  int   inex_re, inex_im;
+  mpfr_t tmp;
+
+  /* Treat the most probable case of compatible precisions first */
+  if (     MPC_PREC_RE (b) == MPC_PREC_IM (a)
+        && MPC_PREC_IM (b) == MPC_PREC_RE (a))
+  {
+     if (a == b)
+        mpfr_swap (mpc_realref (a), mpc_imagref (a));
+     else
+     {
+        mpfr_set (mpc_realref (a), mpc_imagref (b), GMP_RNDN);
+        mpfr_set (mpc_imagref (a), mpc_realref (b), GMP_RNDN);
+     }
+     if (sign >= 0)
+        MPFR_CHANGE_SIGN (mpc_realref (a));
+     else
+        MPFR_CHANGE_SIGN (mpc_imagref (a));
+     inex_re = 0;
+     inex_im = 0;
+  }
+  else
+  {
+     if (a == b)
+     {
+        mpfr_init2 (tmp, MPC_PREC_RE (a));
+        if (sign >= 0)
+        {
+           inex_re = mpfr_neg (tmp, mpc_imagref (b), MPC_RND_RE (rnd));
+           inex_im = mpfr_set (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+        }
+        else
+        {
+           inex_re = mpfr_set (tmp, mpc_imagref (b), MPC_RND_RE (rnd));
+           inex_im = mpfr_neg (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+        }
+        mpfr_clear (mpc_realref (a));
+        mpc_realref (a)[0] = tmp [0];
+     }
+     else
+        if (sign >= 0)
+        {
+           inex_re = mpfr_neg (mpc_realref (a), mpc_imagref (b), MPC_RND_RE (rnd));
+           inex_im = mpfr_set (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+        }
+        else
+        {
+           inex_re = mpfr_set (mpc_realref (a), mpc_imagref (b), MPC_RND_RE (rnd));
+           inex_im = mpfr_neg (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+        }
+  }
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/mul_si.c b/contrib/mpc/src/mul_si.c
new file mode 100644 (file)
index 0000000..f539d8b
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_mul_si -- Multiply a complex number by a signed integer.
+
+Copyright (C) 2005, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+   int inex_re, inex_im;
+
+   inex_re = mpfr_mul_si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+   inex_im = mpfr_mul_si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+   return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/mul_ui.c b/contrib/mpc/src/mul_ui.c
new file mode 100644 (file)
index 0000000..922e4b3
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_mul_ui -- Multiply a complex number by a nonnegative integer.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_mul_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_mul_ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/neg.c b/contrib/mpc/src/neg.c
new file mode 100644 (file)
index 0000000..2aae7ca
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_neg -- Negate a complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_neg (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_neg (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+  inex_im = mpfr_neg (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/norm.c b/contrib/mpc/src/norm.c
new file mode 100644 (file)
index 0000000..ab413b6
--- /dev/null
@@ -0,0 +1,182 @@
+/* mpc_norm -- Square of the norm of a complex number.
+
+Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+/* a <- norm(b) = b * conj(b)
+   (the rounding mode is mpfr_rnd_t here since we return an mpfr number) */
+int
+mpc_norm (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+   int inexact;
+   int saved_underflow, saved_overflow;
+
+   /* handling of special values; consistent with abs in that
+      norm = abs^2; so norm (+-inf, xxx) = norm (xxx, +-inf) = +inf */
+   if (!mpc_fin_p (b))
+         return mpc_abs (a, b, rnd);
+   else if (mpfr_zero_p (mpc_realref (b))) {
+      if (mpfr_zero_p (mpc_imagref (b)))
+         return mpfr_set_ui (a, 0, rnd); /* +0 */
+      else
+         return mpfr_sqr (a, mpc_imagref (b), rnd);
+   }
+   else if (mpfr_zero_p (mpc_imagref (b)))
+     return mpfr_sqr (a, mpc_realref (b), rnd); /* Re(b) <> 0 */
+
+   else /* everything finite and non-zero */ {
+      mpfr_t u, v, res;
+      mpfr_prec_t prec, prec_u, prec_v;
+      int loops;
+      const int max_loops = 2;
+         /* switch to exact squarings when loops==max_loops */
+
+      prec = mpfr_get_prec (a);
+
+      mpfr_init (u);
+      mpfr_init (v);
+      mpfr_init (res);
+
+      /* save the underflow or overflow flags from MPFR */
+      saved_underflow = mpfr_underflow_p ();
+      saved_overflow = mpfr_overflow_p ();
+
+      loops = 0;
+      mpfr_clear_underflow ();
+      mpfr_clear_overflow ();
+      do {
+         loops++;
+         prec += mpc_ceil_log2 (prec) + 3;
+         if (loops >= max_loops) {
+            prec_u = 2 * MPC_PREC_RE (b);
+            prec_v = 2 * MPC_PREC_IM (b);
+         }
+         else {
+            prec_u = MPC_MIN (prec, 2 * MPC_PREC_RE (b));
+            prec_v = MPC_MIN (prec, 2 * MPC_PREC_IM (b));
+         }
+
+         mpfr_set_prec (u, prec_u);
+         mpfr_set_prec (v, prec_v);
+
+         inexact  = mpfr_sqr (u, mpc_realref(b), GMP_RNDD); /* err <= 1 ulp in prec */
+         inexact |= mpfr_sqr (v, mpc_imagref(b), GMP_RNDD); /* err <= 1 ulp in prec */
+
+         /* If loops = max_loops, inexact should be 0 here, except in case
+               of underflow or overflow.
+            If loops < max_loops and inexact is zero, we can exit the
+            while-loop since it only remains to add u and v into a. */
+         if (inexact) {
+             mpfr_set_prec (res, prec);
+             mpfr_add (res, u, v, GMP_RNDD); /* err <= 3 ulp in prec */
+         }
+
+      } while (loops < max_loops && inexact != 0
+               && !mpfr_can_round (res, prec - 2, GMP_RNDD, GMP_RNDU,
+                                   mpfr_get_prec (a) + (rnd == GMP_RNDN)));
+
+      if (!inexact)
+         /* squarings were exact, neither underflow nor overflow */
+         inexact = mpfr_add (a, u, v, rnd);
+      /* if there was an overflow in Re(b)^2 or Im(b)^2 or their sum,
+         since the norm is larger, there is an overflow for the norm */
+      else if (mpfr_overflow_p ()) {
+         /* replace by "correctly rounded overflow" */
+         mpfr_set_ui (a, 1ul, GMP_RNDN);
+         inexact = mpfr_mul_2ui (a, a, mpfr_get_emax (), rnd);
+      }
+      else if (mpfr_underflow_p ()) {
+         /* necessarily one of the squarings did underflow (otherwise their
+            sum could not underflow), thus one of u, v is zero. */
+         mpfr_exp_t emin = mpfr_get_emin ();
+
+         /* Now either both u and v are zero, or u is zero and v exact,
+            or v is zero and u exact.
+            In the latter case, Im(b)^2 < 2^(emin-1).
+            If ulp(u) >= 2^(emin+1) and norm(b) is not exactly
+            representable at the target precision, then rounding u+Im(b)^2
+            is equivalent to rounding u+2^(emin-1).
+            For instance, if exp(u)>0 and the target precision is smaller
+            than about |emin|, the norm is not representable. To make the
+            scaling in the "else" case work without underflow, we test
+            whether exp(u) is larger than a small negative number instead.
+            The second case is handled analogously.                        */
+         if (!mpfr_zero_p (u)
+             && mpfr_get_exp (u) - 2 * (mpfr_exp_t) prec_u > emin
+             && mpfr_get_exp (u) > -10) {
+               mpfr_set_prec (v, MPFR_PREC_MIN);
+               mpfr_set_ui_2exp (v, 1, emin - 1, GMP_RNDZ);
+               inexact = mpfr_add (a, u, v, rnd);
+         }
+         else if (!mpfr_zero_p (v)
+             && mpfr_get_exp (v) - 2 * (mpfr_exp_t) prec_v > emin
+             && mpfr_get_exp (v) > -10) {
+               mpfr_set_prec (u, MPFR_PREC_MIN);
+               mpfr_set_ui_2exp (u, 1, emin - 1, GMP_RNDZ);
+               inexact = mpfr_add (a, u, v, rnd);
+         }
+         else {
+            unsigned long int scale, exp_re, exp_im;
+            int inex_underflow;
+
+            /* scale the input to an average exponent close to 0 */
+            exp_re = (unsigned long int) (-mpfr_get_exp (mpc_realref (b)));
+            exp_im = (unsigned long int) (-mpfr_get_exp (mpc_imagref (b)));
+            scale = exp_re / 2 + exp_im / 2 + (exp_re % 2 + exp_im % 2) / 2;
+               /* (exp_re + exp_im) / 2, computed in a way avoiding
+                  integer overflow                                  */
+            if (mpfr_zero_p (u)) {
+               /* recompute the scaled value exactly */
+               mpfr_mul_2ui (u, mpc_realref (b), scale, GMP_RNDN);
+               mpfr_sqr (u, u, GMP_RNDN);
+            }
+            else /* just scale */
+               mpfr_mul_2ui (u, u, 2*scale, GMP_RNDN);
+            if (mpfr_zero_p (v)) {
+               mpfr_mul_2ui (v, mpc_imagref (b), scale, GMP_RNDN);
+               mpfr_sqr (v, v, GMP_RNDN);
+            }
+            else
+               mpfr_mul_2ui (v, v, 2*scale, GMP_RNDN);
+
+            inexact = mpfr_add (a, u, v, rnd);
+            mpfr_clear_underflow ();
+            inex_underflow = mpfr_div_2ui (a, a, 2*scale, rnd);
+            if (mpfr_underflow_p ())
+               inexact = inex_underflow;
+         }
+      }
+      else /* no problems, ternary value due to mpfr_can_round trick */
+         inexact = mpfr_set (a, res, rnd);
+
+      /* restore underflow and overflow flags from MPFR */
+      if (saved_underflow)
+        mpfr_set_underflow ();
+      if (saved_overflow)
+        mpfr_set_overflow ();
+
+      mpfr_clear (u);
+      mpfr_clear (v);
+      mpfr_clear (res);
+   }
+
+   return inexact;
+}
diff --git a/contrib/mpc/src/out_str.c b/contrib/mpc/src/out_str.c
new file mode 100644 (file)
index 0000000..87cc823
--- /dev/null
@@ -0,0 +1,39 @@
+/* mpc_out_str -- Output a complex number on a given stream.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for FILE */
+#include <ctype.h>
+#include "mpc-impl.h"
+
+size_t
+mpc_out_str (FILE *stream, int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd) {
+   size_t size = 3; /* for '(', ' ' and ')' */
+
+   if (stream == NULL)
+      stream = stdout; /* fprintf does not allow NULL as first argument */
+
+   fprintf (stream, "(");
+   size += mpfr_out_str (stream, base, n, mpc_realref(op), MPC_RND_RE(rnd));
+   fprintf (stream, " ");
+   size += mpfr_out_str (stream, base, n, mpc_imagref(op), MPC_RND_RE(rnd));
+   fprintf (stream, ")");
+
+   return size;
+}
diff --git a/contrib/mpc/src/pow.c b/contrib/mpc/src/pow.c
new file mode 100644 (file)
index 0000000..892f467
--- /dev/null
@@ -0,0 +1,819 @@
+/* mpc_pow -- Raise a complex number to the power of another complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+/* Return non-zero iff c+i*d is an exact square (a+i*b)^2,
+   with a, b both of the form m*2^e with m, e integers.
+   If so, returns in a+i*b the corresponding square root, with a >= 0.
+   The variables a, b must not overlap with c, d.
+
+   We have c = a^2 - b^2 and d = 2*a*b.
+
+   If one of a, b is exact, then both are (see algorithms.tex).
+
+   Case 1: a <> 0 and b <> 0.
+   Let a = m*2^e and b = n*2^f with m, e, n, f integers, m and n odd
+   (we will treat apart the case a = 0 or b = 0).
+   Then 2*a*b = m*n*2^(e+f+1), thus necessarily e+f >= -1.
+   Assume e < 0, then f >= 0, then a^2 - b^2 = m^2*2^(2e) - n^2*2^(2f) cannot
+   be an integer, since n^2*2^(2f) is an integer, and m^2*2^(2e) is not.
+   Similarly when f < 0 (and thus e >= 0).
+   Thus we have e, f >= 0, and a, b are both integers.
+   Let A = 2a^2, then eliminating b between c = a^2 - b^2 and d = 2*a*b
+   gives A^2 - 2c*A - d^2 = 0, which has solutions c +/- sqrt(c^2+d^2).
+   We thus need c^2+d^2 to be a square, and c + sqrt(c^2+d^2) --- the solution
+   we are interested in --- to be two times a square. Then b = d/(2a) is
+   necessarily an integer.
+
+   Case 2: a = 0. Then d is necessarily zero, thus it suffices to check
+   whether c = -b^2, i.e., if -c is a square.
+
+   Case 3: b = 0. Then d is necessarily zero, thus it suffices to check
+   whether c = a^2, i.e., if c is a square.
+*/
+static int
+mpc_perfect_square_p (mpz_t a, mpz_t b, mpz_t c, mpz_t d)
+{
+  if (mpz_cmp_ui (d, 0) == 0) /* case a = 0 or b = 0 */
+    {
+      /* necessarily c < 0 here, since we have already considered the case
+         where x is real non-negative and y is real */
+      MPC_ASSERT (mpz_cmp_ui (c, 0) < 0);
+      mpz_neg (b, c);
+      if (mpz_perfect_square_p (b)) /* case 2 above */
+        {
+          mpz_sqrt (b, b);
+          mpz_set_ui (a, 0);
+          return 1; /* c + i*d = (0 + i*b)^2 */
+        }
+    }
+  else /* both a and b are non-zero */
+    {
+      if (mpz_divisible_2exp_p (d, 1) == 0)
+        return 0; /* d must be even */
+      mpz_mul (a, c, c);
+      mpz_addmul (a, d, d); /* c^2 + d^2 */
+      if (mpz_perfect_square_p (a))
+        {
+          mpz_sqrt (a, a);
+          mpz_add (a, c, a); /* c + sqrt(c^2+d^2) */
+          if (mpz_divisible_2exp_p (a, 1))
+            {
+              mpz_tdiv_q_2exp (a, a, 1);
+              if (mpz_perfect_square_p (a))
+                {
+                  mpz_sqrt (a, a);
+                  mpz_tdiv_q_2exp (b, d, 1); /* d/2 */
+                  mpz_divexact (b, b, a); /* d/(2a) */
+                  return 1;
+                }
+            }
+        }
+    }
+  return 0; /* not a square */
+}
+
+/* fix the sign of Re(z) or Im(z) in case it is zero,
+   and Re(x) is zero.
+   sign_eps is 0 if Re(x) = +0, 1 if Re(x) = -0
+   sign_a is the sign bit of Im(x).
+   Assume y is an integer (does nothing otherwise).
+*/
+static void
+fix_sign (mpc_ptr z, int sign_eps, int sign_a, mpfr_srcptr y)
+{
+  int ymod4 = -1;
+  mpfr_exp_t ey;
+  mpz_t my;
+  unsigned long int t;
+
+  mpz_init (my);
+
+  ey = mpfr_get_z_exp (my, y);
+  /* normalize so that my is odd */
+  t = mpz_scan1 (my, 0);
+  ey += (mpfr_exp_t) t;
+  mpz_tdiv_q_2exp (my, my, t);
+  /* y = my*2^ey */
+
+  /* compute y mod 4 (in case y is an integer) */
+  if (ey >= 2)
+    ymod4 = 0;
+  else if (ey == 1)
+    ymod4 = mpz_tstbit (my, 0) * 2; /* correct if my < 0 */
+  else if (ey == 0)
+    {
+      ymod4 = mpz_tstbit (my, 1) * 2 + mpz_tstbit (my, 0);
+      if (mpz_cmp_ui (my , 0) < 0)
+        ymod4 = 4 - ymod4;
+    }
+  else /* y is not an integer */
+    goto end;
+
+  if (mpfr_zero_p (mpc_realref(z)))
+    {
+      /* we assume y is always integer in that case (FIXME: prove it):
+         (eps+I*a)^y = +0 + I*a^y for y = 1 mod 4 and sign_eps = 0
+         (eps+I*a)^y = -0 - I*a^y for y = 3 mod 4 and sign_eps = 0 */
+      MPC_ASSERT (ymod4 == 1 || ymod4 == 3);
+      if ((ymod4 == 3 && sign_eps == 0) ||
+          (ymod4 == 1 && sign_eps == 1))
+        mpfr_neg (mpc_realref(z), mpc_realref(z), GMP_RNDZ);
+    }
+  else if (mpfr_zero_p (mpc_imagref(z)))
+    {
+      /* we assume y is always integer in that case (FIXME: prove it):
+         (eps+I*a)^y =  a^y - 0*I for y = 0 mod 4 and sign_a = sign_eps
+         (eps+I*a)^y =  -a^y +0*I for y = 2 mod 4 and sign_a = sign_eps */
+      MPC_ASSERT (ymod4 == 0 || ymod4 == 2);
+      if ((ymod4 == 0 && sign_a == sign_eps) ||
+          (ymod4 == 2 && sign_a != sign_eps))
+        mpfr_neg (mpc_imagref(z), mpc_imagref(z), GMP_RNDZ);
+    }
+
+ end:
+  mpz_clear (my);
+}
+
+/* If x^y is exactly representable (with maybe a larger precision than z),
+   round it in z and return the (mpc) inexact flag in [0, 10].
+
+   If x^y is not exactly representable, return -1.
+
+   If intermediate computations lead to numbers of more than maxprec bits,
+   then abort and return -2 (in that case, to avoid loops, mpc_pow_exact
+   should be called again with a larger value of maxprec).
+
+   Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real).
+
+   Warning: z and x might be the same variable, same for Re(z) or Im(z) and y.
+
+   In case -1 or -2 is returned, z is not modified.
+*/
+static int
+mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd,
+               mpfr_prec_t maxprec)
+{
+  mpfr_exp_t ec, ed, ey;
+  mpz_t my, a, b, c, d, u;
+  unsigned long int t;
+  int ret = -2;
+  int sign_rex = mpfr_signbit (mpc_realref(x));
+  int sign_imx = mpfr_signbit (mpc_imagref(x));
+  int x_imag = mpfr_zero_p (mpc_realref(x));
+  int z_is_y = 0;
+  mpfr_t copy_of_y;
+
+  if (mpc_realref (z) == y || mpc_imagref (z) == y)
+    {
+      z_is_y = 1;
+      mpfr_init2 (copy_of_y, mpfr_get_prec (y));
+      mpfr_set (copy_of_y, y, GMP_RNDN);
+    }
+
+  mpz_init (my);
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (c);
+  mpz_init (d);
+  mpz_init (u);
+
+  ey = mpfr_get_z_exp (my, y);
+  /* normalize so that my is odd */
+  t = mpz_scan1 (my, 0);
+  ey += (mpfr_exp_t) t;
+  mpz_tdiv_q_2exp (my, my, t);
+  /* y = my*2^ey with my odd */
+
+  if (x_imag)
+    {
+      mpz_set_ui (c, 0);
+      ec = 0;
+    }
+  else
+    ec = mpfr_get_z_exp (c, mpc_realref(x));
+  if (mpfr_zero_p (mpc_imagref(x)))
+    {
+      mpz_set_ui (d, 0);
+      ed = ec;
+    }
+  else
+    {
+      ed = mpfr_get_z_exp (d, mpc_imagref(x));
+      if (x_imag)
+        ec = ed;
+    }
+  /* x = c*2^ec + I * d*2^ed */
+  /* equalize the exponents of x */
+  if (ec < ed)
+    {
+      mpz_mul_2exp (d, d, (unsigned long int) (ed - ec));
+      if ((mpfr_prec_t) mpz_sizeinbase (d, 2) > maxprec)
+        goto end;
+    }
+  else if (ed < ec)
+    {
+      mpz_mul_2exp (c, c, (unsigned long int) (ec - ed));
+      if ((mpfr_prec_t) mpz_sizeinbase (c, 2) > maxprec)
+        goto end;
+      ec = ed;
+    }
+  /* now ec=ed and x = (c + I * d) * 2^ec */
+
+  /* divide by two if possible */
+  if (mpz_cmp_ui (c, 0) == 0)
+    {
+      t = mpz_scan1 (d, 0);
+      mpz_tdiv_q_2exp (d, d, t);
+      ec += (mpfr_exp_t) t;
+    }
+  else if (mpz_cmp_ui (d, 0) == 0)
+    {
+      t = mpz_scan1 (c, 0);
+      mpz_tdiv_q_2exp (c, c, t);
+      ec += (mpfr_exp_t) t;
+    }
+  else /* neither c nor d is zero */
+    {
+      unsigned long v;
+      t = mpz_scan1 (c, 0);
+      v = mpz_scan1 (d, 0);
+      if (v < t)
+        t = v;
+      mpz_tdiv_q_2exp (c, c, t);
+      mpz_tdiv_q_2exp (d, d, t);
+      ec += (mpfr_exp_t) t;
+    }
+
+  /* now either one of c, d is odd */
+
+  while (ey < 0)
+    {
+      /* check if x is a square */
+      if (ec & 1)
+        {
+          mpz_mul_2exp (c, c, 1);
+          mpz_mul_2exp (d, d, 1);
+          ec --;
+        }
+      /* now ec is even */
+      if (mpc_perfect_square_p (a, b, c, d) == 0)
+        break;
+      mpz_swap (a, c);
+      mpz_swap (b, d);
+      ec /= 2;
+      ey ++;
+    }
+
+  if (ey < 0)
+    {
+      ret = -1; /* not representable */
+      goto end;
+    }
+
+  /* Now ey >= 0, it thus suffices to check that x^my is representable.
+     If my > 0, this is always true. If my < 0, we first try to invert
+     (c+I*d)*2^ec.
+  */
+  if (mpz_cmp_ui (my, 0) < 0)
+    {
+      /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient
+         condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|.
+         Assume a prime p <> 2 divides c^2 + d^2,
+         then if p does not divide c or d, 1 / (c + I*d) cannot be exact.
+         If p divides both c and d, then we can write c = p*c', d = p*d',
+         and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d)
+         is exact, then 1/(c' + I*d') is exact too, and we are back to the
+         previous case. In conclusion, a necessary and sufficient condition
+         is that c^2 + d^2 is a power of two.
+      */
+      /* FIXME: we could first compute c^2+d^2 mod a limb for example */
+      mpz_mul (a, c, c);
+      mpz_addmul (a, d, d);
+      t = mpz_scan1 (a, 0);
+      if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */
+        {
+          ret = -1; /* not representable */
+          goto end;
+        }
+      /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */
+      mpz_neg (d, d);
+      ec = -ec - (mpfr_exp_t) t;
+      mpz_neg (my, my);
+    }
+
+  /* now ey >= 0 and my >= 0, and we want to compute
+     [(c + I * d) * 2^ec] ^ (my * 2^ey).
+
+     We first compute [(c + I * d) * 2^ec]^my, then square ey times. */
+  t = mpz_sizeinbase (my, 2) - 1;
+  mpz_set (a, c);
+  mpz_set (b, d);
+  ed = ec;
+  /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */
+  while (t-- > 0)
+    {
+      unsigned long int v, w;
+      /* square a + I*b */
+      mpz_mul (u, a, b);
+      mpz_mul (a, a, a);
+      mpz_submul (a, b, b);
+      mpz_mul_2exp (b, u, 1);
+      ed *= 2;
+      if (mpz_tstbit (my, t)) /* multiply by c + I*d */
+        {
+          mpz_mul (u, a, c);
+          mpz_submul (u, b, d); /* ac-bd */
+          mpz_mul (b, b, c);
+          mpz_addmul (b, a, d); /* bc+ad */
+          mpz_swap (a, u);
+          ed += ec;
+        }
+      /* remove powers of two in (a,b) */
+      if (mpz_cmp_ui (a, 0) == 0)
+        {
+          w = mpz_scan1 (b, 0);
+          mpz_tdiv_q_2exp (b, b, w);
+          ed += (mpfr_exp_t) w;
+        }
+      else if (mpz_cmp_ui (b, 0) == 0)
+        {
+          w = mpz_scan1 (a, 0);
+          mpz_tdiv_q_2exp (a, a, w);
+          ed += (mpfr_exp_t) w;
+        }
+      else
+        {
+          w = mpz_scan1 (a, 0);
+          v = mpz_scan1 (b, 0);
+          if (v < w)
+            w = v;
+          mpz_tdiv_q_2exp (a, a, w);
+          mpz_tdiv_q_2exp (b, b, w);
+          ed += (mpfr_exp_t) w;
+        }
+      if (   (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
+          || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
+        goto end;
+    }
+  /* now a+I*b = (c+I*d)^my */
+
+  while (ey-- > 0)
+    {
+      unsigned long sa, sb;
+
+      /* square a + I*b */
+      mpz_mul (u, a, b);
+      mpz_mul (a, a, a);
+      mpz_submul (a, b, b);
+      mpz_mul_2exp (b, u, 1);
+      ed *= 2;
+
+      /* divide by largest 2^n possible, to avoid many loops for e.g.,
+         (2+2*I)^16777216 */
+      sa = mpz_scan1 (a, 0);
+      sb = mpz_scan1 (b, 0);
+      sa = (sa <= sb) ? sa : sb;
+      mpz_tdiv_q_2exp (a, a, sa);
+      mpz_tdiv_q_2exp (b, b, sa);
+      ed += (mpfr_exp_t) sa;
+
+      if (   (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
+          || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
+        goto end;
+    }
+
+  ret = mpfr_set_z (mpc_realref(z), a, MPC_RND_RE(rnd));
+  ret = MPC_INEX(ret, mpfr_set_z (mpc_imagref(z), b, MPC_RND_IM(rnd)));
+  mpfr_mul_2si (mpc_realref(z), mpc_realref(z), ed, MPC_RND_RE(rnd));
+  mpfr_mul_2si (mpc_imagref(z), mpc_imagref(z), ed, MPC_RND_IM(rnd));
+
+ end:
+  mpz_clear (my);
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (c);
+  mpz_clear (d);
+  mpz_clear (u);
+
+  if (ret >= 0 && x_imag)
+    fix_sign (z, sign_rex, sign_imx, (z_is_y) ? copy_of_y : y);
+
+  if (z_is_y)
+    mpfr_clear (copy_of_y);
+
+  return ret;
+}
+
+/* Return 1 if y*2^k is an odd integer, 0 otherwise.
+   Adapted from MPFR, file pow.c.
+
+   Examples: with k=0, check if y is an odd integer,
+             with k=1, check if y is half-an-integer,
+             with k=-1, check if y/2 is an odd integer.
+*/
+#define MPFR_LIMB_HIGHBIT ((mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1))
+static int
+is_odd (mpfr_srcptr y, mpfr_exp_t k)
+{
+  mpfr_exp_t expo;
+  mpfr_prec_t prec;
+  mp_size_t yn;
+  mp_limb_t *yp;
+
+  expo = mpfr_get_exp (y) + k;
+  if (expo <= 0)
+    return 0;  /* |y| < 1 and not 0 */
+
+  prec = mpfr_get_prec (y);
+  if ((mpfr_prec_t) expo > prec)
+    return 0;  /* y is a multiple of 2^(expo-prec), thus not odd */
+
+  /* 0 < expo <= prec:
+     y = 1xxxxxxxxxt.zzzzzzzzzzzzzzzzzz[000]
+          expo bits   (prec-expo) bits
+
+     We have to check that:
+     (a) the bit 't' is set
+     (b) all the 'z' bits are zero
+  */
+
+  prec = ((prec - 1) / BITS_PER_MP_LIMB + 1) * BITS_PER_MP_LIMB - expo;
+  /* number of z+0 bits */
+
+  yn = prec / BITS_PER_MP_LIMB;
+  /* yn is the index of limb containing the 't' bit */
+
+  yp = y->_mpfr_d;
+  /* if expo is a multiple of BITS_PER_MP_LIMB, t is bit 0 */
+  if (expo % BITS_PER_MP_LIMB == 0 ? (yp[yn] & 1) == 0
+      : yp[yn] << ((expo % BITS_PER_MP_LIMB) - 1) != MPFR_LIMB_HIGHBIT)
+    return 0;
+  while (--yn >= 0)
+    if (yp[yn] != 0)
+      return 0;
+  return 1;
+}
+
+/* Put in z the value of x^y, rounded according to 'rnd'.
+   Return the inexact flag in [0, 10]. */
+int
+mpc_pow (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+  int ret = -2, loop, x_real, x_imag, y_real, z_real = 0, z_imag = 0;
+  mpc_t t, u;
+  mpfr_prec_t p, pr, pi, maxprec;
+  int saved_underflow, saved_overflow;
+  
+  /* save the underflow or overflow flags from MPFR */
+  saved_underflow = mpfr_underflow_p ();
+  saved_overflow = mpfr_overflow_p ();
+
+  x_real = mpfr_zero_p (mpc_imagref(x));
+  y_real = mpfr_zero_p (mpc_imagref(y));
+
+  if (y_real && mpfr_zero_p (mpc_realref(y))) /* case y zero */
+    {
+      if (x_real && mpfr_zero_p (mpc_realref(x)))
+        {
+          /* we define 0^0 to be (1, +0) since the real part is
+             coherent with MPFR where 0^0 gives 1, and the sign of the
+             imaginary part cannot be determined                       */
+          mpc_set_ui_ui (z, 1, 0, MPC_RNDNN);
+          return 0;
+        }
+      else /* x^0 = 1 +/- i*0 even for x=NaN see algorithms.tex for the
+              sign of zero */
+        {
+          mpfr_t n;
+          int inex, cx1;
+          int sign_zi;
+          /* cx1 < 0 if |x| < 1
+             cx1 = 0 if |x| = 1
+             cx1 > 0 if |x| > 1
+          */
+          mpfr_init (n);
+          inex = mpc_norm (n, x, GMP_RNDN);
+          cx1 = mpfr_cmp_ui (n, 1);
+          if (cx1 == 0 && inex != 0)
+            cx1 = -inex;
+
+          sign_zi = (cx1 < 0 && mpfr_signbit (mpc_imagref (y)) == 0)
+            || (cx1 == 0
+                && mpfr_signbit (mpc_imagref (x)) != mpfr_signbit (mpc_realref (y)))
+            || (cx1 > 0 && mpfr_signbit (mpc_imagref (y)));
+
+          /* warning: mpc_set_ui_ui does not set Im(z) to -0 if Im(rnd)=RNDD */
+          ret = mpc_set_ui_ui (z, 1, 0, rnd);
+
+          if (MPC_RND_IM (rnd) == GMP_RNDD || sign_zi)
+            mpc_conj (z, z, MPC_RNDNN);
+
+          mpfr_clear (n);
+          return ret;
+        }
+    }
+
+  if (!mpc_fin_p (x) || !mpc_fin_p (y))
+    {
+      /* special values: exp(y*log(x)) */
+      mpc_init2 (u, 2);
+      mpc_log (u, x, MPC_RNDNN);
+      mpc_mul (u, u, y, MPC_RNDNN);
+      ret = mpc_exp (z, u, rnd);
+      mpc_clear (u);
+      goto end;
+    }
+
+  if (x_real) /* case x real */
+    {
+      if (mpfr_zero_p (mpc_realref(x))) /* x is zero */
+        {
+          /* special values: exp(y*log(x)) */
+          mpc_init2 (u, 2);
+          mpc_log (u, x, MPC_RNDNN);
+          mpc_mul (u, u, y, MPC_RNDNN);
+          ret = mpc_exp (z, u, rnd);
+          mpc_clear (u);
+          goto end;
+        }
+
+      /* Special case 1^y = 1 */
+      if (mpfr_cmp_ui (mpc_realref(x), 1) == 0)
+        {
+          int s1, s2;
+          s1 = mpfr_signbit (mpc_realref (y));
+          s2 = mpfr_signbit (mpc_imagref (x));
+
+          ret = mpc_set_ui (z, +1, rnd);
+          /* the sign of the zero imaginary part is known in some cases (see
+             algorithm.tex). In such cases we have
+             (x +s*0i)^(y+/-0i) = x^y + s*sign(y)*0i
+             where s = +/-1.  We extend here this rule to fix the sign of the
+             zero part.
+
+             Note that the sign must also be set explicitly when rnd=RNDD
+             because mpfr_set_ui(z_i, 0, rnd) always sets z_i to +0.
+          */
+          if (MPC_RND_IM (rnd) == GMP_RNDD || s1 != s2)
+            mpc_conj (z, z, MPC_RNDNN);
+          goto end;
+        }
+
+      /* x^y is real when:
+         (a) x is real and y is integer
+         (b) x is real non-negative and y is real */
+      if (y_real && (mpfr_integer_p (mpc_realref(y)) ||
+                     mpfr_cmp_ui (mpc_realref(x), 0) >= 0))
+        {
+          int s1, s2;
+          s1 = mpfr_signbit (mpc_realref (y));
+          s2 = mpfr_signbit (mpc_imagref (x));
+
+          ret = mpfr_pow (mpc_realref(z), mpc_realref(x), mpc_realref(y), MPC_RND_RE(rnd));
+          ret = MPC_INEX(ret, mpfr_set_ui (mpc_imagref(z), 0, MPC_RND_IM(rnd)));
+
+          /* the sign of the zero imaginary part is known in some cases
+             (see algorithm.tex). In such cases we have (x +s*0i)^(y+/-0i)
+             = x^y + s*sign(y)*0i where s = +/-1.
+             We extend here this rule to fix the sign of the zero part.
+
+             Note that the sign must also be set explicitly when rnd=RNDD
+             because mpfr_set_ui(z_i, 0, rnd) always sets z_i to +0.
+          */
+          if (MPC_RND_IM(rnd) == GMP_RNDD || s1 != s2)
+            mpfr_neg (mpc_imagref(z), mpc_imagref(z), MPC_RND_IM(rnd));
+          goto end;
+        }
+
+      /* (-1)^(n+I*t) is real for n integer and t real */
+      if (mpfr_cmp_si (mpc_realref(x), -1) == 0 && mpfr_integer_p (mpc_realref(y)))
+        z_real = 1;
+
+      /* for x real, x^y is imaginary when:
+         (a) x is negative and y is half-an-integer
+         (b) x = -1 and Re(y) is half-an-integer
+      */
+      if ((mpfr_cmp_ui (mpc_realref(x), 0) < 0) && is_odd (mpc_realref(y), 1)
+         && (y_real || mpfr_cmp_si (mpc_realref(x), -1) == 0))
+        z_imag = 1;
+    }
+  else /* x non real */
+    /* I^(t*I) and (-I)^(t*I) are real for t real,
+       I^(n+t*I) and (-I)^(n+t*I) are real for n even and t real, and
+       I^(n+t*I) and (-I)^(n+t*I) are imaginary for n odd and t real
+       (s*I)^n is real for n even and imaginary for n odd */
+    if ((mpc_cmp_si_si (x, 0, 1) == 0 || mpc_cmp_si_si (x, 0, -1) == 0 ||
+         (mpfr_cmp_ui (mpc_realref(x), 0) == 0 && y_real)) &&
+        mpfr_integer_p (mpc_realref(y)))
+      { /* x is I or -I, and Re(y) is an integer */
+        if (is_odd (mpc_realref(y), 0))
+          z_imag = 1; /* Re(y) odd: z is imaginary */
+        else
+          z_real = 1; /* Re(y) even: z is real */
+      }
+    else /* (t+/-t*I)^(2n) is imaginary for n odd and real for n even */
+      if (mpfr_cmpabs (mpc_realref(x), mpc_imagref(x)) == 0 && y_real &&
+          mpfr_integer_p (mpc_realref(y)) && is_odd (mpc_realref(y), 0) == 0)
+        {
+          if (is_odd (mpc_realref(y), -1)) /* y/2 is odd */
+            z_imag = 1;
+          else
+            z_real = 1;
+        }
+
+  pr = mpfr_get_prec (mpc_realref(z));
+  pi = mpfr_get_prec (mpc_imagref(z));
+  p = (pr > pi) ? pr : pi;
+  p += 12; /* experimentally, seems to give less than 10% of failures in
+              Ziv's strategy; probably wrong now since q is not computed      */
+  if (p < 64)
+    p = 64;
+  mpc_init2 (u, p);
+  mpc_init2 (t, p);
+  pr += MPC_RND_RE(rnd) == GMP_RNDN;
+  pi += MPC_RND_IM(rnd) == GMP_RNDN;
+  maxprec = MPC_MAX_PREC (z);
+  x_imag = mpfr_zero_p (mpc_realref(x));
+  for (loop = 0;; loop++)
+    {
+      int ret_exp;
+      mpfr_exp_t dr, di;
+      mpfr_prec_t q=0;
+      /* to avoid warning message, real initialisation below */
+
+      mpc_log (t, x, MPC_RNDNN);
+      mpc_mul (t, t, y, MPC_RNDNN);
+
+      if (loop == 0) {
+         /* compute q such that |Re (y log x)|, |Im (y log x)| < 2^q */
+         q = mpfr_get_exp (mpc_realref(t)) > 0 ? mpfr_get_exp (mpc_realref(t)) : 0;
+         if (mpfr_get_exp (mpc_imagref(t)) > (mpfr_exp_t) q)
+            q = mpfr_get_exp (mpc_imagref(t));
+      }
+
+      mpfr_clear_overflow ();
+      mpfr_clear_underflow ();
+      ret_exp = mpc_exp (u, t, MPC_RNDNN);
+      if (mpfr_underflow_p () || mpfr_overflow_p ()) {
+         /* under- and overflow flags are set by mpc_exp */
+         mpc_set (z, u, MPC_RNDNN);
+         ret = ret_exp;
+         goto exact;
+      }
+
+      /* Since the error bound is global, we have to take into account the
+         exponent difference between the real and imaginary parts. We assume
+         either the real or the imaginary part of u is not zero.
+      */
+      dr = mpfr_zero_p (mpc_realref(u)) ? mpfr_get_exp (mpc_imagref(u))
+        : mpfr_get_exp (mpc_realref(u));
+      di = mpfr_zero_p (mpc_imagref(u)) ? dr : mpfr_get_exp (mpc_imagref(u));
+      if (dr > di)
+        {
+          di = dr - di;
+          dr = 0;
+        }
+      else
+        {
+          dr = di - dr;
+          di = 0;
+        }
+      /* the term -3 takes into account the factor 4 in the complex error
+         (see algorithms.tex) plus one due to the exponent difference: if
+         z = a + I*b, where the relative error on z is at most 2^(-p), and
+         EXP(a) = EXP(b) + k, the relative error on b is at most 2^(k-p) */
+      if ((z_imag || (p > q + 3 + dr && mpfr_can_round (mpc_realref(u), p - q - 3 - dr, GMP_RNDN, GMP_RNDZ, pr))) &&
+          (z_real || (p > q + 3 + di && mpfr_can_round (mpc_imagref(u), p - q - 3 - di, GMP_RNDN, GMP_RNDZ, pi))))
+        break;
+
+      /* if Re(u) is not known to be zero, assume it is a normal number, i.e.,
+         neither zero, Inf or NaN, otherwise we might enter an infinite loop */
+      MPC_ASSERT (z_imag || mpfr_number_p (mpc_realref(u)));
+      /* idem for Im(u) */
+      MPC_ASSERT (z_real || mpfr_number_p (mpc_imagref(u)));
+
+      if (ret == -2) /* we did not yet call mpc_pow_exact, or it aborted
+                        because intermediate computations had > maxprec bits */
+        {
+          /* check exact cases (see algorithms.tex) */
+          if (y_real)
+            {
+              maxprec *= 2;
+              ret = mpc_pow_exact (z, x, mpc_realref(y), rnd, maxprec);
+              if (ret != -1 && ret != -2)
+                goto exact;
+            }
+          p += dr + di + 64;
+        }
+      else
+        p += p / 2;
+      mpc_set_prec (t, p);
+      mpc_set_prec (u, p);
+    }
+
+  if (z_real)
+    {
+      /* When the result is real (see algorithm.tex for details),
+         Im(x^y) =
+         + sign(imag(y))*0i,               if |x| > 1
+         + sign(imag(x))*sign(real(y))*0i, if |x| = 1
+         - sign(imag(y))*0i,               if |x| < 1
+      */
+      mpfr_t n;
+      int inex, cx1;
+      int sign_zi, sign_rex, sign_imx;
+      /* cx1 < 0 if |x| < 1
+         cx1 = 0 if |x| = 1
+         cx1 > 0 if |x| > 1
+      */
+
+      sign_rex = mpfr_signbit (mpc_realref (x));
+      sign_imx = mpfr_signbit (mpc_imagref (x));
+      mpfr_init (n);
+      inex = mpc_norm (n, x, GMP_RNDN);
+      cx1 = mpfr_cmp_ui (n, 1);
+      if (cx1 == 0 && inex != 0)
+        cx1 = -inex;
+
+      sign_zi = (cx1 < 0 && mpfr_signbit (mpc_imagref (y)) == 0)
+        || (cx1 == 0 && sign_imx != mpfr_signbit (mpc_realref (y)))
+        || (cx1 > 0 && mpfr_signbit (mpc_imagref (y)));
+
+      /* copy RE(y) to n since if z==y we will destroy Re(y) below */
+      mpfr_set_prec (n, mpfr_get_prec (mpc_realref (y)));
+      mpfr_set (n, mpc_realref (y), GMP_RNDN);
+      ret = mpfr_set (mpc_realref(z), mpc_realref(u), MPC_RND_RE(rnd));
+      if (y_real && (x_real || x_imag))
+        {
+          /* FIXME: with y_real we assume Im(y) is really 0, which is the case
+             for example when y comes from pow_fr, but in case Im(y) is +0 or
+             -0, we might get different results */
+          mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd));
+          fix_sign (z, sign_rex, sign_imx, n);
+          ret = MPC_INEX(ret, 0); /* imaginary part is exact */
+        }
+      else
+        {
+          ret = MPC_INEX (ret, mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd)));
+          /* warning: mpfr_set_ui does not set Im(z) to -0 if Im(rnd) = RNDD */
+          if (MPC_RND_IM (rnd) == GMP_RNDD || sign_zi)
+            mpc_conj (z, z, MPC_RNDNN);
+        }
+
+      mpfr_clear (n);
+    }
+  else if (z_imag)
+    {
+      ret = mpfr_set (mpc_imagref(z), mpc_imagref(u), MPC_RND_IM(rnd));
+      /* if z is imaginary and y real, then x cannot be real */
+      if (y_real && x_imag)
+        {
+          int sign_rex = mpfr_signbit (mpc_realref (x));
+
+          /* If z overlaps with y we set Re(z) before checking Re(y) below,
+             but in that case y=0, which was dealt with above. */
+          mpfr_set_ui (mpc_realref (z), 0, MPC_RND_RE (rnd));
+          /* Note: fix_sign only does something when y is an integer,
+             then necessarily y = 1 or 3 (mod 4), and in that case the
+             sign of Im(x) is irrelevant. */
+          fix_sign (z, sign_rex, 0, mpc_realref (y));
+          ret = MPC_INEX(0, ret);
+        }
+      else
+        ret = MPC_INEX(mpfr_set_ui (mpc_realref(z), 0, MPC_RND_RE(rnd)), ret);
+    }
+  else
+    ret = mpc_set (z, u, rnd);
+ exact:
+  mpc_clear (t);
+  mpc_clear (u);
+
+  /* restore underflow and overflow flags from MPFR */
+  if (saved_underflow)
+    mpfr_set_underflow ();
+  if (saved_overflow)
+    mpfr_set_overflow ();
+
+ end:
+  return ret;
+}
diff --git a/contrib/mpc/src/pow_d.c b/contrib/mpc/src/pow_d.c
new file mode 100644 (file)
index 0000000..8034b26
--- /dev/null
@@ -0,0 +1,38 @@
+/* mpc_pow_d -- Raise a complex number to a double-precision power.
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include <float.h>    /* for DBL_MANT_DIG */
+#include "mpc-impl.h"
+
+int
+mpc_pow_d (mpc_ptr z, mpc_srcptr x, double y, mpc_rnd_t rnd)
+{
+  mpc_t yy;
+  int inex;
+  
+  MPC_ASSERT(FLT_RADIX == 2);
+  mpc_init3 (yy, DBL_MANT_DIG, MPFR_PREC_MIN);
+  mpc_set_d (yy, y, MPC_RNDNN);   /* exact */
+  inex = mpc_pow (z, x, yy, rnd);
+  mpc_clear (yy);
+  return inex;
+}
+
diff --git a/contrib/mpc/src/pow_fr.c b/contrib/mpc/src/pow_fr.c
new file mode 100644 (file)
index 0000000..8c5d930
--- /dev/null
@@ -0,0 +1,37 @@
+/* mpc_pow_fr -- Raise a complex number to a floating-point power.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_fr (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd)
+{
+  mpc_t yy;
+  int inex;
+
+  /* avoid copying the significand of y by copying only the struct */
+  mpc_realref(yy)[0] = y[0];
+  mpfr_init2 (mpc_imagref(yy), MPFR_PREC_MIN);
+  mpfr_set_ui (mpc_imagref(yy), 0, GMP_RNDN);
+  inex = mpc_pow (z, x, yy, rnd);
+  mpfr_clear (mpc_imagref(yy));
+  return inex;
+}
+
diff --git a/contrib/mpc/src/pow_ld.c b/contrib/mpc/src/pow_ld.c
new file mode 100644 (file)
index 0000000..9d98a98
--- /dev/null
@@ -0,0 +1,38 @@
+/* mpc_pow_ld -- Raise a complex number to a long double power.
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include <float.h>    /* for LDBL_MANT_DIG */
+#include "mpc-impl.h"
+
+int
+mpc_pow_ld (mpc_ptr z, mpc_srcptr x, long double y, mpc_rnd_t rnd)
+{
+  mpc_t yy;
+  int inex;
+
+  MPC_ASSERT(FLT_RADIX == 2);
+  mpc_init3 (yy, LDBL_MANT_DIG, MPFR_PREC_MIN);
+  mpc_set_ld (yy, y, MPC_RNDNN);   /* exact */
+  inex = mpc_pow (z, x, yy, rnd);
+  mpc_clear (yy);
+  return inex;
+}
+
diff --git a/contrib/mpc/src/pow_si.c b/contrib/mpc/src/pow_si.c
new file mode 100644 (file)
index 0000000..5b5c5d9
--- /dev/null
@@ -0,0 +1,30 @@
+/* mpc_pow_si -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_si (mpc_ptr z, mpc_srcptr x, long y, mpc_rnd_t rnd)
+{
+   if (y >= 0)
+     return mpc_pow_usi (z, x, (unsigned long) y, 1, rnd);
+   else
+     return mpc_pow_usi (z, x, (unsigned long) (-y), -1, rnd);
+}
diff --git a/contrib/mpc/src/pow_ui.c b/contrib/mpc/src/pow_ui.c
new file mode 100644 (file)
index 0000000..da82a94
--- /dev/null
@@ -0,0 +1,169 @@
+/* mpc_pow_ui -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <limits.h> /* for CHAR_BIT */
+#include "mpc-impl.h"
+
+static int
+mpc_pow_usi_naive (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
+   mpc_rnd_t rnd)
+{
+   int inex;
+   mpc_t t;
+
+   mpc_init3 (t, sizeof (unsigned long) * CHAR_BIT, MPFR_PREC_MIN);
+   if (sign > 0)
+      mpc_set_ui (t, y, MPC_RNDNN); /* exact */
+   else
+      mpc_set_si (t, - (signed long) y, MPC_RNDNN);
+   inex = mpc_pow (z, x, t, rnd);
+   mpc_clear (t);
+
+   return inex;
+}
+
+
+int
+mpc_pow_usi (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
+   mpc_rnd_t rnd)
+   /* computes z = x^(sign*y) */
+{
+   int inex;
+   mpc_t t, x3;
+   mpfr_prec_t p, l, l0;
+   long unsigned int u;
+   int has3; /* non-zero if y has '11' in its binary representation */
+   int loop, done;
+
+   /* let mpc_pow deal with special values */
+   if (!mpc_fin_p (x) || mpfr_zero_p (mpc_realref (x)) || mpfr_zero_p (mpc_imagref(x))
+       || y == 0)
+      return mpc_pow_usi_naive (z, x, y, sign, rnd);
+   /* easy special cases */
+   else if (y == 1) {
+      if (sign > 0)
+         return mpc_set (z, x, rnd);
+      else
+         return mpc_ui_div (z, 1ul, x, rnd);
+   }
+   else if (y == 2 && sign > 0)
+      return mpc_sqr (z, x, rnd);
+   /* let mpc_pow treat potential over- and underflows */
+   else {
+      mpfr_exp_t exp_r = mpfr_get_exp (mpc_realref (x)),
+                 exp_i = mpfr_get_exp (mpc_imagref (x));
+      if (   MPC_MAX (exp_r, exp_i) > mpfr_get_emax () / (mpfr_exp_t) y
+             /* heuristic for overflow */
+          || MPC_MAX (-exp_r, -exp_i) > (-mpfr_get_emin ()) / (mpfr_exp_t) y
+             /* heuristic for underflow */
+         )
+         return mpc_pow_usi_naive (z, x, y, sign, rnd);
+   }
+
+   has3 = (y & (y >> 1)) != 0;
+   for (l = 0, u = y; u > 3; l ++, u >>= 1);
+   /* l>0 is the number of bits of y, minus 2, thus y has bits:
+      y_{l+1} y_l y_{l-1} ... y_1 y_0 */
+   l0 = l + 2;
+   p = MPC_MAX_PREC(z) + l0 + 32; /* l0 ensures that y*2^{-p} <= 1 below */
+   mpc_init2 (t, p);
+   if (has3)
+      mpc_init2 (x3, p);
+
+   loop = 0;
+   done = 0;
+   while (!done) {
+      loop++;
+
+      mpc_sqr (t, x, MPC_RNDNN);
+      if (has3) {
+         mpc_mul (x3, t, x, MPC_RNDNN);
+         if ((y >> l) & 1) /* y starts with 11... */
+            mpc_set (t, x3, MPC_RNDNN);
+      }
+      while (l-- > 0) {
+         mpc_sqr (t, t, MPC_RNDNN);
+         if ((y >> l) & 1) {
+            if ((l > 0) && ((y >> (l-1)) & 1)) /* implies has3 <> 0 */ {
+               l--;
+               mpc_sqr (t, t, MPC_RNDNN);
+               mpc_mul (t, t, x3, MPC_RNDNN);
+            }
+            else
+               mpc_mul (t, t, x, MPC_RNDNN);
+         }
+      }
+      if (sign < 0)
+         mpc_ui_div (t, 1ul, t, MPC_RNDNN);
+
+      if (mpfr_zero_p (mpc_realref(t)) || mpfr_zero_p (mpc_imagref(t))) {
+         inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
+            /* since mpfr_get_exp() is not defined for zero */
+         done = 1;
+      }
+      else {
+         /* see error bound in algorithms.tex; we use y<2^l0 instead of y-1
+            also when sign>0                                                */
+         mpfr_exp_t diff;
+         mpfr_prec_t er, ei;
+
+         diff = mpfr_get_exp (mpc_realref(t)) - mpfr_get_exp (mpc_imagref(t));
+         /* the factor on the real part is 2+2^(-diff+2) <= 4 for diff >= 1
+            and < 2^(-diff+3) for diff <= 0 */
+         er = (diff >= 1) ? l0 + 3 : l0 + (-diff) + 3;
+         /* the factor on the imaginary part is 2+2^(diff+2) <= 4 for diff <= -1
+            and < 2^(diff+3) for diff >= 0 */
+         ei = (diff <= -1) ? l0 + 3 : l0 + diff + 3;
+         if (mpfr_can_round (mpc_realref(t), p - er, GMP_RNDN, GMP_RNDZ,
+                              MPC_PREC_RE(z) + (MPC_RND_RE(rnd) == GMP_RNDN))
+               && mpfr_can_round (mpc_imagref(t), p - ei, GMP_RNDN, GMP_RNDZ,
+                              MPC_PREC_IM(z) + (MPC_RND_IM(rnd) == GMP_RNDN))) {
+            inex = mpc_set (z, t, rnd);
+            done = 1;
+         }
+         else if (loop == 1 && SAFE_ABS(mpfr_prec_t, diff) < MPC_MAX_PREC(z)) {
+            /* common case, make a second trial at higher precision */
+            p += MPC_MAX_PREC(x);
+            mpc_set_prec (t, p);
+            if (has3)
+               mpc_set_prec (x3, p);
+            l = l0 - 2;
+         }
+         else {
+            /* stop the loop and use mpc_pow */
+            inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
+            done = 1;
+         }
+      }
+   }
+
+   mpc_clear (t);
+   if (has3)
+      mpc_clear (x3);
+
+   return inex;
+}
+
+
+int
+mpc_pow_ui (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
+{
+  return mpc_pow_usi (z, x, y, 1, rnd);
+}
diff --git a/contrib/mpc/src/pow_z.c b/contrib/mpc/src/pow_z.c
new file mode 100644 (file)
index 0000000..22eb544
--- /dev/null
@@ -0,0 +1,47 @@
+/* mpc_pow_z -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_z (mpc_ptr z, mpc_srcptr x, mpz_srcptr y, mpc_rnd_t rnd)
+{
+   mpc_t yy;
+   int inex;
+   mpfr_prec_t n = (mpfr_prec_t) mpz_sizeinbase (y, 2);
+
+   /* if y fits in an unsigned long or long, call the corresponding functions,
+      which are supposed to be more efficient */
+   if (mpz_cmp_ui (y, 0ul) >= 0) {
+      if (mpz_fits_ulong_p (y))
+         return mpc_pow_usi (z, x, mpz_get_ui (y), 1, rnd);
+   }
+   else {
+      if (mpz_fits_slong_p (y))
+         return mpc_pow_usi (z, x, (unsigned long) (-mpz_get_si (y)), -1, rnd);
+   }
+
+   mpc_init3 (yy, (n < MPFR_PREC_MIN) ? MPFR_PREC_MIN : n, MPFR_PREC_MIN);
+   mpc_set_z (yy, y, MPC_RNDNN);   /* exact */
+   inex = mpc_pow (z, x, yy, rnd);
+   mpc_clear (yy);
+   return inex;
+}
+
diff --git a/contrib/mpc/src/proj.c b/contrib/mpc/src/proj.c
new file mode 100644 (file)
index 0000000..ace58c5
--- /dev/null
@@ -0,0 +1,34 @@
+/* mpc_proj -- projection of a complex number onto the Riemann sphere.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_proj (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+   if (mpc_inf_p (b)) {
+      /* infinities project to +Inf +i* copysign(0.0, cimag(z)) */
+      mpfr_set_inf (mpc_realref (a), +1);
+      mpfr_set_zero (mpc_imagref (a), (mpfr_signbit (mpc_imagref (b)) ? -1 : 1));
+      return MPC_INEX (0, 0);
+   }
+   else
+      return mpc_set (a, b, rnd);
+}
diff --git a/contrib/mpc/src/real.c b/contrib/mpc/src/real.c
new file mode 100644 (file)
index 0000000..041dddb
--- /dev/null
@@ -0,0 +1,27 @@
+/* mpc_real -- Get the real part of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_real (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+  return mpfr_set (a, mpc_realref (b), rnd);
+}
diff --git a/contrib/mpc/src/set.c b/contrib/mpc/src/set.c
new file mode 100644 (file)
index 0000000..e7a3c11
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_set -- Set a complex number from another complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_set (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_set (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/set_prec.c b/contrib/mpc/src/set_prec.c
new file mode 100644 (file)
index 0000000..c5e6f24
--- /dev/null
@@ -0,0 +1,28 @@
+/* mpc_set_prec -- reset the precision of a complex variable.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_set_prec (mpc_t x, mpfr_prec_t prec)
+{
+  mpfr_set_prec (mpc_realref(x), prec);
+  mpfr_set_prec (mpc_imagref(x), prec);
+}
diff --git a/contrib/mpc/src/set_str.c b/contrib/mpc/src/set_str.c
new file mode 100644 (file)
index 0000000..195b9ac
--- /dev/null
@@ -0,0 +1,42 @@
+/* mpc_set_str -- Convert a string into a complex number.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <ctype.h>
+#include "mpc-impl.h"
+
+int
+mpc_set_str (mpc_t z, const char *str, int base, mpc_rnd_t rnd)
+{
+  char *p;
+  int inex;
+
+  inex = mpc_strtoc (z, str, &p, base, rnd);
+
+  if (inex != -1){
+     while (isspace ((unsigned char) (*p)))
+        p++;
+     if (*p == '\0')
+        return inex;
+  }
+
+  mpfr_set_nan (mpc_realref (z));
+  mpfr_set_nan (mpc_imagref (z));
+  return -1;
+}
diff --git a/contrib/mpc/src/set_x.c b/contrib/mpc/src/set_x.c
new file mode 100644 (file)
index 0000000..94ec12d
--- /dev/null
@@ -0,0 +1,104 @@
+/* mpc_set_x -- Set the real part of a complex number
+   (imaginary part equals +0 regardless of rounding mode).
+
+Copyright (C) 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# ifdef HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#ifdef HAVE_COMPLEX_H
+# include <complex.h>
+#endif
+
+#include "mpc-impl.h"
+
+#define MPC_SET_X(real_t, z, real_value, rnd)     \
+  {                                                                     \
+    int _inex_re, _inex_im;                                             \
+    _inex_re = (mpfr_set_ ## real_t) (mpc_realref (z), (real_value), MPC_RND_RE (rnd)); \
+    _inex_im = mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd)); \
+    return MPC_INEX (_inex_re, _inex_im);                               \
+  }
+
+int
+mpc_set_fr (mpc_ptr a, mpfr_srcptr b, mpc_rnd_t rnd)
+   MPC_SET_X (fr, a, b, rnd)
+
+int
+mpc_set_d (mpc_ptr a, double b, mpc_rnd_t rnd)
+   MPC_SET_X (d, a, b, rnd)
+
+int
+mpc_set_ld (mpc_ptr a, long double b, mpc_rnd_t rnd)
+   MPC_SET_X (ld, a, b, rnd)
+
+int
+mpc_set_ui (mpc_ptr a, unsigned long int b, mpc_rnd_t rnd)
+   MPC_SET_X (ui, a, b, rnd)
+
+int
+mpc_set_si (mpc_ptr a, long int b, mpc_rnd_t rnd)
+   MPC_SET_X (si, a, b, rnd)
+
+int
+mpc_set_z (mpc_ptr a, mpz_srcptr b, mpc_rnd_t rnd)
+   MPC_SET_X (z, a, b, rnd)
+
+int
+mpc_set_q (mpc_ptr a, mpq_srcptr b, mpc_rnd_t rnd)
+   MPC_SET_X (q, a, b, rnd)
+
+int
+mpc_set_f (mpc_ptr a, mpf_srcptr b, mpc_rnd_t rnd)
+   MPC_SET_X (f, a, b, rnd)
+
+#ifdef _MPC_H_HAVE_INTMAX_T
+int
+mpc_set_uj (mpc_ptr a, uintmax_t b, mpc_rnd_t rnd)
+   MPC_SET_X (uj, a, b, rnd)
+
+int
+mpc_set_sj (mpc_ptr a, intmax_t b, mpc_rnd_t rnd)
+   MPC_SET_X (sj, a, b, rnd)
+#endif
+
+#ifdef HAVE_COMPLEX_H
+int
+mpc_set_dc (mpc_ptr a, double _Complex b, mpc_rnd_t rnd) {
+   return mpc_set_d_d (a, creal (b), cimag (b), rnd);
+}
+
+int
+mpc_set_ldc (mpc_ptr a, long double _Complex b, mpc_rnd_t rnd) {
+   return mpc_set_ld_ld (a, creall (b), cimagl (b), rnd);
+}
+#endif
+
+void
+mpc_set_nan (mpc_ptr a) {
+   mpfr_set_nan (mpc_realref (a));
+   mpfr_set_nan (mpc_imagref (a));
+}
diff --git a/contrib/mpc/src/set_x_x.c b/contrib/mpc/src/set_x_x.c
new file mode 100644 (file)
index 0000000..3ce69f2
--- /dev/null
@@ -0,0 +1,78 @@
+/* mpc_set_x_x -- Set complex number real and imaginary parts from parameters
+   whose type is known by mpfr.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# ifdef HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#include "mpc-impl.h"
+
+#define MPC_SET_X_X(type, z, real_value, imag_value, rnd)       \
+  MPC_SET_X_Y (type, type, z, real_value, imag_value, rnd)
+
+int
+mpc_set_d_d (mpc_ptr z, double a, double b, mpc_rnd_t rnd)
+  MPC_SET_X_X (d, z, a, b, rnd)
+
+int
+mpc_set_f_f (mpc_ptr z, mpf_srcptr a, mpf_srcptr b, mpc_rnd_t rnd)
+  MPC_SET_X_X (f, z, a, b, rnd)
+
+int
+mpc_set_fr_fr (mpc_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpc_rnd_t rnd)
+  MPC_SET_X_X (fr, z, a, b, rnd)
+
+int
+mpc_set_ld_ld (mpc_ptr z, long double a, long double b, mpc_rnd_t rnd)
+  MPC_SET_X_X (ld, z, a, b, rnd)
+
+int
+mpc_set_q_q (mpc_ptr z, mpq_srcptr a, mpq_srcptr b, mpc_rnd_t rnd)
+  MPC_SET_X_X (q, z, a, b, rnd)
+
+int
+mpc_set_si_si (mpc_ptr z, long int a, long int b, mpc_rnd_t rnd)
+  MPC_SET_X_X (si, z, a, b, rnd)
+
+int
+mpc_set_ui_ui (mpc_ptr z, unsigned long int a, unsigned long int b,
+               mpc_rnd_t rnd)
+  MPC_SET_X_X (ui, z, a, b, rnd)
+
+int
+mpc_set_z_z (mpc_ptr z, mpz_srcptr a, mpz_srcptr b, mpc_rnd_t rnd)
+  MPC_SET_X_X (z, z, a, b, rnd)
+
+#ifdef _MPC_H_HAVE_INTMAX_T
+int
+mpc_set_uj_uj (mpc_ptr z, uintmax_t a, uintmax_t b, mpc_rnd_t rnd)
+  MPC_SET_X_X (uj, z, a, b, rnd)
+
+int
+mpc_set_sj_sj (mpc_ptr z, intmax_t a, intmax_t b, mpc_rnd_t rnd)
+  MPC_SET_X_X (sj, z, a, b, rnd)
+#endif
diff --git a/contrib/mpc/src/sin.c b/contrib/mpc/src/sin.c
new file mode 100644 (file)
index 0000000..27df761
--- /dev/null
@@ -0,0 +1,27 @@
+/* mpc_sin -- sine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+   return MPC_INEX1 (mpc_sin_cos (rop, NULL, op, rnd, 0));
+}
diff --git a/contrib/mpc/src/sin_cos.c b/contrib/mpc/src/sin_cos.c
new file mode 100644 (file)
index 0000000..0cff45a
--- /dev/null
@@ -0,0 +1,402 @@
+/* mpc_sin_cos -- combined sine and cosine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+static int
+mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+   /* assumes that op (that is, its real or imaginary part) is not finite */
+{
+   int overlap;
+   mpc_t op_loc;
+
+   overlap = (rop_sin == op || rop_cos == op);
+   if (overlap) {
+      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
+      mpc_set (op_loc, op, MPC_RNDNN);
+   }
+   else
+      op_loc [0] = op [0];
+
+   if (rop_sin != NULL) {
+      if (mpfr_nan_p (mpc_realref (op_loc)) || mpfr_nan_p (mpc_imagref (op_loc))) {
+         mpc_set (rop_sin, op_loc, rnd_sin);
+         if (mpfr_nan_p (mpc_imagref (op_loc))) {
+            /* sin(x +i*NaN) = NaN +i*NaN, except for x=0 */
+            /* sin(-0 +i*NaN) = -0 +i*NaN */
+            /* sin(+0 +i*NaN) = +0 +i*NaN */
+            if (!mpfr_zero_p (mpc_realref (op_loc)))
+               mpfr_set_nan (mpc_realref (rop_sin));
+         }
+         else /* op = NaN + i*y */
+            if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
+            /* sin(NaN -i*Inf) = NaN -i*Inf */
+            /* sin(NaN -i*0) = NaN -i*0 */
+            /* sin(NaN +i*0) = NaN +i*0 */
+            /* sin(NaN +i*Inf) = NaN +i*Inf */
+            /* sin(NaN +i*y) = NaN +i*NaN, when 0<|y|<Inf */
+            mpfr_set_nan (mpc_imagref (rop_sin));
+      }
+      else if (mpfr_inf_p (mpc_realref (op_loc))) {
+         mpfr_set_nan (mpc_realref (rop_sin));
+
+         if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
+            /* sin(+/-Inf +i*y) = NaN +i*NaN, when 0<|y|<Inf */
+            mpfr_set_nan (mpc_imagref (rop_sin));
+         else
+            /* sin(+/-Inf -i*Inf) = NaN -i*Inf */
+            /* sin(+/-Inf +i*Inf) = NaN +i*Inf */
+            /* sin(+/-Inf -i*0) = NaN -i*0 */
+            /* sin(+/-Inf +i*0) = NaN +i*0 */
+            mpfr_set (mpc_imagref (rop_sin), mpc_imagref (op_loc), MPC_RND_IM (rnd_sin));
+      }
+      else if (mpfr_zero_p (mpc_realref (op_loc))) {
+         /* sin(-0 -i*Inf) = -0 -i*Inf */
+         /* sin(+0 -i*Inf) = +0 -i*Inf */
+         /* sin(-0 +i*Inf) = -0 +i*Inf */
+         /* sin(+0 +i*Inf) = +0 +i*Inf */
+         mpc_set (rop_sin, op_loc, rnd_sin);
+      }
+      else {
+         /* sin(x -i*Inf) = +Inf*(sin(x) -i*cos(x)) */
+         /* sin(x +i*Inf) = +Inf*(sin(x) +i*cos(x)) */
+         mpfr_t s, c;
+         mpfr_init2 (s, 2);
+         mpfr_init2 (c, 2);
+         mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDZ);
+         mpfr_set_inf (mpc_realref (rop_sin), MPFR_SIGN (s));
+         mpfr_set_inf (mpc_imagref (rop_sin), MPFR_SIGN (c)*MPFR_SIGN (mpc_imagref (op_loc)));
+         mpfr_clear (s);
+         mpfr_clear (c);
+      }
+   }
+
+   if (rop_cos != NULL) {
+      if (mpfr_nan_p (mpc_realref (op_loc))) {
+         /* cos(NaN + i * NaN) = NaN + i * NaN */
+         /* cos(NaN - i * Inf) = +Inf + i * NaN */
+         /* cos(NaN + i * Inf) = +Inf + i * NaN */
+         /* cos(NaN - i * 0) = NaN - i * 0 */
+         /* cos(NaN + i * 0) = NaN + i * 0 */
+         /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
+         if (mpfr_inf_p (mpc_imagref (op_loc)))
+            mpfr_set_inf (mpc_realref (rop_cos), +1);
+         else
+            mpfr_set_nan (mpc_realref (rop_cos));
+
+         if (mpfr_zero_p (mpc_imagref (op_loc)))
+            mpfr_set (mpc_imagref (rop_cos), mpc_imagref (op_loc), MPC_RND_IM (rnd_cos));
+         else
+            mpfr_set_nan (mpc_imagref (rop_cos));
+      }
+      else if (mpfr_nan_p (mpc_imagref (op_loc))) {
+          /* cos(-Inf + i * NaN) = NaN + i * NaN */
+          /* cos(+Inf + i * NaN) = NaN + i * NaN */
+          /* cos(-0 + i * NaN) = NaN - i * 0 */
+          /* cos(+0 + i * NaN) = NaN + i * 0 */
+          /* cos(x + i * NaN) = NaN + i * NaN, when x != 0 */
+         if (mpfr_zero_p (mpc_realref (op_loc)))
+            mpfr_set (mpc_imagref (rop_cos), mpc_realref (op_loc), MPC_RND_IM (rnd_cos));
+         else
+            mpfr_set_nan (mpc_imagref (rop_cos));
+
+         mpfr_set_nan (mpc_realref (rop_cos));
+      }
+      else if (mpfr_inf_p (mpc_realref (op_loc))) {
+         /* cos(-Inf -i*Inf) = cos(+Inf +i*Inf) = -Inf +i*NaN */
+         /* cos(-Inf +i*Inf) = cos(+Inf -i*Inf) = +Inf +i*NaN */
+         /* cos(-Inf -i*0) = cos(+Inf +i*0) = NaN -i*0 */
+         /* cos(-Inf +i*0) = cos(+Inf -i*0) = NaN +i*0 */
+         /* cos(-Inf +i*y) = cos(+Inf +i*y) = NaN +i*NaN, when y != 0 */
+
+         const int same_sign =
+            mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
+
+         if (mpfr_inf_p (mpc_imagref (op_loc)))
+            mpfr_set_inf (mpc_realref (rop_cos), (same_sign ? -1 : +1));
+         else
+            mpfr_set_nan (mpc_realref (rop_cos));
+
+         if (mpfr_zero_p (mpc_imagref (op_loc)))
+            mpfr_setsign (mpc_imagref (rop_cos), mpc_imagref (op_loc), same_sign,
+                          MPC_RND_IM(rnd_cos));
+         else
+            mpfr_set_nan (mpc_imagref (rop_cos));
+      }
+      else if (mpfr_zero_p (mpc_realref (op_loc))) {
+         /* cos(-0 -i*Inf) = cos(+0 +i*Inf) = +Inf -i*0 */
+         /* cos(-0 +i*Inf) = cos(+0 -i*Inf) = +Inf +i*0 */
+         const int same_sign =
+            mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
+
+         mpfr_setsign (mpc_imagref (rop_cos), mpc_realref (op_loc), same_sign,
+                       MPC_RND_IM (rnd_cos));
+         mpfr_set_inf (mpc_realref (rop_cos), +1);
+      }
+      else {
+         /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
+         /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
+         mpfr_t s, c;
+         mpfr_init2 (c, 2);
+         mpfr_init2 (s, 2);
+         mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDN);
+         mpfr_set_inf (mpc_realref (rop_cos), mpfr_sgn (c));
+         mpfr_set_inf (mpc_imagref (rop_cos),
+            (mpfr_sgn (mpc_imagref (op_loc)) == mpfr_sgn (s) ? -1 : +1));
+         mpfr_clear (s);
+         mpfr_clear (c);
+      }
+   }
+
+   if (overlap)
+      mpc_clear (op_loc);
+
+   return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
+      /* everything is exact */
+}
+
+
+static int
+mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+   /* assumes that op is real */
+{
+   int inex_sin_re = 0, inex_cos_re = 0;
+      /* Until further notice, assume computations exact; in particular,
+         by definition, for not computed values.                         */
+   mpfr_t s, c;
+   int inex_s, inex_c;
+   int sign_im = mpfr_signbit (mpc_imagref (op));
+
+   /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */
+   /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */
+   if (rop_sin != 0)
+      mpfr_init2 (s, MPC_PREC_RE (rop_sin));
+   else
+      mpfr_init2 (s, 2); /* We need only the sign. */
+   if (rop_cos != NULL)
+      mpfr_init2 (c, MPC_PREC_RE (rop_cos));
+   else
+      mpfr_init2 (c, 2);
+   inex_s = mpfr_sin (s, mpc_realref (op), MPC_RND_RE (rnd_sin));
+   inex_c = mpfr_cos (c, mpc_realref (op), MPC_RND_RE (rnd_cos));
+      /* We cannot use mpfr_sin_cos since we may need two distinct rounding
+         modes and the exact return values. If we need only the sign, an
+         arbitrary rounding mode will work.                                 */
+
+   if (rop_sin != NULL) {
+      mpfr_set (mpc_realref (rop_sin), s, GMP_RNDN); /* exact */
+      inex_sin_re = inex_s;
+      mpfr_set_zero (mpc_imagref (rop_sin),
+         (     ( sign_im && !mpfr_signbit(c))
+            || (!sign_im &&  mpfr_signbit(c)) ? -1 : 1));
+   }
+
+   if (rop_cos != NULL) {
+      mpfr_set (mpc_realref (rop_cos), c, GMP_RNDN); /* exact */
+      inex_cos_re = inex_c;
+      mpfr_set_zero (mpc_imagref (rop_cos),
+         (     ( sign_im &&  mpfr_signbit(s))
+            || (!sign_im && !mpfr_signbit(s)) ? -1 : 1));
+   }
+
+   mpfr_clear (s);
+   mpfr_clear (c);
+
+   return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
+}
+
+
+static int
+mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+   /* assumes that op is purely imaginary, but not zero */
+{
+   int inex_sin_im = 0, inex_cos_re = 0;
+      /* assume exact if not computed */
+   int overlap;
+   mpc_t op_loc;
+
+   overlap = (rop_sin == op || rop_cos == op);
+   if (overlap) {
+      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
+      mpc_set (op_loc, op, MPC_RNDNN);
+   }
+   else
+      op_loc [0] = op [0];
+
+   if (rop_sin != NULL) {
+      /* sin(+-O +i*y) = +-0 +i*sinh(y) */
+      mpfr_set (mpc_realref(rop_sin), mpc_realref(op_loc), GMP_RNDN);
+      inex_sin_im = mpfr_sinh (mpc_imagref(rop_sin), mpc_imagref(op_loc), MPC_RND_IM(rnd_sin));
+   }
+
+   if (rop_cos != NULL) {
+      /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0,
+         cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
+         where y > 0 */
+      inex_cos_re = mpfr_cosh (mpc_realref (rop_cos), mpc_imagref (op_loc), MPC_RND_RE (rnd_cos));
+
+      mpfr_set_ui (mpc_imagref (rop_cos), 0ul, MPC_RND_IM (rnd_cos));
+      if (mpfr_signbit (mpc_realref (op_loc)) ==  mpfr_signbit (mpc_imagref (op_loc)))
+         MPFR_CHANGE_SIGN (mpc_imagref (rop_cos));
+   }
+
+   if (overlap)
+      mpc_clear (op_loc);
+
+   return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0));
+}
+
+
+int
+mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+   /* Feature not documented in the texinfo file: One of rop_sin or
+      rop_cos may be NULL, in which case it is not computed, and the
+      corresponding ternary inexact value is set to 0 (exact).       */
+{
+   if (!mpc_fin_p (op))
+      return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+   else if (mpfr_zero_p (mpc_imagref (op)))
+      return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+   else if (mpfr_zero_p (mpc_realref (op)))
+      return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+   else {
+      /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
+                           and  cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).
+
+         For Re(sin(op)) (and analogously, the other parts), we use the
+         following algorithm, with rounding to nearest for all operations
+         and working precision w:
+
+         (1) x = o(sin(a))
+         (2) y = o(cosh(b))
+         (3) r = o(x*y)
+         then the error on r is at most 4 ulps, since we can write
+         r = sin(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
+         thus for w >= 2, r = sin(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
+         thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
+      */
+      mpfr_t s, c, sh, ch, sch, csh;
+      mpfr_prec_t prec;
+      int ok;
+      int inex_re, inex_im, inex_sin, inex_cos;
+
+      prec = 2;
+      if (rop_sin != NULL)
+         prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
+      if (rop_cos != NULL)
+         prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));
+
+      mpfr_init2 (s, 2);
+      mpfr_init2 (c, 2);
+      mpfr_init2 (sh, 2);
+      mpfr_init2 (ch, 2);
+      mpfr_init2 (sch, 2);
+      mpfr_init2 (csh, 2);
+
+      do {
+         ok = 1;
+         prec += mpc_ceil_log2 (prec) + 5;
+
+         mpfr_set_prec (s, prec);
+         mpfr_set_prec (c, prec);
+         mpfr_set_prec (sh, prec);
+         mpfr_set_prec (ch, prec);
+         mpfr_set_prec (sch, prec);
+         mpfr_set_prec (csh, prec);
+
+         mpfr_sin_cos (s, c, mpc_realref(op), GMP_RNDN);
+         mpfr_sinh_cosh (sh, ch, mpc_imagref(op), GMP_RNDN);
+
+         if (rop_sin != NULL) {
+            /* real part of sine */
+            mpfr_mul (sch, s, ch, GMP_RNDN);
+            ok = (!mpfr_number_p (sch))
+                  || mpfr_can_round (sch, prec - 2, GMP_RNDN, GMP_RNDZ,
+                        MPC_PREC_RE (rop_sin)
+                        + (MPC_RND_RE (rnd_sin) == GMP_RNDN));
+
+            if (ok) {
+               /* imaginary part of sine */
+               mpfr_mul (csh, c, sh, GMP_RNDN);
+               ok = (!mpfr_number_p (csh))
+                     || mpfr_can_round (csh, prec - 2, GMP_RNDN, GMP_RNDZ,
+                           MPC_PREC_IM (rop_sin)
+                           + (MPC_RND_IM (rnd_sin) == GMP_RNDN));
+            }
+         }
+
+         if (rop_cos != NULL && ok) {
+            /* real part of cosine */
+            mpfr_mul (c, c, ch, GMP_RNDN);
+            ok = (!mpfr_number_p (c))
+                  || mpfr_can_round (c, prec - 2, GMP_RNDN, GMP_RNDZ,
+                        MPC_PREC_RE (rop_cos)
+                        + (MPC_RND_RE (rnd_cos) == GMP_RNDN));
+
+            if (ok) {
+               /* imaginary part of cosine */
+               mpfr_mul (s, s, sh, GMP_RNDN);
+               mpfr_neg (s, s, GMP_RNDN);
+               ok = (!mpfr_number_p (s))
+                     || mpfr_can_round (s, prec - 2, GMP_RNDN, GMP_RNDZ,
+                           MPC_PREC_IM (rop_cos)
+                           + (MPC_RND_IM (rnd_cos) == GMP_RNDN));
+            }
+         }
+      } while (ok == 0);
+
+      if (rop_sin != NULL) {
+         inex_re = mpfr_set (mpc_realref (rop_sin), sch, MPC_RND_RE (rnd_sin));
+         if (mpfr_inf_p (sch))
+            inex_re = mpfr_sgn (sch);
+         inex_im = mpfr_set (mpc_imagref (rop_sin), csh, MPC_RND_IM (rnd_sin));
+         if (mpfr_inf_p (csh))
+            inex_im = mpfr_sgn (csh);
+         inex_sin = MPC_INEX (inex_re, inex_im);
+      }
+      else
+         inex_sin = MPC_INEX (0,0); /* return exact if not computed */
+
+      if (rop_cos != NULL) {
+         inex_re = mpfr_set (mpc_realref (rop_cos), c, MPC_RND_RE (rnd_cos));
+         if (mpfr_inf_p (c))
+            inex_re = mpfr_sgn (c);
+         inex_im = mpfr_set (mpc_imagref (rop_cos), s, MPC_RND_IM (rnd_cos));
+         if (mpfr_inf_p (s))
+            inex_im = mpfr_sgn (s);
+         inex_cos = MPC_INEX (inex_re, inex_im);
+      }
+      else
+         inex_cos = MPC_INEX (0,0); /* return exact if not computed */
+
+      mpfr_clear (s);
+      mpfr_clear (c);
+      mpfr_clear (sh);
+      mpfr_clear (ch);
+      mpfr_clear (sch);
+      mpfr_clear (csh);
+
+      return (MPC_INEX12 (inex_sin, inex_cos));
+   }
+}
diff --git a/contrib/mpc/src/sinh.c b/contrib/mpc/src/sinh.c
new file mode 100644 (file)
index 0000000..509cc57
--- /dev/null
@@ -0,0 +1,47 @@
+/* mpc_sinh -- hyperbolic sine of a complex number.
+
+Copyright (C)2008, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  /* sinh(op) = -i*sin(i*op) = conj(-i*sin(conj(-i*op))) */
+  mpc_t z;
+  mpc_t sin_z;
+  int inex;
+
+  /* z := conj(-i * op) and rop = conj(-i * sin(z)), in other words, we have
+     to switch real and imaginary parts. Let us set them without copying
+     significands. */
+  mpc_realref (z)[0] = mpc_imagref (op)[0];
+  mpc_imagref (z)[0] = mpc_realref (op)[0];
+  mpc_realref (sin_z)[0] = mpc_imagref (rop)[0];
+  mpc_imagref (sin_z)[0] = mpc_realref (rop)[0];
+
+  inex = mpc_sin (sin_z, z, MPC_RND (MPC_RND_IM (rnd), MPC_RND_RE (rnd)));
+
+  /* sin_z and rop parts share the same significands, copy the rest now. */
+  mpc_realref (rop)[0] = mpc_imagref (sin_z)[0];
+  mpc_imagref (rop)[0] = mpc_realref (sin_z)[0];
+
+  /* swap inexact flags for real and imaginary parts */
+  return MPC_INEX (MPC_INEX_IM (inex), MPC_INEX_RE (inex));
+}
diff --git a/contrib/mpc/src/sqr.c b/contrib/mpc/src/sqr.c
new file mode 100644 (file)
index 0000000..f1ce1ba
--- /dev/null
@@ -0,0 +1,324 @@
+/* mpc_sqr -- Square a complex number.
+
+Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+
+static int
+mpfr_fsss (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr c, mpfr_rnd_t rnd)
+{
+   /* Computes z = a^2 - c^2.
+      Assumes that a and c are finite and non-zero; so a squaring yielding
+      an infinity is an overflow, and a squaring yielding 0 is an underflow.
+      Assumes further that z is distinct from a and c. */
+
+   int inex;
+   mpfr_t u, v;
+
+   /* u=a^2, v=c^2 exactly */
+   mpfr_init2 (u, 2*mpfr_get_prec (a));
+   mpfr_init2 (v, 2*mpfr_get_prec (c));
+   mpfr_sqr (u, a, GMP_RNDN);
+   mpfr_sqr (v, c, GMP_RNDN);
+
+   /* tentatively compute z as u-v; here we need z to be distinct
+      from a and c to not lose the latter */
+   inex = mpfr_sub (z, u, v, rnd);
+
+   if (mpfr_inf_p (z)) {
+      /* replace by "correctly rounded overflow" */
+      mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), GMP_RNDN);
+      inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd);
+   }
+   else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) {
+      /* exactly u underflowed, determine inexact flag */
+      inex = (mpfr_signbit (u) ? 1 : -1);
+   }
+   else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) {
+      /* exactly v underflowed, determine inexact flag */
+      inex = (mpfr_signbit (v) ? -1 : 1);
+   }
+   else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) {
+      /* In the first case, u and v are +inf.
+         In the second case, u and v are zeroes; their difference may be 0
+         or the least representable number, with a sign to be determined.
+         Redo the computations with mpz_t exponents */
+      mpfr_exp_t ea, ec;
+      mpz_t eu, ev;
+         /* cheat to work around the const qualifiers */
+
+      /* Normalise the input by shifting and keep track of the shifts in
+         the exponents of u and v */
+      ea = mpfr_get_exp (a);
+      ec = mpfr_get_exp (c);
+
+      mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0);
+      mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0);
+
+      mpz_init (eu);
+      mpz_init (ev);
+      mpz_set_si (eu, (long int) ea);
+      mpz_mul_2exp (eu, eu, 1);
+      mpz_set_si (ev, (long int) ec);
+      mpz_mul_2exp (ev, ev, 1);
+
+      /* recompute u and v and move exponents to eu and ev */
+      mpfr_sqr (u, a, GMP_RNDN);
+      /* exponent of u is non-positive */
+      mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u)));
+      mpfr_set_exp (u, (mpfr_prec_t) 0);
+      mpfr_sqr (v, c, GMP_RNDN);
+      mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v)));
+      mpfr_set_exp (v, (mpfr_prec_t) 0);
+      if (mpfr_nan_p (z)) {
+         mpfr_exp_t emax = mpfr_get_emax ();
+         int overflow;
+         /* We have a = ma * 2^ea with 1/2 <= |ma| < 1 and ea <= emax.
+            So eu <= 2*emax, and eu > emax since we have
+            an overflow. The same holds for ev. Shift u and v by as much as
+            possible so that one of them has exponent emax and the
+            remaining exponents in eu and ev are the same. Then carry out
+            the addition. Shifting u and v prevents an underflow. */
+         if (mpz_cmp (eu, ev) >= 0) {
+            mpfr_set_exp (u, emax);
+            mpz_sub_ui (eu, eu, (long int) emax);
+            mpz_sub (ev, ev, eu);
+            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev));
+               /* remaining common exponent is now in eu */
+         }
+         else {
+            mpfr_set_exp (v, emax);
+            mpz_sub_ui (ev, ev, (long int) emax);
+            mpz_sub (eu, eu, ev);
+            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu));
+            mpz_set (eu, ev);
+               /* remaining common exponent is now also in eu */
+         }
+         inex = mpfr_sub (z, u, v, rnd);
+            /* Result is finite since u and v have the same sign. */
+         overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd);
+         if (overflow)
+            inex = overflow;
+      }
+      else {
+         int underflow;
+         /* Subtraction of two zeroes. We have a = ma * 2^ea
+            with 1/2 <= |ma| < 1 and ea >= emin and similarly for b.
+            So 2*emin < 2*emin+1 <= eu < emin < 0, and analogously for v. */
+         mpfr_exp_t emin = mpfr_get_emin ();
+         if (mpz_cmp (eu, ev) <= 0) {
+            mpfr_set_exp (u, emin);
+            mpz_add_ui (eu, eu, (unsigned long int) (-emin));
+            mpz_sub (ev, ev, eu);
+            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev));
+         }
+         else {
+            mpfr_set_exp (v, emin);
+            mpz_add_ui (ev, ev, (unsigned long int) (-emin));
+            mpz_sub (eu, eu, ev);
+            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu));
+            mpz_set (eu, ev);
+         }
+         inex = mpfr_sub (z, u, v, rnd);
+         mpz_neg (eu, eu);
+         underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd);
+         if (underflow)
+            inex = underflow;
+      }
+
+      mpz_clear (eu);
+      mpz_clear (ev);
+
+      mpfr_set_exp ((mpfr_ptr) a, ea);
+      mpfr_set_exp ((mpfr_ptr) c, ec);
+         /* works also when a == c */
+   }
+
+   mpfr_clear (u);
+   mpfr_clear (v);
+
+   return inex;
+}
+
+
+int
+mpc_sqr (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+   int ok;
+   mpfr_t u, v;
+   mpfr_t x;
+      /* temporary variable to hold the real part of op,
+         needed in the case rop==op */
+   mpfr_prec_t prec;
+   int inex_re, inex_im, inexact;
+   mpfr_exp_t emin;
+   int saved_underflow;
+
+   /* special values: NaN and infinities */
+   if (!mpc_fin_p (op)) {
+      if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op))) {
+         mpfr_set_nan (mpc_realref (rop));
+         mpfr_set_nan (mpc_imagref (rop));
+      }
+      else if (mpfr_inf_p (mpc_realref (op))) {
+         if (mpfr_inf_p (mpc_imagref (op))) {
+            mpfr_set_inf (mpc_imagref (rop),
+                          MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+            mpfr_set_nan (mpc_realref (rop));
+         }
+         else {
+            if (mpfr_zero_p (mpc_imagref (op)))
+               mpfr_set_nan (mpc_imagref (rop));
+            else
+               mpfr_set_inf (mpc_imagref (rop),
+                             MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+            mpfr_set_inf (mpc_realref (rop), +1);
+         }
+      }
+      else /* IM(op) is infinity, RE(op) is not */ {
+         if (mpfr_zero_p (mpc_realref (op)))
+            mpfr_set_nan (mpc_imagref (rop));
+         else
+            mpfr_set_inf (mpc_imagref (rop),
+                          MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+         mpfr_set_inf (mpc_realref (rop), -1);
+      }
+      return MPC_INEX (0, 0); /* exact */
+   }
+
+   prec = MPC_MAX_PREC(rop);
+
+   /* Check for real resp. purely imaginary number */
+   if (mpfr_zero_p (mpc_imagref(op))) {
+      int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op));
+      inex_re = mpfr_sqr (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd));
+      inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN);
+      if (!same_sign)
+        mpc_conj (rop, rop, MPC_RNDNN);
+      return MPC_INEX(inex_re, inex_im);
+   }
+   if (mpfr_zero_p (mpc_realref(op))) {
+      int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op));
+      inex_re = -mpfr_sqr (mpc_realref(rop), mpc_imagref(op), INV_RND (MPC_RND_RE(rnd)));
+      mpfr_neg (mpc_realref(rop), mpc_realref(rop), GMP_RNDN);
+      inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN);
+      if (!same_sign)
+        mpc_conj (rop, rop, MPC_RNDNN);
+      return MPC_INEX(inex_re, inex_im);
+   }
+
+   if (rop == op)
+   {
+      mpfr_init2 (x, MPC_PREC_RE (op));
+      mpfr_set (x, op->re, GMP_RNDN);
+   }
+   else
+      x [0] = op->re [0];
+   /* From here on, use x instead of op->re and safely overwrite rop->re. */
+
+   /* Compute real part of result. */
+   if (SAFE_ABS (mpfr_exp_t,
+                 mpfr_get_exp (mpc_realref (op)) - mpfr_get_exp (mpc_imagref (op)))
+       > (mpfr_exp_t) MPC_MAX_PREC (op) / 2) {
+      /* If the real and imaginary parts of the argument have very different
+         exponents, it is not reasonable to use Karatsuba squaring; compute
+         exactly with the standard formulae instead, even if this means an
+         additional multiplication. Using the approach copied from mul, over-
+         and underflows are also handled correctly. */
+
+      inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd));
+   }
+   else {
+      /* Karatsuba squaring: we compute the real part as (x+y)*(x-y) and the
+         imaginary part as 2*x*y, with a total of 2M instead of 2S+1M for the
+         naive algorithm, which computes x^2-y^2 and 2*y*y */
+      mpfr_init (u);
+      mpfr_init (v);
+
+      emin = mpfr_get_emin ();
+
+      do
+      {
+         prec += mpc_ceil_log2 (prec) + 5;
+
+         mpfr_set_prec (u, prec);
+         mpfr_set_prec (v, prec);
+
+         /* Let op = x + iy. We need u = x+y and v = x-y, rounded away.      */
+         /* The error is bounded above by 1 ulp.                             */
+         /* We first let inexact be 1 if the real part is not computed       */
+         /* exactly and determine the sign later.                            */
+         inexact =  ROUND_AWAY (mpfr_add (u, x, mpc_imagref (op), MPFR_RNDA), u)
+                  | ROUND_AWAY (mpfr_sub (v, x, mpc_imagref (op), MPFR_RNDA), v);
+
+         /* compute the real part as u*v, rounded away                    */
+         /* determine also the sign of inex_re                            */
+
+         if (mpfr_sgn (u) == 0 || mpfr_sgn (v) == 0) {
+            /* as we have rounded away, the result is exact */
+            mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+            inex_re = 0;
+            ok = 1;
+         }
+         else {
+            mpfr_rnd_t rnd_away;
+               /* FIXME: can be replaced by MPFR_RNDA in mpfr >= 3 */
+            rnd_away = (mpfr_sgn (u) * mpfr_sgn (v) > 0 ? GMP_RNDU : GMP_RNDD);
+            inexact |= ROUND_AWAY (mpfr_mul (u, u, v, MPFR_RNDA), u); /* error 5 */
+            if (mpfr_get_exp (u) == emin || mpfr_inf_p (u)) {
+               /* under- or overflow */
+               inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd));
+               ok = 1;
+            }
+            else {
+               ok = (!inexact) | mpfr_can_round (u, prec - 3,
+                     rnd_away, GMP_RNDZ,
+                     MPC_PREC_RE (rop) + (MPC_RND_RE (rnd) == GMP_RNDN));
+               if (ok) {
+                  inex_re = mpfr_set (mpc_realref (rop), u, MPC_RND_RE (rnd));
+                  if (inex_re == 0)
+                     /* remember that u was already rounded */
+                     inex_re = inexact;
+               }
+            }
+         }
+      }
+      while (!ok);
+
+      mpfr_clear (u);
+      mpfr_clear (v);
+   }
+
+   saved_underflow = mpfr_underflow_p ();
+   mpfr_clear_underflow ();
+   inex_im = mpfr_mul (rop->im, x, op->im, MPC_RND_IM (rnd));
+   if (!mpfr_underflow_p ())
+      inex_im |= mpfr_mul_2ui (rop->im, rop->im, 1, MPC_RND_IM (rnd));
+      /* We must not multiply by 2 if rop->im has been set to the smallest
+         representable number. */
+   if (saved_underflow)
+      mpfr_set_underflow ();
+
+   if (rop == op)
+      mpfr_clear (x);
+
+   return MPC_INEX (inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/sqrt.c b/contrib/mpc/src/sqrt.c
new file mode 100644 (file)
index 0000000..dd2ff60
--- /dev/null
@@ -0,0 +1,364 @@
+/* mpc_sqrt -- Take the square root of a complex number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+#if MPFR_VERSION_MAJOR < 3
+#define mpfr_min_prec(x) \
+   ( ((prec + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) * BITS_PER_MP_LIMB \
+     - mpn_scan1 (x->_mpfr_d, 0))
+#endif
+
+
+int
+mpc_sqrt (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+  int ok_w, ok_t = 0;
+  mpfr_t    w, t;
+  mpfr_rnd_t  rnd_w, rnd_t;
+  mpfr_prec_t prec_w, prec_t;
+  /* the rounding mode and the precision required for w and t, which can */
+  /* be either the real or the imaginary part of a */
+  mpfr_prec_t prec;
+  int inex_w, inex_t = 1, inex_re, inex_im, loops = 0;
+  const int re_cmp = mpfr_cmp_ui (mpc_realref (b), 0),
+            im_cmp = mpfr_cmp_ui (mpc_imagref (b), 0);
+     /* comparison of the real/imaginary part of b with 0 */
+  int repr_w, repr_t = 0 /* to avoid gcc warning */ ;
+     /* flag indicating whether the computed value is already representable
+        at the target precision */
+  const int im_sgn = mpfr_signbit (mpc_imagref (b)) == 0 ? 0 : -1;
+     /* we need to know the sign of Im(b) when it is +/-0 */
+  const mpfr_rnd_t r = im_sgn ? GMP_RNDD : GMP_RNDU;
+     /* rounding mode used when computing t */
+
+  /* special values */
+  if (!mpc_fin_p (b)) {
+   /* sqrt(x +i*Inf) = +Inf +I*Inf, even if x = NaN */
+   /* sqrt(x -i*Inf) = +Inf -I*Inf, even if x = NaN */
+   if (mpfr_inf_p (mpc_imagref (b)))
+      {
+         mpfr_set_inf (mpc_realref (a), +1);
+         mpfr_set_inf (mpc_imagref (a), im_sgn);
+         return MPC_INEX (0, 0);
+      }
+
+   if (mpfr_inf_p (mpc_realref (b)))
+      {
+         if (mpfr_signbit (mpc_realref (b)))
+         {
+            if (mpfr_number_p (mpc_imagref (b)))
+               {
+               /* sqrt(-Inf +i*y) = +0 +i*Inf, when y positive */
+               /* sqrt(-Inf +i*y) = +0 -i*Inf, when y positive */
+               mpfr_set_ui (mpc_realref (a), 0, GMP_RNDN);
+               mpfr_set_inf (mpc_imagref (a), im_sgn);
+               return MPC_INEX (0, 0);
+               }
+            else
+               {
+               /* sqrt(-Inf +i*NaN) = NaN +/-i*Inf */
+               mpfr_set_nan (mpc_realref (a));
+               mpfr_set_inf (mpc_imagref (a), im_sgn);
+               return MPC_INEX (0, 0);
+               }
+         }
+         else
+         {
+            if (mpfr_number_p (mpc_imagref (b)))
+               {
+               /* sqrt(+Inf +i*y) = +Inf +i*0, when y positive */
+               /* sqrt(+Inf +i*y) = +Inf -i*0, when y positive */
+               mpfr_set_inf (mpc_realref (a), +1);
+               mpfr_set_ui (mpc_imagref (a), 0, GMP_RNDN);
+               if (im_sgn)
+                  mpc_conj (a, a, MPC_RNDNN);
+               return MPC_INEX (0, 0);
+               }
+            else
+               {
+               /* sqrt(+Inf -i*Inf) = +Inf -i*Inf */
+               /* sqrt(+Inf +i*Inf) = +Inf +i*Inf */
+               /* sqrt(+Inf +i*NaN) = +Inf +i*NaN */
+               return mpc_set (a, b, rnd);
+               }
+         }
+      }
+
+   /* sqrt(x +i*NaN) = NaN +i*NaN, if x is not infinite */
+   /* sqrt(NaN +i*y) = NaN +i*NaN, if y is not infinite */
+   if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b)))
+      {
+         mpfr_set_nan (mpc_realref (a));
+         mpfr_set_nan (mpc_imagref (a));
+         return MPC_INEX (0, 0);
+      }
+  }
+
+  /* purely real */
+  if (im_cmp == 0)
+    {
+      if (re_cmp == 0)
+        {
+          mpc_set_ui_ui (a, 0, 0, MPC_RNDNN);
+          if (im_sgn)
+            mpc_conj (a, a, MPC_RNDNN);
+          return MPC_INEX (0, 0);
+        }
+      else if (re_cmp > 0)
+        {
+          inex_w = mpfr_sqrt (mpc_realref (a), mpc_realref (b), MPC_RND_RE (rnd));
+          mpfr_set_ui (mpc_imagref (a), 0, GMP_RNDN);
+          if (im_sgn)
+            mpc_conj (a, a, MPC_RNDNN);
+          return MPC_INEX (inex_w, 0);
+        }
+      else
+        {
+          mpfr_init2 (w, MPC_PREC_RE (b));
+          mpfr_neg (w, mpc_realref (b), GMP_RNDN);
+          if (im_sgn)
+            {
+              inex_w = -mpfr_sqrt (mpc_imagref (a), w, INV_RND (MPC_RND_IM (rnd)));
+              mpfr_neg (mpc_imagref (a), mpc_imagref (a), GMP_RNDN);
+            }
+          else
+            inex_w = mpfr_sqrt (mpc_imagref (a), w, MPC_RND_IM (rnd));
+
+          mpfr_set_ui (mpc_realref (a), 0, GMP_RNDN);
+          mpfr_clear (w);
+          return MPC_INEX (0, inex_w);
+        }
+    }
+
+  /* purely imaginary */
+  if (re_cmp == 0)
+    {
+      mpfr_t y;
+
+      y[0] = mpc_imagref (b)[0];
+      /* If y/2 underflows, so does sqrt(y/2) */
+      mpfr_div_2ui (y, y, 1, GMP_RNDN);
+      if (im_cmp > 0)
+        {
+          inex_w = mpfr_sqrt (mpc_realref (a), y, MPC_RND_RE (rnd));
+          inex_t = mpfr_sqrt (mpc_imagref (a), y, MPC_RND_IM (rnd));
+        }
+      else
+        {
+          mpfr_neg (y, y, GMP_RNDN);
+          inex_w = mpfr_sqrt (mpc_realref (a), y, MPC_RND_RE (rnd));
+          inex_t = -mpfr_sqrt (mpc_imagref (a), y, INV_RND (MPC_RND_IM (rnd)));
+          mpfr_neg (mpc_imagref (a), mpc_imagref (a), GMP_RNDN);
+        }
+      return MPC_INEX (inex_w, inex_t);
+    }
+
+  prec = MPC_MAX_PREC(a);
+
+  mpfr_init (w);
+  mpfr_init (t);
+
+   if (re_cmp > 0) {
+      rnd_w = MPC_RND_RE (rnd);
+      prec_w = MPC_PREC_RE (a);
+      rnd_t = MPC_RND_IM(rnd);
+      if (rnd_t == GMP_RNDZ)
+         /* force GMP_RNDD or GMP_RNDUP, using sign(t) = sign(y) */
+         rnd_t = (im_cmp > 0 ? GMP_RNDD : GMP_RNDU);
+      prec_t = MPC_PREC_IM (a);
+   }
+   else {
+      prec_w = MPC_PREC_IM (a);
+      prec_t = MPC_PREC_RE (a);
+      if (im_cmp > 0) {
+         rnd_w = MPC_RND_IM(rnd);
+         rnd_t = MPC_RND_RE(rnd);
+         if (rnd_t == GMP_RNDZ)
+            rnd_t = GMP_RNDD;
+      }
+      else {
+         rnd_w = INV_RND(MPC_RND_IM (rnd));
+         rnd_t = INV_RND(MPC_RND_RE (rnd));
+         if (rnd_t == GMP_RNDZ)
+            rnd_t = GMP_RNDU;
+      }
+   }
+
+  do
+    {
+      loops ++;
+      prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
+      mpfr_set_prec (w, prec);
+      mpfr_set_prec (t, prec);
+      /* let b = x + iy */
+      /* w = sqrt ((|x| + sqrt (x^2 + y^2)) / 2), rounded down */
+      /* total error bounded by 3 ulps */
+      inex_w = mpc_abs (w, b, GMP_RNDD);
+      if (re_cmp < 0)
+        inex_w |= mpfr_sub (w, w, mpc_realref (b), GMP_RNDD);
+      else
+        inex_w |= mpfr_add (w, w, mpc_realref (b), GMP_RNDD);
+      inex_w |= mpfr_div_2ui (w, w, 1, GMP_RNDD);
+      inex_w |= mpfr_sqrt (w, w, GMP_RNDD);
+
+      repr_w = mpfr_min_prec (w) <= prec_w;
+      if (!repr_w)
+         /* use the usual trick for obtaining the ternary value */
+         ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDU,
+                                prec_w + (rnd_w == GMP_RNDN));
+      else {
+            /* w is representable in the target precision and thus cannot be
+               rounded up */
+         if (rnd_w == GMP_RNDN)
+            /* If w can be rounded to nearest, then actually no rounding
+               occurs, and the ternary value is known from inex_w. */
+            ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDN, prec_w);
+         else
+            /* If w can be rounded down, then any direct rounding and the
+               ternary flag can be determined from inex_w. */
+            ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDD, prec_w);
+      }
+
+      if (!inex_w || ok_w) {
+         /* t = y / 2w, rounded away */
+         /* total error bounded by 7 ulps */
+         inex_t = mpfr_div (t, mpc_imagref (b), w, r);
+         if (!inex_t && inex_w)
+            /* The division was exact, but w was not. */
+            inex_t = im_sgn ? -1 : 1;
+         inex_t |= mpfr_div_2ui (t, t, 1, r);
+         repr_t = mpfr_min_prec (t) <= prec_t;
+         if (!repr_t)
+             /* As for w; since t was rounded away, we check whether rounding to 0
+                is possible. */
+            ok_t = mpfr_can_round (t, prec - 3, r, GMP_RNDZ,
+                                   prec_t + (rnd_t == GMP_RNDN));
+         else {
+            if (rnd_t == GMP_RNDN)
+               ok_t = mpfr_can_round (t, prec - 3, r, GMP_RNDN, prec_t);
+            else
+               ok_t = mpfr_can_round (t, prec - 3, r, r, prec_t);
+         }
+      }
+    }
+    while ((inex_w && !ok_w) || (inex_t && !ok_t));
+
+   if (re_cmp > 0) {
+         inex_re = mpfr_set (mpc_realref (a), w, MPC_RND_RE(rnd));
+         inex_im = mpfr_set (mpc_imagref (a), t, MPC_RND_IM(rnd));
+   }
+   else if (im_cmp > 0) {
+      inex_re = mpfr_set (mpc_realref(a), t, MPC_RND_RE(rnd));
+      inex_im = mpfr_set (mpc_imagref(a), w, MPC_RND_IM(rnd));
+   }
+   else {
+      inex_re = mpfr_neg (mpc_realref (a), t, MPC_RND_RE(rnd));
+      inex_im = mpfr_neg (mpc_imagref (a), w, MPC_RND_IM(rnd));
+   }
+
+   if (repr_w && inex_w) {
+      if (rnd_w == GMP_RNDN) {
+         /* w has not been rounded with mpfr_set/mpfr_neg, determine ternary
+            value from inex_w instead */
+         if (re_cmp > 0)
+            inex_re = inex_w;
+         else if (im_cmp > 0)
+            inex_im = inex_w;
+         else
+            inex_im = -inex_w;
+      }
+      else {
+         /* determine ternary value, but also potentially add 1 ulp; can only
+            be done now when we are in the target precision */
+         if (re_cmp > 0) {
+            if (rnd_w == GMP_RNDU) {
+               MPFR_ADD_ONE_ULP (mpc_realref (a));
+               inex_re = +1;
+            }
+            else
+               inex_re = -1;
+         }
+         else if (im_cmp > 0) {
+            if (rnd_w == GMP_RNDU) {
+               MPFR_ADD_ONE_ULP (mpc_imagref (a));
+               inex_im = +1;
+            }
+            else
+               inex_im = -1;
+         }
+         else {
+            if (rnd_w == GMP_RNDU) {
+               MPFR_ADD_ONE_ULP (mpc_imagref (a));
+               inex_im = -1;
+            }
+            else
+               inex_im = +1;
+         }
+      }
+   }
+   if (repr_t && inex_t) {
+      if (rnd_t == GMP_RNDN) {
+         if (re_cmp > 0)
+            inex_im = inex_t;
+         else if (im_cmp > 0)
+            inex_re = inex_t;
+         else
+            inex_re = -inex_t;
+      }
+      else {
+         if (re_cmp > 0) {
+            if (rnd_t == r)
+               inex_im = inex_t;
+            else {
+               inex_im = -inex_t;
+               /* im_cmp > 0 implies that Im(b) > 0, thus im_sgn = 0
+                  and r = GMP_RNDU.
+                  im_cmp < 0 implies that Im(b) < 0, thus im_sgn = -1
+                  and r = GMP_RNDD. */
+               MPFR_SUB_ONE_ULP (mpc_imagref (a));
+            }
+         }
+         else if (im_cmp > 0) {
+            if (rnd_t == r)
+               inex_re = inex_t;
+            else {
+               inex_re = -inex_t;
+               /* im_cmp > 0 implies r = GMP_RNDU (see above) */
+               MPFR_SUB_ONE_ULP (mpc_realref (a));
+            }
+         }
+         else { /* im_cmp < 0 */
+            if (rnd_t == r)
+               inex_re = -inex_t;
+            else {
+               inex_re = inex_t;
+               /* im_cmp < 0 implies r = GMP_RNDD (see above) */
+               MPFR_SUB_ONE_ULP (mpc_realref (a));
+            }
+         }
+      }
+   }
+
+  mpfr_clear (w);
+  mpfr_clear (t);
+
+  return MPC_INEX (inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/strtoc.c b/contrib/mpc/src/strtoc.c
new file mode 100644 (file)
index 0000000..b96ccee
--- /dev/null
@@ -0,0 +1,89 @@
+/* mpc_strtoc -- Read a complex number from a string.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "mpc-impl.h"
+
+static void
+skip_whitespace (const char **p)
+{
+   /* TODO: This function had better be inlined, but it is unclear whether
+      the hassle to get this implemented across all platforms is worth it. */
+   while (isspace ((unsigned char) **p))
+      (*p)++;
+}
+
+int
+mpc_strtoc (mpc_ptr rop, const char *nptr, char **endptr, int base, mpc_rnd_t rnd)
+{
+   const char *p;
+   char *end;
+   int bracketed = 0;
+
+   int inex_re = 0, inex_im = 0;
+
+   if (nptr == NULL || base > 36 || base == 1)
+     goto error;
+
+   p = nptr;
+   skip_whitespace (&p);
+
+   if (*p == '('){
+      bracketed = 1;
+      ++p;
+   }
+
+   inex_re = mpfr_strtofr (mpc_realref(rop), p, &end, base, MPC_RND_RE (rnd));
+   if (end == p)
+      goto error;
+   p = end;
+
+   if (!bracketed)
+     inex_im = mpfr_set_ui (mpc_imagref (rop), 0ul, GMP_RNDN);
+   else {
+     if (!isspace ((unsigned char)*p))
+         goto error;
+
+      skip_whitespace (&p);
+
+      inex_im = mpfr_strtofr (mpc_imagref(rop), p, &end, base, MPC_RND_IM (rnd));
+      if (end == p)
+         goto error;
+      p = end;
+
+      skip_whitespace (&p);
+      if (*p != ')')
+         goto error;
+
+      p++;
+   }
+
+   if (endptr != NULL)
+     *endptr = (char*) p;
+   return MPC_INEX (inex_re, inex_im);
+
+error:
+   if (endptr != NULL)
+     *endptr = (char*) nptr;
+   mpfr_set_nan (mpc_realref (rop));
+   mpfr_set_nan (mpc_imagref (rop));
+   return -1;
+}
diff --git a/contrib/mpc/src/sub.c b/contrib/mpc/src/sub.c
new file mode 100644 (file)
index 0000000..8b8a97d
--- /dev/null
@@ -0,0 +1,32 @@
+/* mpc_sub -- Subtract two complex numbers.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sub (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_sub (mpc_realref(a), mpc_realref(b), mpc_realref(c), MPC_RND_RE(rnd));
+  inex_im = mpfr_sub (mpc_imagref(a), mpc_imagref(b), mpc_imagref(c), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/sub_fr.c b/contrib/mpc/src/sub_fr.c
new file mode 100644 (file)
index 0000000..ade33a9
--- /dev/null
@@ -0,0 +1,34 @@
+/* mpc_sub_fr -- Substract a floating-point number to the real part of a
+   complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_sub_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_sub (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/sub_ui.c b/contrib/mpc/src/sub_ui.c
new file mode 100644 (file)
index 0000000..561c469
--- /dev/null
@@ -0,0 +1,33 @@
+/* mpc_sub_ui -- Add a complex number and an unsigned long int.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_sub_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+  int inex_re, inex_im;
+
+  inex_re = mpfr_sub_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+  inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+  return MPC_INEX(inex_re, inex_im);
+}
diff --git a/contrib/mpc/src/swap.c b/contrib/mpc/src/swap.c
new file mode 100644 (file)
index 0000000..9590132
--- /dev/null
@@ -0,0 +1,29 @@
+/* mpc_swap -- Swap two complex numbers.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_swap (mpc_ptr a, mpc_ptr b)
+{
+  /* assumes real and imaginary parts do not overlap */
+  mpfr_swap (mpc_realref(a), mpc_realref(b));
+  mpfr_swap (mpc_imagref(a), mpc_imagref(b));
+}
diff --git a/contrib/mpc/src/tan.c b/contrib/mpc/src/tan.c
new file mode 100644 (file)
index 0000000..24cd92b
--- /dev/null
@@ -0,0 +1,284 @@
+/* mpc_tan -- tangent of a complex number.
+
+Copyright (C) 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>    /* for MPC_ASSERT */
+#include <limits.h>
+#include "mpc-impl.h"
+
+int
+mpc_tan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+  mpc_t x, y;
+  mpfr_prec_t prec;
+  mpfr_exp_t err;
+  int ok = 0;
+  int inex;
+
+  /* special values */
+  if (!mpc_fin_p (op))
+    {
+      if (mpfr_nan_p (mpc_realref (op)))
+        {
+          if (mpfr_inf_p (mpc_imagref (op)))
+            /* tan(NaN -i*Inf) = +/-0 -i */
+            /* tan(NaN +i*Inf) = +/-0 +i */
+            {
+              /* exact unless 1 is not in exponent range */
+              inex = mpc_set_si_si (rop, 0,
+                                    (MPFR_SIGN (mpc_imagref (op)) < 0) ? -1 : +1,
+                                    rnd);
+            }
+          else
+            /* tan(NaN +i*y) = NaN +i*NaN, when y is finite */
+            /* tan(NaN +i*NaN) = NaN +i*NaN */
+            {
+              mpfr_set_nan (mpc_realref (rop));
+              mpfr_set_nan (mpc_imagref (rop));
+              inex = MPC_INEX (0, 0); /* always exact */
+            }
+        }
+      else if (mpfr_nan_p (mpc_imagref (op)))
+        {
+          if (mpfr_cmp_ui (mpc_realref (op), 0) == 0)
+            /* tan(-0 +i*NaN) = -0 +i*NaN */
+            /* tan(+0 +i*NaN) = +0 +i*NaN */
+            {
+              mpc_set (rop, op, rnd);
+              inex = MPC_INEX (0, 0); /* always exact */
+            }
+          else
+            /* tan(x +i*NaN) = NaN +i*NaN, when x != 0 */
+            {
+              mpfr_set_nan (mpc_realref (rop));
+              mpfr_set_nan (mpc_imagref (rop));
+              inex = MPC_INEX (0, 0); /* always exact */
+            }
+        }
+      else if (mpfr_inf_p (mpc_realref (op)))
+        {
+          if (mpfr_inf_p (mpc_imagref (op)))
+            /* tan(-Inf -i*Inf) = -/+0 -i */
+            /* tan(-Inf +i*Inf) = -/+0 +i */
+            /* tan(+Inf -i*Inf) = +/-0 -i */
+            /* tan(+Inf +i*Inf) = +/-0 +i */
+            {
+              const int sign_re = mpfr_signbit (mpc_realref (op));
+              int inex_im;
+
+              mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+              mpfr_setsign (mpc_realref (rop), mpc_realref (rop), sign_re, GMP_RNDN);
+
+              /* exact, unless 1 is not in exponent range */
+              inex_im = mpfr_set_si (mpc_imagref (rop),
+                                     mpfr_signbit (mpc_imagref (op)) ? -1 : +1,
+                                     MPC_RND_IM (rnd));
+              inex = MPC_INEX (0, inex_im);
+            }
+          else
+            /* tan(-Inf +i*y) = tan(+Inf +i*y) = NaN +i*NaN, when y is
+               finite */
+            {
+              mpfr_set_nan (mpc_realref (rop));
+              mpfr_set_nan (mpc_imagref (rop));
+              inex = MPC_INEX (0, 0); /* always exact */
+            }
+        }
+      else
+        /* tan(x -i*Inf) = +0*sin(x)*cos(x) -i, when x is finite */
+        /* tan(x +i*Inf) = +0*sin(x)*cos(x) +i, when x is finite */
+        {
+          mpfr_t c;
+          mpfr_t s;
+          int inex_im;
+
+          mpfr_init (c);
+          mpfr_init (s);
+
+          mpfr_sin_cos (s, c, mpc_realref (op), GMP_RNDN);
+          mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+          mpfr_setsign (mpc_realref (rop), mpc_realref (rop),
+                        mpfr_signbit (c) != mpfr_signbit (s), GMP_RNDN);
+          /* exact, unless 1 is not in exponent range */
+          inex_im = mpfr_set_si (mpc_imagref (rop),
+                                 (mpfr_signbit (mpc_imagref (op)) ? -1 : +1),
+                                 MPC_RND_IM (rnd));
+          inex = MPC_INEX (0, inex_im);
+
+          mpfr_clear (s);
+          mpfr_clear (c);
+        }
+
+      return inex;
+    }
+
+  if (mpfr_zero_p (mpc_realref (op)))
+    /* tan(-0 -i*y) = -0 +i*tanh(y), when y is finite. */
+    /* tan(+0 +i*y) = +0 +i*tanh(y), when y is finite. */
+    {
+      int inex_im;
+
+      mpfr_set (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+      inex_im = mpfr_tanh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+      return MPC_INEX (0, inex_im);
+    }
+
+  if (mpfr_zero_p (mpc_imagref (op)))
+    /* tan(x -i*0) = tan(x) -i*0, when x is finite. */
+    /* tan(x +i*0) = tan(x) +i*0, when x is finite. */
+    {
+      int inex_re;
+
+      inex_re = mpfr_tan (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+      mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+      return MPC_INEX (inex_re, 0);
+    }
+
+  /* ordinary (non-zero) numbers */
+
+  /* tan(op) = sin(op) / cos(op).
+
+     We use the following algorithm with rounding away from 0 for all
+     operations, and working precision w:
+
+     (1) x = A(sin(op))
+     (2) y = A(cos(op))
+     (3) z = A(x/y)
+
+     the error on Im(z) is at most 81 ulp,
+     the error on Re(z) is at most
+     7 ulp if k < 2,
+     8 ulp if k = 2,
+     else 5+k ulp, where
+     k = Exp(Re(x))+Exp(Re(y))-2min{Exp(Re(y)), Exp(Im(y))}-Exp(Re(x/y))
+     see proof in algorithms.tex.
+  */
+
+  prec = MPC_MAX_PREC(rop);
+
+  mpc_init2 (x, 2);
+  mpc_init2 (y, 2);
+
+  err = 7;
+
+  do
+    {
+      mpfr_exp_t k, exr, eyr, eyi, ezr;
+
+      ok = 0;
+
+      /* FIXME: prevent addition overflow */
+      prec += mpc_ceil_log2 (prec) + err;
+      mpc_set_prec (x, prec);
+      mpc_set_prec (y, prec);
+
+      /* rounding away from zero: except in the cases x=0 or y=0 (processed
+         above), sin x and cos y are never exact, so rounding away from 0 is
+         rounding towards 0 and adding one ulp to the absolute value */
+      mpc_sin_cos (x, y, op, MPC_RNDZZ, MPC_RNDZZ);
+      MPFR_ADD_ONE_ULP (mpc_realref (x));
+      MPFR_ADD_ONE_ULP (mpc_imagref (x));
+      MPFR_ADD_ONE_ULP (mpc_realref (y));
+      MPFR_ADD_ONE_ULP (mpc_imagref (y));
+      MPC_ASSERT (mpfr_z