|
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 |
}
|