Blame src/mul.c

Packit Service 2e9770
/* mpc_mul -- Multiply two complex numbers
Packit Service 2e9770
Packit Service 2e9770
Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012, 2016 INRIA
Packit Service 2e9770
Packit Service 2e9770
This file is part of GNU MPC.
Packit Service 2e9770
Packit Service 2e9770
GNU MPC is free software; you can redistribute it and/or modify it under
Packit Service 2e9770
the terms of the GNU Lesser General Public License as published by the
Packit Service 2e9770
Free Software Foundation; either version 3 of the License, or (at your
Packit Service 2e9770
option) any later version.
Packit Service 2e9770
Packit Service 2e9770
GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
Packit Service 2e9770
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
Packit Service 2e9770
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
Packit Service 2e9770
more details.
Packit Service 2e9770
Packit Service 2e9770
You should have received a copy of the GNU Lesser General Public License
Packit Service 2e9770
along with this program. If not, see http://www.gnu.org/licenses/ .
Packit Service 2e9770
*/
Packit Service 2e9770
Packit Service 2e9770
#include <stdio.h>    /* for MPC_ASSERT */
Packit Service 2e9770
#include "mpc-impl.h"
Packit Service 2e9770
Packit Service 2e9770
#define mpz_add_si(z,x,y) do { \
Packit Service 2e9770
   if (y >= 0) \
Packit Service 2e9770
      mpz_add_ui (z, x, (long int) y); \
Packit Service 2e9770
   else \
Packit Service 2e9770
      mpz_sub_ui (z, x, (long int) (-y)); \
Packit Service 2e9770
   } while (0);
Packit Service 2e9770
Packit Service 2e9770
/* compute z=x*y when x has an infinite part */
Packit Service 2e9770
static int
Packit Service 2e9770
mul_infinite (mpc_ptr z, mpc_srcptr x, mpc_srcptr y)
Packit Service 2e9770
{
Packit Service 2e9770
   /* Let x=xr+i*xi and y=yr+i*yi; extract the signs of the operands */
Packit Service 2e9770
   int xrs = mpfr_signbit (mpc_realref (x)) ? -1 : 1;
Packit Service 2e9770
   int xis = mpfr_signbit (mpc_imagref (x)) ? -1 : 1;
Packit Service 2e9770
   int yrs = mpfr_signbit (mpc_realref (y)) ? -1 : 1;
Packit Service 2e9770
   int yis = mpfr_signbit (mpc_imagref (y)) ? -1 : 1;
Packit Service 2e9770
Packit Service 2e9770
   int u, v;
Packit Service 2e9770
Packit Service 2e9770
   /* compute the sign of
Packit Service 2e9770
      u = xrs * yrs * xr * yr - xis * yis * xi * yi
Packit Service 2e9770
      v = xrs * yis * xr * yi + xis * yrs * xi * yr
Packit Service 2e9770
      +1 if positive, -1 if negative, 0 if NaN */
Packit Service 2e9770
   if (  mpfr_nan_p (mpc_realref (x)) || mpfr_nan_p (mpc_imagref (x))
Packit Service 2e9770
      || mpfr_nan_p (mpc_realref (y)) || mpfr_nan_p (mpc_imagref (y))) {
Packit Service 2e9770
      u = 0;
Packit Service 2e9770
      v = 0;
Packit Service 2e9770
   }
Packit Service 2e9770
   else if (mpfr_inf_p (mpc_realref (x))) {
Packit Service 2e9770
      /* x = (+/-inf) xr + i*xi */
Packit Service 2e9770
      u = (   mpfr_zero_p (mpc_realref (y))
Packit Service 2e9770
           || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_imagref (y)))
Packit Service 2e9770
           || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_imagref (y)))
Packit Service 2e9770
           || (   (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (y)))
Packit Service 2e9770
              && xrs*yrs == xis*yis)
Packit Service 2e9770
           ? 0 : xrs * yrs);
Packit Service 2e9770
      v = (   mpfr_zero_p (mpc_imagref (y))
Packit Service 2e9770
           || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_realref (y)))
Packit Service 2e9770
           || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_realref (y)))
Packit Service 2e9770
           || (   (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (x)))
Packit Service 2e9770
               && xrs*yis != xis*yrs)
Packit Service 2e9770
           ? 0 : xrs * yis);
Packit Service 2e9770
   }
Packit Service 2e9770
   else {
Packit Service 2e9770
      /* x = xr + i*(+/-inf) with |xr| != inf */
Packit Service 2e9770
      u = (   mpfr_zero_p (mpc_imagref (y))
Packit Service 2e9770
           || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_realref (y)))
Packit Service 2e9770
           || (mpfr_inf_p (mpc_realref (y)) && xrs*yrs == xis*yis)
Packit Service 2e9770
           ? 0 : -xis * yis);
Packit Service 2e9770
      v = (   mpfr_zero_p (mpc_realref (y))
Packit Service 2e9770
           || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_imagref (y)))
Packit Service 2e9770
           || (mpfr_inf_p (mpc_imagref (y)) && xrs*yis != xis*yrs)
Packit Service 2e9770
           ? 0 : xis * yrs);
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (u == 0 && v == 0) {
Packit Service 2e9770
      /* Naive result is NaN+i*NaN. Obtain an infinity using the algorithm
Packit Service 2e9770
         given in Annex G.5.1 of the ISO C99 standard */
Packit Service 2e9770
      int xr = (mpfr_zero_p (mpc_realref (x)) || mpfr_nan_p (mpc_realref (x)) ? 0
Packit Service 2e9770
                : (mpfr_inf_p (mpc_realref (x)) ? 1 : 0));
Packit Service 2e9770
      int xi = (mpfr_zero_p (mpc_imagref (x)) || mpfr_nan_p (mpc_imagref (x)) ? 0
Packit Service 2e9770
                : (mpfr_inf_p (mpc_imagref (x)) ? 1 : 0));
Packit Service 2e9770
      int yr = (mpfr_zero_p (mpc_realref (y)) || mpfr_nan_p (mpc_realref (y)) ? 0 : 1);
Packit Service 2e9770
      int yi = (mpfr_zero_p (mpc_imagref (y)) || mpfr_nan_p (mpc_imagref (y)) ? 0 : 1);
Packit Service 2e9770
      if (mpc_inf_p (y)) {
Packit Service 2e9770
         yr = mpfr_inf_p (mpc_realref (y)) ? 1 : 0;
Packit Service 2e9770
         yi = mpfr_inf_p (mpc_imagref (y)) ? 1 : 0;
Packit Service 2e9770
      }
Packit Service 2e9770
Packit Service 2e9770
      u = xrs * xr * yrs * yr - xis * xi * yis * yi;
Packit Service 2e9770
      v = xrs * xr * yis * yi + xis * xi * yrs * yr;
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (u == 0)
Packit Service 2e9770
      mpfr_set_nan (mpc_realref (z));
Packit Service 2e9770
   else
Packit Service 2e9770
      mpfr_set_inf (mpc_realref (z), u);
Packit Service 2e9770
Packit Service 2e9770
   if (v == 0)
Packit Service 2e9770
      mpfr_set_nan (mpc_imagref (z));
Packit Service 2e9770
   else
Packit Service 2e9770
      mpfr_set_inf (mpc_imagref (z), v);
Packit Service 2e9770
Packit Service 2e9770
   return MPC_INEX (0, 0); /* exact */
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
/* compute z = x*y for Im(y) == 0 */
Packit Service 2e9770
static int
Packit Service 2e9770
mul_real (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   int xrs, xis, yrs, yis;
Packit Service 2e9770
   int inex;
Packit Service 2e9770
Packit Service 2e9770
   /* save signs of operands */
Packit Service 2e9770
   xrs = MPFR_SIGNBIT (mpc_realref (x));
Packit Service 2e9770
   xis = MPFR_SIGNBIT (mpc_imagref (x));
Packit Service 2e9770
   yrs = MPFR_SIGNBIT (mpc_realref (y));
Packit Service 2e9770
   yis = MPFR_SIGNBIT (mpc_imagref (y));
Packit Service 2e9770
Packit Service 2e9770
   inex = mpc_mul_fr (z, x, mpc_realref (y), rnd);
Packit Service 2e9770
   /* Signs of zeroes may be wrong. Their correction does not change the
Packit Service 2e9770
      inexact flag. */
Packit Service 2e9770
   if (mpfr_zero_p (mpc_realref (z)))
Packit Service 2e9770
      mpfr_setsign (mpc_realref (z), mpc_realref (z), MPC_RND_RE(rnd) == MPFR_RNDD
Packit Service 2e9770
                     || (xrs != yrs && xis == yis), MPFR_RNDN);
Packit Service 2e9770
   if (mpfr_zero_p (mpc_imagref (z)))
Packit Service 2e9770
      mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == MPFR_RNDD
Packit Service 2e9770
                     || (xrs != yis && xis != yrs), MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
   return inex;
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
/* compute z = x*y for Re(y) == 0, and Im(x) != 0 and Im(y) != 0 */
Packit Service 2e9770
static int
Packit Service 2e9770
mul_imag (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   int sign;
Packit Service 2e9770
   int inex_re, inex_im;
Packit Service 2e9770
   int overlap = z == x || z == y;
Packit Service 2e9770
   mpc_t rop;
Packit Service 2e9770
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
Packit Service 2e9770
   else
Packit Service 2e9770
      rop [0] = z[0];
Packit Service 2e9770
Packit Service 2e9770
   sign =    (MPFR_SIGNBIT (mpc_realref (y)) != MPFR_SIGNBIT (mpc_imagref (x)))
Packit Service 2e9770
          && (MPFR_SIGNBIT (mpc_imagref (y)) != MPFR_SIGNBIT (mpc_realref (x)));
Packit Service 2e9770
Packit Service 2e9770
   inex_re = -mpfr_mul (mpc_realref (rop), mpc_imagref (x), mpc_imagref (y),
Packit Service 2e9770
                        INV_RND (MPC_RND_RE (rnd)));
Packit Service 2e9770
   mpfr_neg (mpc_realref (rop), mpc_realref (rop), MPFR_RNDN); /* exact */
Packit Service 2e9770
   inex_im = mpfr_mul (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y),
Packit Service 2e9770
                       MPC_RND_IM (rnd));
Packit Service 2e9770
   mpc_set (z, rop, MPC_RNDNN);
Packit Service 2e9770
Packit Service 2e9770
   /* Sign of zeroes may be wrong (note that Re(z) cannot be zero) */
Packit Service 2e9770
   if (mpfr_zero_p (mpc_imagref (z)))
Packit Service 2e9770
      mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == MPFR_RNDD
Packit Service 2e9770
                     || sign, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_clear (rop);
Packit Service 2e9770
Packit Service 2e9770
   return MPC_INEX (inex_re, inex_im);
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
#define MPFR_MANT(x)      ((x)->_mpfr_d)
Packit Service 2e9770
#define MPFR_PREC(x)      ((x)->_mpfr_prec)
Packit Service 2e9770
#define MPFR_EXP(x)       ((x)->_mpfr_exp)
Packit Service 2e9770
#define MPFR_LIMB_SIZE(x) ((MPFR_PREC (x) - 1) / GMP_NUMB_BITS + 1)
Packit Service 2e9770
Packit Service 2e9770
#if HAVE_MPFR_FMMA == 0
Packit Service 2e9770
static int
Packit Service 2e9770
mpc_fmma (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpfr_srcptr c,
Packit Service 2e9770
           mpfr_srcptr d, int sign, mpfr_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   /* Computes z = ab+cd if sign >= 0, or z = ab-cd if sign < 0.
Packit Service 2e9770
      Assumes that a, b, c, d are finite and non-zero; so any multiplication
Packit Service 2e9770
      of two of them yielding an infinity is an overflow, and a
Packit Service 2e9770
      multiplication yielding 0 is an underflow.
Packit Service 2e9770
      Assumes further that z is distinct from a, b, c, d. */
Packit Service 2e9770
Packit Service 2e9770
   int inex;
Packit Service 2e9770
   mpfr_t u, v;
Packit Service 2e9770
   mp_size_t an, bn, cn, dn;
Packit Service 2e9770
Packit Service 2e9770
   /* u=a*b, v=sign*c*d exactly */
Packit Service 2e9770
   an = MPFR_LIMB_SIZE(a);
Packit Service 2e9770
   bn = MPFR_LIMB_SIZE(b);
Packit Service 2e9770
   cn = MPFR_LIMB_SIZE(c);
Packit Service 2e9770
   dn = MPFR_LIMB_SIZE(d);
Packit Service 2e9770
   MPFR_MANT(u) = malloc ((an + bn) * sizeof (mp_limb_t));
Packit Service 2e9770
   MPFR_MANT(v) = malloc ((cn + dn) * sizeof (mp_limb_t));
Packit Service 2e9770
   if (an >= bn)
Packit Service 2e9770
     mpn_mul (MPFR_MANT(u), MPFR_MANT(a), an, MPFR_MANT(b), bn);
Packit Service 2e9770
   else
Packit Service 2e9770
     mpn_mul (MPFR_MANT(u), MPFR_MANT(b), bn, MPFR_MANT(a), an);
Packit Service 2e9770
   if ((MPFR_MANT(u)[an + bn - 1] >> (GMP_NUMB_BITS - 1)) == 0)
Packit Service 2e9770
     {
Packit Service 2e9770
       mpn_lshift (MPFR_MANT(u), MPFR_MANT(u), an + bn, 1);
Packit Service 2e9770
       MPFR_EXP(u) = MPFR_EXP(a) + MPFR_EXP(b) - 1;
Packit Service 2e9770
     }
Packit Service 2e9770
   else
Packit Service 2e9770
     MPFR_EXP(u) = MPFR_EXP(a) + MPFR_EXP(b);
Packit Service 2e9770
   if (cn >= dn)
Packit Service 2e9770
     mpn_mul (MPFR_MANT(v), MPFR_MANT(c), cn, MPFR_MANT(d), dn);
Packit Service 2e9770
   else
Packit Service 2e9770
     mpn_mul (MPFR_MANT(v), MPFR_MANT(d), dn, MPFR_MANT(c), cn);
Packit Service 2e9770
   if ((MPFR_MANT(v)[cn + dn - 1] >> (GMP_NUMB_BITS - 1)) == 0)
Packit Service 2e9770
     {
Packit Service 2e9770
       mpn_lshift (MPFR_MANT(v), MPFR_MANT(v), cn + dn, 1);
Packit Service 2e9770
       MPFR_EXP(v) = MPFR_EXP(c) + MPFR_EXP(d) - 1;
Packit Service 2e9770
     }
Packit Service 2e9770
   else
Packit Service 2e9770
     MPFR_EXP(v) = MPFR_EXP(c) + MPFR_EXP(d);
Packit Service 2e9770
   MPFR_PREC(u) = (an + bn) * GMP_NUMB_BITS;
Packit Service 2e9770
   MPFR_PREC(v) = (cn + dn) * GMP_NUMB_BITS;
Packit Service 2e9770
   MPFR_SIGN(u) = MPFR_SIGN(a) * MPFR_SIGN(b);
Packit Service 2e9770
   if (sign > 0)
Packit Service 2e9770
     MPFR_SIGN(v) = MPFR_SIGN(c) * MPFR_SIGN(d);
Packit Service 2e9770
   else
Packit Service 2e9770
     MPFR_SIGN(v) = -MPFR_SIGN(c) * MPFR_SIGN(d);
Packit Service 2e9770
Packit Service 2e9770
   mpfr_check_range (u, 0, MPFR_RNDN);
Packit Service 2e9770
   mpfr_check_range (v, 0, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
   /* tentatively compute z as u+v; here we need z to be distinct
Packit Service 2e9770
      from a, b, c, d to not lose the latter */
Packit Service 2e9770
   inex = mpfr_add (z, u, v, rnd);
Packit Service 2e9770
Packit Service 2e9770
   if (!mpfr_regular_p(z) || !mpfr_regular_p(u) || !mpfr_regular_p(v))
Packit Service 2e9770
     {
Packit Service 2e9770
       if (mpfr_inf_p (z)) {
Packit Service 2e9770
         /* replace by "correctly rounded overflow" */
Packit Service 2e9770
         mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), MPFR_RNDN);
Packit Service 2e9770
         inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd);
Packit Service 2e9770
       }
Packit Service 2e9770
       else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) {
Packit Service 2e9770
         /* exactly u underflowed, determine inexact flag */
Packit Service 2e9770
         inex = (mpfr_signbit (u) ? 1 : -1);
Packit Service 2e9770
       }
Packit Service 2e9770
       else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) {
Packit Service 2e9770
         /* exactly v underflowed, determine inexact flag */
Packit Service 2e9770
         inex = (mpfr_signbit (v) ? 1 : -1);
Packit Service 2e9770
       }
Packit Service 2e9770
       else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) {
Packit Service 2e9770
      /* In the first case, u and v are infinities with opposite signs.
Packit Service 2e9770
         In the second case, u and v are zeroes; their sum may be 0 or the
Packit Service 2e9770
         least representable number, with a sign to be determined.
Packit Service 2e9770
         Redo the computations with mpz_t exponents */
Packit Service 2e9770
      mpfr_exp_t ea, eb, ec, ed;
Packit Service 2e9770
      mpz_t eu, ev;
Packit Service 2e9770
         /* cheat to work around the const qualifiers */
Packit Service 2e9770
Packit Service 2e9770
      /* Normalise the input by shifting and keep track of the shifts in
Packit Service 2e9770
         the exponents of u and v */
Packit Service 2e9770
      ea = mpfr_get_exp (a);
Packit Service 2e9770
      eb = mpfr_get_exp (b);
Packit Service 2e9770
      ec = mpfr_get_exp (c);
Packit Service 2e9770
      ed = mpfr_get_exp (d);
Packit Service 2e9770
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) b, (mpfr_prec_t) 0);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) d, (mpfr_prec_t) 0);
Packit Service 2e9770
Packit Service 2e9770
      mpz_init (eu);
Packit Service 2e9770
      mpz_init (ev);
Packit Service 2e9770
      mpz_set_si (eu, (long int) ea);
Packit Service 2e9770
      mpz_add_si (eu, eu, (long int) eb);
Packit Service 2e9770
      mpz_set_si (ev, (long int) ec);
Packit Service 2e9770
      mpz_add_si (ev, ev, (long int) ed);
Packit Service 2e9770
Packit Service 2e9770
      /* recompute u and v and move exponents to eu and ev */
Packit Service 2e9770
      mpfr_mul (u, a, b, MPFR_RNDN);
Packit Service 2e9770
      /* exponent of u is non-positive */
Packit Service 2e9770
      mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u)));
Packit Service 2e9770
      mpfr_set_exp (u, (mpfr_prec_t) 0);
Packit Service 2e9770
      mpfr_mul (v, c, d, MPFR_RNDN);
Packit Service 2e9770
      if (sign < 0)
Packit Service 2e9770
         mpfr_neg (v, v, MPFR_RNDN);
Packit Service 2e9770
      mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v)));
Packit Service 2e9770
      mpfr_set_exp (v, (mpfr_prec_t) 0);
Packit Service 2e9770
Packit Service 2e9770
      if (mpfr_nan_p (z)) {
Packit Service 2e9770
         mpfr_exp_t emax = mpfr_get_emax ();
Packit Service 2e9770
         int overflow;
Packit Service 2e9770
         /* We have a = ma * 2^ea with 1/2 <= |ma| < 1 and ea <= emax, and
Packit Service 2e9770
            analogously for b. So eu <= 2*emax, and eu > emax since we have
Packit Service 2e9770
            an overflow. The same holds for ev. Shift u and v by as much as
Packit Service 2e9770
            possible so that one of them has exponent emax and the
Packit Service 2e9770
            remaining exponents in eu and ev are the same. Then carry out
Packit Service 2e9770
            the addition. Shifting u and v prevents an underflow. */
Packit Service 2e9770
         if (mpz_cmp (eu, ev) >= 0) {
Packit Service 2e9770
            mpfr_set_exp (u, emax);
Packit Service 2e9770
            mpz_sub_ui (eu, eu, (long int) emax);
Packit Service 2e9770
            mpz_sub (ev, ev, eu);
Packit Service 2e9770
            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev));
Packit Service 2e9770
               /* remaining common exponent is now in eu */
Packit Service 2e9770
         }
Packit Service 2e9770
         else {
Packit Service 2e9770
            mpfr_set_exp (v, emax);
Packit Service 2e9770
            mpz_sub_ui (ev, ev, (long int) emax);
Packit Service 2e9770
            mpz_sub (eu, eu, ev);
Packit Service 2e9770
            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu));
Packit Service 2e9770
            mpz_set (eu, ev);
Packit Service 2e9770
               /* remaining common exponent is now also in eu */
Packit Service 2e9770
         }
Packit Service 2e9770
         inex = mpfr_add (z, u, v, rnd);
Packit Service 2e9770
            /* Result is finite since u and v have different signs. */
Packit Service 2e9770
         overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd);
Packit Service 2e9770
         if (overflow)
Packit Service 2e9770
            inex = overflow;
Packit Service 2e9770
      }
Packit Service 2e9770
      else {
Packit Service 2e9770
         int underflow;
Packit Service 2e9770
         /* Addition of two zeroes with same sign. We have a = ma * 2^ea
Packit Service 2e9770
            with 1/2 <= |ma| < 1 and ea >= emin and similarly for b.
Packit Service 2e9770
            So 2*emin < 2*emin+1 <= eu < emin < 0, and analogously for v. */
Packit Service 2e9770
         mpfr_exp_t emin = mpfr_get_emin ();
Packit Service 2e9770
         if (mpz_cmp (eu, ev) <= 0) {
Packit Service 2e9770
            mpfr_set_exp (u, emin);
Packit Service 2e9770
            mpz_add_ui (eu, eu, (unsigned long int) (-emin));
Packit Service 2e9770
            mpz_sub (ev, ev, eu);
Packit Service 2e9770
            mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev));
Packit Service 2e9770
         }
Packit Service 2e9770
         else {
Packit Service 2e9770
            mpfr_set_exp (v, emin);
Packit Service 2e9770
            mpz_add_ui (ev, ev, (unsigned long int) (-emin));
Packit Service 2e9770
            mpz_sub (eu, eu, ev);
Packit Service 2e9770
            mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu));
Packit Service 2e9770
            mpz_set (eu, ev);
Packit Service 2e9770
         }
Packit Service 2e9770
         inex = mpfr_add (z, u, v, rnd);
Packit Service 2e9770
         mpz_neg (eu, eu);
Packit Service 2e9770
         underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd);
Packit Service 2e9770
         if (underflow)
Packit Service 2e9770
            inex = underflow;
Packit Service 2e9770
      }
Packit Service 2e9770
Packit Service 2e9770
      mpz_clear (eu);
Packit Service 2e9770
      mpz_clear (ev);
Packit Service 2e9770
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) a, ea);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) b, eb);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) c, ec);
Packit Service 2e9770
      mpfr_set_exp ((mpfr_ptr) d, ed);
Packit Service 2e9770
         /* works also when some of a, b, c, d are not all distinct */
Packit Service 2e9770
       }
Packit Service 2e9770
     }
Packit Service 2e9770
Packit Service 2e9770
   free (MPFR_MANT(u));
Packit Service 2e9770
   free (MPFR_MANT(v));
Packit Service 2e9770
   return inex;
Packit Service 2e9770
}
Packit Service 2e9770
#endif
Packit Service 2e9770
Packit Service 2e9770
int
Packit Service 2e9770
mpc_mul_naive (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   /* computes z=x*y by the schoolbook method, where x and y are assumed
Packit Service 2e9770
      to be finite and without zero parts                                */
Packit Service 2e9770
   int overlap, inex;
Packit Service 2e9770
   mpc_t rop;
Packit Service 2e9770
Packit Service 2e9770
   MPC_ASSERT (   mpfr_regular_p (mpc_realref (x)) && mpfr_regular_p (mpc_imagref (x))
Packit Service 2e9770
               && mpfr_regular_p (mpc_realref (y)) && mpfr_regular_p (mpc_imagref (y)));
Packit Service 2e9770
   overlap = (z == x) || (z == y);
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
Packit Service 2e9770
   else
Packit Service 2e9770
      rop [0] = z [0];
Packit Service 2e9770
Packit Service 2e9770
#if HAVE_MPFR_FMMA
Packit Service 2e9770
   inex = MPC_INEX (mpfr_fmms (mpc_realref (rop), mpc_realref (x), mpc_realref (y), mpc_imagref (x),
Packit Service 2e9770
                               mpc_imagref (y), MPC_RND_RE (rnd)),
Packit Service 2e9770
                    mpfr_fmma (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y), mpc_imagref (x),
Packit Service 2e9770
                               mpc_realref (y), MPC_RND_IM (rnd)));
Packit Service 2e9770
#else
Packit Service 2e9770
   inex = MPC_INEX (mpc_fmma (mpc_realref (rop), mpc_realref (x), mpc_realref (y), mpc_imagref (x),
Packit Service 2e9770
                               mpc_imagref (y), -1, MPC_RND_RE (rnd)),
Packit Service 2e9770
                    mpc_fmma (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y), mpc_imagref (x),
Packit Service 2e9770
                               mpc_realref (y), +1, MPC_RND_IM (rnd)));
Packit Service 2e9770
#endif
Packit Service 2e9770
Packit Service 2e9770
   mpc_set (z, rop, MPC_RNDNN);
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_clear (rop);
Packit Service 2e9770
Packit Service 2e9770
   return inex;
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
int
Packit Service 2e9770
mpc_mul_karatsuba (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   /* computes rop=op1*op2 by a Karatsuba algorithm, where op1 and op2
Packit Service 2e9770
      are assumed to be finite and without zero parts                  */
Packit Service 2e9770
  mpfr_srcptr a, b, c, d;
Packit Service 2e9770
  int mul_i, ok, inexact, mul_a, mul_c, inex_re = 0, inex_im = 0, sign_x, sign_u;
Packit Service 2e9770
  mpfr_t u, v, w, x;
Packit Service 2e9770
  mpfr_prec_t prec, prec_re, prec_u, prec_v, prec_w;
Packit Service 2e9770
  mpfr_rnd_t rnd_re, rnd_u;
Packit Service 2e9770
  int overlap;
Packit Service 2e9770
     /* true if rop == op1 or rop == op2 */
Packit Service 2e9770
  mpc_t result;
Packit Service 2e9770
     /* overlap is quite difficult to handle, because we have to tentatively
Packit Service 2e9770
        round the variable u in the end to either the real or the imaginary
Packit Service 2e9770
        part of rop (it is not possible to tell now whether the real or
Packit Service 2e9770
        imaginary part is used). If this fails, we have to start again and
Packit Service 2e9770
        need the correct values of op1 and op2.
Packit Service 2e9770
        So we just create a new variable for the result in this case. */
Packit Service 2e9770
  int loop;
Packit Service 2e9770
  const int MAX_MUL_LOOP = 1;
Packit Service 2e9770
Packit Service 2e9770
  overlap = (rop == op1) || (rop == op2);
Packit Service 2e9770
  if (overlap)
Packit Service 2e9770
     mpc_init3 (result, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
Packit Service 2e9770
  else
Packit Service 2e9770
     result [0] = rop [0];
Packit Service 2e9770
Packit Service 2e9770
  a = mpc_realref(op1);
Packit Service 2e9770
  b = mpc_imagref(op1);
Packit Service 2e9770
  c = mpc_realref(op2);
Packit Service 2e9770
  d = mpc_imagref(op2);
Packit Service 2e9770
Packit Service 2e9770
  /* (a + i*b) * (c + i*d) = [ac - bd] + i*[ad + bc] */
Packit Service 2e9770
Packit Service 2e9770
  mul_i = 0; /* number of multiplications by i */
Packit Service 2e9770
  mul_a = 1; /* implicit factor for a */
Packit Service 2e9770
  mul_c = 1; /* implicit factor for c */
Packit Service 2e9770
Packit Service 2e9770
  if (mpfr_cmp_abs (a, b) < 0)
Packit Service 2e9770
    {
Packit Service 2e9770
      MPFR_SWAP (a, b);
Packit Service 2e9770
      mul_i ++;
Packit Service 2e9770
      mul_a = -1; /* consider i * (a+i*b) = -b + i*a */
Packit Service 2e9770
    }
Packit Service 2e9770
Packit Service 2e9770
  if (mpfr_cmp_abs (c, d) < 0)
Packit Service 2e9770
    {
Packit Service 2e9770
      MPFR_SWAP (c, d);
Packit Service 2e9770
      mul_i ++;
Packit Service 2e9770
      mul_c = -1; /* consider -d + i*c instead of c + i*d */
Packit Service 2e9770
    }
Packit Service 2e9770
Packit Service 2e9770
  /* find the precision and rounding mode for the new real part */
Packit Service 2e9770
  if (mul_i % 2)
Packit Service 2e9770
    {
Packit Service 2e9770
      prec_re = MPC_PREC_IM(rop);
Packit Service 2e9770
      rnd_re = MPC_RND_IM(rnd);
Packit Service 2e9770
    }
Packit Service 2e9770
  else /* mul_i = 0 or 2 */
Packit Service 2e9770
    {
Packit Service 2e9770
      prec_re = MPC_PREC_RE(rop);
Packit Service 2e9770
      rnd_re = MPC_RND_RE(rnd);
Packit Service 2e9770
    }
Packit Service 2e9770
Packit Service 2e9770
  if (mul_i)
Packit Service 2e9770
    rnd_re = INV_RND(rnd_re);
Packit Service 2e9770
Packit Service 2e9770
  /* now |a| >= |b| and |c| >= |d| */
Packit Service 2e9770
  prec = MPC_MAX_PREC(rop);
Packit Service 2e9770
Packit Service 2e9770
  mpfr_init2 (v, prec_v = mpfr_get_prec (a) + mpfr_get_prec (d));
Packit Service 2e9770
  mpfr_init2 (w, prec_w = mpfr_get_prec (b) + mpfr_get_prec (c));
Packit Service 2e9770
  mpfr_init2 (u, 2);
Packit Service 2e9770
  mpfr_init2 (x, 2);
Packit Service 2e9770
Packit Service 2e9770
  inexact = mpfr_mul (v, a, d, MPFR_RNDN);
Packit Service 2e9770
  if (inexact) {
Packit Service 2e9770
     /* over- or underflow */
Packit Service 2e9770
    ok = 0;
Packit Service 2e9770
    goto clear;
Packit Service 2e9770
  }
Packit Service 2e9770
  if (mul_a == -1)
Packit Service 2e9770
    mpfr_neg (v, v, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
  inexact = mpfr_mul (w, b, c, MPFR_RNDN);
Packit Service 2e9770
  if (inexact) {
Packit Service 2e9770
     /* over- or underflow */
Packit Service 2e9770
     ok = 0;
Packit Service 2e9770
     goto clear;
Packit Service 2e9770
  }
Packit Service 2e9770
  if (mul_c == -1)
Packit Service 2e9770
    mpfr_neg (w, w, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
  /* compute sign(v-w) */
Packit Service 2e9770
  sign_x = mpfr_cmp_abs (v, w);
Packit Service 2e9770
  if (sign_x > 0)
Packit Service 2e9770
    sign_x = 2 * mpfr_sgn (v) - mpfr_sgn (w);
Packit Service 2e9770
  else if (sign_x == 0)
Packit Service 2e9770
    sign_x = mpfr_sgn (v) - mpfr_sgn (w);
Packit Service 2e9770
  else
Packit Service 2e9770
    sign_x = mpfr_sgn (v) - 2 * mpfr_sgn (w);
Packit Service 2e9770
Packit Service 2e9770
   sign_u = mul_a * mpfr_sgn (a) * mul_c * mpfr_sgn (c);
Packit Service 2e9770
Packit Service 2e9770
   if (sign_x * sign_u < 0)
Packit Service 2e9770
    {  /* swap inputs */
Packit Service 2e9770
      MPFR_SWAP (a, c);
Packit Service 2e9770
      MPFR_SWAP (b, d);
Packit Service 2e9770
      mpfr_swap (v, w);
Packit Service 2e9770
      { int tmp; tmp = mul_a; mul_a = mul_c; mul_c = tmp; }
Packit Service 2e9770
      sign_x = - sign_x;
Packit Service 2e9770
    }
Packit Service 2e9770
Packit Service 2e9770
   /* now sign_x * sign_u >= 0 */
Packit Service 2e9770
   loop = 0;
Packit Service 2e9770
   do
Packit Service 2e9770
     {
Packit Service 2e9770
        loop++;
Packit Service 2e9770
         /* the following should give failures with prob. <= 1/prec */
Packit Service 2e9770
         prec += mpc_ceil_log2 (prec) + 3;
Packit Service 2e9770
Packit Service 2e9770
         mpfr_set_prec (u, prec_u = prec);
Packit Service 2e9770
         mpfr_set_prec (x, prec);
Packit Service 2e9770
Packit Service 2e9770
         /* first compute away(b +/- a) and store it in u */
Packit Service 2e9770
         inexact = (mul_a == -1 ?
Packit Service 2e9770
                    mpfr_sub (u, b, a, MPFR_RNDA) :
Packit Service 2e9770
                    mpfr_add (u, b, a, MPFR_RNDA));
Packit Service 2e9770
Packit Service 2e9770
         /* then compute away(+/-c - d) and store it in x */
Packit Service 2e9770
         inexact |= (mul_c == -1 ?
Packit Service 2e9770
                     mpfr_add (x, c, d, MPFR_RNDA) :
Packit Service 2e9770
                     mpfr_sub (x, c, d, MPFR_RNDA));
Packit Service 2e9770
         if (mul_c == -1)
Packit Service 2e9770
           mpfr_neg (x, x, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
         if (inexact == 0)
Packit Service 2e9770
            mpfr_prec_round (u, prec_u = 2 * prec, MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
         /* compute away(u*x) and store it in u */
Packit Service 2e9770
         inexact |= mpfr_mul (u, u, x, MPFR_RNDA);
Packit Service 2e9770
            /* (a+b)*(c-d) */
Packit Service 2e9770
Packit Service 2e9770
	 /* if all computations are exact up to here, it may be that
Packit Service 2e9770
	    the real part is exact, thus we need if possible to
Packit Service 2e9770
	    compute v - w exactly */
Packit Service 2e9770
	 if (inexact == 0)
Packit Service 2e9770
	   {
Packit Service 2e9770
	     mpfr_prec_t prec_x;
Packit Service 2e9770
             /* v and w are different from 0, so mpfr_get_exp is safe to use */
Packit Service 2e9770
             prec_x = SAFE_ABS (mpfr_exp_t, mpfr_get_exp (v) - mpfr_get_exp (w))
Packit Service 2e9770
                      + MPC_MAX (prec_v, prec_w) + 1;
Packit Service 2e9770
                      /* +1 is necessary for a potential carry */
Packit Service 2e9770
	     /* ensure we do not use a too large precision */
Packit Service 2e9770
	     if (prec_x > prec_u)
Packit Service 2e9770
               prec_x = prec_u;
Packit Service 2e9770
	     if (prec_x > prec)
Packit Service 2e9770
	       mpfr_prec_round (x, prec_x, MPFR_RNDN);
Packit Service 2e9770
	   }
Packit Service 2e9770
Packit Service 2e9770
         rnd_u = (sign_u > 0) ? MPFR_RNDU : MPFR_RNDD;
Packit Service 2e9770
         inexact |= mpfr_sub (x, v, w, rnd_u); /* ad - bc */
Packit Service 2e9770
Packit Service 2e9770
         /* in case u=0, ensure that rnd_u rounds x away from zero */
Packit Service 2e9770
         if (mpfr_sgn (u) == 0)
Packit Service 2e9770
           rnd_u = (mpfr_sgn (x) > 0) ? MPFR_RNDU : MPFR_RNDD;
Packit Service 2e9770
         inexact |= mpfr_add (u, u, x, rnd_u); /* ac - bd */
Packit Service 2e9770
Packit Service 2e9770
         ok = inexact == 0 ||
Packit Service 2e9770
           mpfr_can_round (u, prec_u - 3, rnd_u, MPFR_RNDZ,
Packit Service 2e9770
                           prec_re + (rnd_re == MPFR_RNDN));
Packit Service 2e9770
         /* this ensures both we can round correctly and determine the correct
Packit Service 2e9770
            inexact flag (for rounding to nearest) */
Packit Service 2e9770
     }
Packit Service 2e9770
   while (!ok && loop <= MAX_MUL_LOOP);
Packit Service 2e9770
      /* after MAX_MUL_LOOP rounds, use mpc_naive instead */
Packit Service 2e9770
Packit Service 2e9770
   if (ok) {
Packit Service 2e9770
      /* if inexact is zero, then u is exactly ac-bd, otherwise fix the sign
Packit Service 2e9770
         of the inexact flag for u, which was rounded away from ac-bd */
Packit Service 2e9770
      if (inexact != 0)
Packit Service 2e9770
      inexact = mpfr_sgn (u);
Packit Service 2e9770
Packit Service 2e9770
      if (mul_i == 0)
Packit Service 2e9770
      {
Packit Service 2e9770
         inex_re = mpfr_set (mpc_realref(result), u, MPC_RND_RE(rnd));
Packit Service 2e9770
         if (inex_re == 0)
Packit Service 2e9770
            {
Packit Service 2e9770
            inex_re = inexact; /* u is rounded away from 0 */
Packit Service 2e9770
            inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
Packit Service 2e9770
            }
Packit Service 2e9770
         else
Packit Service 2e9770
            inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mul_i == 1) /* (x+i*y)/i = y - i*x */
Packit Service 2e9770
      {
Packit Service 2e9770
         inex_im = mpfr_neg (mpc_imagref(result), u, MPC_RND_IM(rnd));
Packit Service 2e9770
         if (inex_im == 0)
Packit Service 2e9770
            {
Packit Service 2e9770
            inex_im = -inexact; /* u is rounded away from 0 */
Packit Service 2e9770
            inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
Packit Service 2e9770
            }
Packit Service 2e9770
         else
Packit Service 2e9770
            inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
Packit Service 2e9770
      }
Packit Service 2e9770
      else /* mul_i = 2, z/i^2 = -z */
Packit Service 2e9770
      {
Packit Service 2e9770
         inex_re = mpfr_neg (mpc_realref(result), u, MPC_RND_RE(rnd));
Packit Service 2e9770
         if (inex_re == 0)
Packit Service 2e9770
            {
Packit Service 2e9770
            inex_re = -inexact; /* u is rounded away from 0 */
Packit Service 2e9770
            inex_im = -mpfr_add (mpc_imagref(result), v, w,
Packit Service 2e9770
                                 INV_RND(MPC_RND_IM(rnd)));
Packit Service 2e9770
            mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
Packit Service 2e9770
            }
Packit Service 2e9770
         else
Packit Service 2e9770
            {
Packit Service 2e9770
            inex_im = -mpfr_add (mpc_imagref(result), v, w,
Packit Service 2e9770
                                 INV_RND(MPC_RND_IM(rnd)));
Packit Service 2e9770
            mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
Packit Service 2e9770
            }
Packit Service 2e9770
      }
Packit Service 2e9770
Packit Service 2e9770
      mpc_set (rop, result, MPC_RNDNN);
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
clear:
Packit Service 2e9770
   mpfr_clear (u);
Packit Service 2e9770
   mpfr_clear (v);
Packit Service 2e9770
   mpfr_clear (w);
Packit Service 2e9770
   mpfr_clear (x);
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_clear (result);
Packit Service 2e9770
Packit Service 2e9770
   if (ok)
Packit Service 2e9770
      return MPC_INEX(inex_re, inex_im);
Packit Service 2e9770
   else
Packit Service 2e9770
      return mpc_mul_naive (rop, op1, op2, rnd);
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
int
Packit Service 2e9770
mpc_mul (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
   /* Conforming to ISO C99 standard (G.5.1 multiplicative operators),
Packit Service 2e9770
      infinities are treated specially if both parts are NaN when computed
Packit Service 2e9770
      naively. */
Packit Service 2e9770
   if (mpc_inf_p (b))
Packit Service 2e9770
      return mul_infinite (a, b, c);
Packit Service 2e9770
   if (mpc_inf_p (c))
Packit Service 2e9770
      return mul_infinite (a, c, b);
Packit Service 2e9770
Packit Service 2e9770
   /* NaN contamination of both parts in result */
Packit Service 2e9770
   if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b))
Packit Service 2e9770
       || mpfr_nan_p (mpc_realref (c)) || mpfr_nan_p (mpc_imagref (c))) {
Packit Service 2e9770
      mpfr_set_nan (mpc_realref (a));
Packit Service 2e9770
      mpfr_set_nan (mpc_imagref (a));
Packit Service 2e9770
      return MPC_INEX (0, 0);
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   /* check for real multiplication */
Packit Service 2e9770
   if (mpfr_zero_p (mpc_imagref (b)))
Packit Service 2e9770
      return mul_real (a, c, b, rnd);
Packit Service 2e9770
   if (mpfr_zero_p (mpc_imagref (c)))
Packit Service 2e9770
      return mul_real (a, b, c, rnd);
Packit Service 2e9770
Packit Service 2e9770
   /* check for purely imaginary multiplication */
Packit Service 2e9770
   if (mpfr_zero_p (mpc_realref (b)))
Packit Service 2e9770
      return mul_imag (a, c, b, rnd);
Packit Service 2e9770
   if (mpfr_zero_p (mpc_realref (c)))
Packit Service 2e9770
      return mul_imag (a, b, c, rnd);
Packit Service 2e9770
Packit Service 2e9770
   /* If the real and imaginary part of one argument have a very different */
Packit Service 2e9770
   /* exponent, it is not reasonable to use Karatsuba multiplication.      */
Packit Service 2e9770
   if (   SAFE_ABS (mpfr_exp_t,
Packit Service 2e9770
                     mpfr_get_exp (mpc_realref (b)) - mpfr_get_exp (mpc_imagref (b)))
Packit Service 2e9770
         > (mpfr_exp_t) MPC_MAX_PREC (b) / 2
Packit Service 2e9770
      || SAFE_ABS (mpfr_exp_t,
Packit Service 2e9770
                     mpfr_get_exp (mpc_realref (c)) - mpfr_get_exp (mpc_imagref (c)))
Packit Service 2e9770
         > (mpfr_exp_t) MPC_MAX_PREC (c) / 2)
Packit Service 2e9770
      return mpc_mul_naive (a, b, c, rnd);
Packit Service 2e9770
   else
Packit Service 2e9770
      return ((MPC_MAX_PREC(a)
Packit Service 2e9770
               <= (mpfr_prec_t) MUL_KARATSUBA_THRESHOLD * BITS_PER_MP_LIMB)
Packit Service 2e9770
            ? mpc_mul_naive : mpc_mul_karatsuba) (a, b, c, rnd);
Packit Service 2e9770
}