Ejemplo n.º 1
0
int
main (void)
{
  mpc_t z;

  test_start ();
  test_end ();

  mpc_init2 (z, 6);
  mpc_set_ui_ui (z, 17, 42, MPC_RNDNN);
  mpfr_set_ui (mpc_realref (z), 18, GMP_RNDN);
  if (mpfr_get_ui (mpc_realref (z), GMP_RNDN) != 18)
    {
      fprintf (stderr, "Error in mpfr_set_ui/mpc_realref\n");
      exit (1);
    }
  mpfr_set_ui (mpc_imagref (z), 43, GMP_RNDN);
  if (mpfr_get_ui (mpc_imagref (z), GMP_RNDN) != 43)
    {
      fprintf (stderr, "Error in mpfr_set_ui/mpc_imagref\n");
      exit (1);
    }
  mpc_clear (z);

  return 0;
}
Ejemplo n.º 2
0
int
main (void)
{
  mpc_t z;

  test_start ();

  mpc_init2 (z, 11);

  mpc_set_ui_ui (z, 2, 3, MPC_RNDNN);
  mpc_pow_d (z, z, 3.0, MPC_RNDNN);
  if (mpc_cmp_si_si (z, -46, 9) != 0)
    {
      printf ("Error for mpc_pow_d (1)\n");
      exit (1);
    }

  mpc_set_si_si (z, -3, 4, MPC_RNDNN);
  mpc_pow_d (z, z, 0.5, MPC_RNDNN);
  if (mpc_cmp_si_si (z, 1, 2) != 0)
    {
      printf ("Error for mpc_pow_d (2)\n");
      exit (1);
    }

  mpc_set_ui_ui (z, 2, 3, MPC_RNDNN);
  mpc_pow_d (z, z, 6.0, MPC_RNDNN);
  if (mpc_cmp_si_si (z, 2035, -828) != 0)
    {
      printf ("Error for mpc_pow_d (3)\n");
      exit (1);
    }

  mpc_clear (z);

  test_end ();

  return 0;
}
Ejemplo n.º 3
0
Archivo: sqrt.c Proyecto: carmel747/TSS
int main() {
	
	mpc_t z;
	int inex;
	mpc_init2(z, 128);
	mpc_set_ui_ui(z, 0, 1, MPC_RNDNN);

	inex = mpc_sqrt(z, z, MPC_RNDNN);
	mpc_out_str(stdout, 10, 3, z, MPC_RNDNN);
	printf("\n%i %i\n", MPC_INEX_RE(inex), MPC_INEX_IM(inex));

	mpc_clear(z);

}
static void
pure_real_argument (void)
{
  /* cosh(x -i*0) = cosh(x) +i*0 if x<0 */
  /* cosh(x -i*0) = cosh(x) -i*0 if x>0 */
  /* cosh(x +i*0) = cosh(x) -i*0 if x<0 */
  /* cosh(x -i*0) = cosh(x) +i*0 if x>0 */
  mpc_t u;
  mpc_t z;
  mpc_t cosh_z;

  mpc_init2 (z, 2);
  mpc_init2 (u, 100);
  mpc_init2 (cosh_z, 100);

  /* cosh(1 +i*0) = cosh(1) +i*0 */
  mpc_set_ui_ui (z, 1, 0, MPC_RNDNN);
  mpfr_cosh (MPC_RE (u), MPC_RE (z), GMP_RNDN);
  mpfr_set_ui (MPC_IM (u), 0, GMP_RNDN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(1 -i*0) = cosh(1) -i*0 */
  mpc_conj (z, z, MPC_RNDNN);
  mpc_conj (u, u, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || !mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(-1 +i*0) = cosh(1) -i*0 */
  mpc_neg (z, z, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || !mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(-1 -i*0) = cosh(1) +i*0 */
  mpc_conj (z, z, MPC_RNDNN);
  mpc_conj (u, u, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  mpc_clear (cosh_z);
  mpc_clear (z);
  mpc_clear (u);
}
Ejemplo n.º 5
0
static void
check_special (void)
{
  mpc_t z[3], res;
  mpc_ptr t[3];
  int i, inex;

  /* z[0] = (1,2), z[1] = (2,3), z[2] = (3,4) */
  for (i = 0; i < 3; i++)
    {
      mpc_init2 (z[i], 17);
      mpc_set_ui_ui (z[i], i+1, i+2, MPC_RNDNN);
      t[i] = z[i];
    }
  mpc_init2 (res, 17);
  /* dot product of empty vectors is 0 */
  inex = mpc_dot (res, t, t, 0, MPC_RNDNN);
  MPC_ASSERT (inex == 0);
  MPC_ASSERT (mpfr_zero_p (mpc_realref (res)));
  MPC_ASSERT (mpfr_zero_p (mpc_imagref (res)));
  MPC_ASSERT (mpfr_signbit (mpc_realref (res)) == 0);
  MPC_ASSERT (mpfr_signbit (mpc_imagref (res)) == 0);
  /* (1,2)*(1,2) = (-3,4) */
  inex = mpc_dot (res, t, t, 1, MPC_RNDNN);
  MPC_ASSERT (inex == 0);
  MPC_ASSERT (mpfr_regular_p (mpc_realref (res)));
  MPC_ASSERT (mpfr_regular_p (mpc_imagref (res)));
  MPC_ASSERT (mpfr_cmp_si (mpc_realref (res), -3) == 0);
  MPC_ASSERT (mpfr_cmp_ui (mpc_imagref (res), 4) == 0);
  /* (1,2)*(1,2) + (2,3)*(2,3) = (-8,16) */
  inex = mpc_dot (res, t, t, 2, MPC_RNDNN);
  MPC_ASSERT (inex == 0);
  MPC_ASSERT (mpfr_regular_p (mpc_realref (res)));
  MPC_ASSERT (mpfr_regular_p (mpc_imagref (res)));
  MPC_ASSERT (mpfr_cmp_si (mpc_realref (res), -8) == 0);
  MPC_ASSERT (mpfr_cmp_ui (mpc_imagref (res), 16) == 0);
  /* (1,2)*(1,2) + (2,3)*(2,3) + (3,4)*(3,4) = (-15,40) */
  inex = mpc_dot (res, t, t, 3, MPC_RNDNN);
  MPC_ASSERT (inex == 0);
  MPC_ASSERT (mpfr_regular_p (mpc_realref (res)));
  MPC_ASSERT (mpfr_regular_p (mpc_imagref (res)));
  MPC_ASSERT (mpfr_cmp_si (mpc_realref (res), -15) == 0);
  MPC_ASSERT (mpfr_cmp_ui (mpc_imagref (res), 40) == 0);
  for (i = 0; i < 3; i++)
    mpc_clear (z[i]);
  mpc_clear (res);
}
static void
pure_imaginary_argument (void)
{
  /* cosh(+0 +i*y) = cos y +i*0*sin y */
  /* cosh(-0 +i*y) = cos y -i*0*sin y */
  mpc_t u;
  mpc_t z;
  mpc_t cosh_z;

  mpc_init2 (z, 2);
  mpc_init2 (u, 100);
  mpc_init2 (cosh_z, 100);

  /* cosh(+0 +i) = cos(1) + i*0 */
  mpc_set_ui_ui (z, 0, 1, MPC_RNDNN);
  mpfr_cos (MPC_RE (u), MPC_IM (z), GMP_RNDN);
  mpfr_set_ui (MPC_IM (u), 0, GMP_RNDN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(+0 -i) = cos(1) - i*0 */
  mpc_conj (z, z, MPC_RNDNN);
  mpc_conj (u, u, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || !mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(-0 +i) = cos(1) - i*0 */
  mpc_neg (z, z, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || !mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  /* cosh(-0 -i) = cos(1) + i*0 */
  mpc_conj (z, z, MPC_RNDNN);
  mpc_conj (u, u, MPC_RNDNN);
  mpc_cosh (cosh_z, z, MPC_RNDNN);
  if (mpc_cmp (cosh_z, u) != 0 || mpfr_signbit (MPC_IM (cosh_z)))
    TEST_FAILED ("mpc_cosh", z, cosh_z, u, MPC_RNDNN);

  mpc_clear (cosh_z);
  mpc_clear (z);
  mpc_clear (u);
}
Ejemplo n.º 7
0
static void
bug20091120 (void)
{
  mpc_t x, y;

  mpc_init2 (x, 53);
  mpc_init3 (y, 17, 42);
  mpc_set_ui_ui (x, 1, 1, MPC_RNDNN);
  mpc_asinh (y, x, MPC_RNDNN);
  if (mpfr_get_prec (mpc_realref(y)) != 17 ||
      mpfr_get_prec (mpc_imagref(y)) != 42)
    {
      printf ("Error, mpc_asinh changed the precisions!!!\n");
      exit (1);
    }
  mpc_clear (x);
  mpc_clear (y);
}
Ejemplo n.º 8
0
int
main (void)
{
  mpc_t z;

  test_start ();

  mpc_init2 (z, 5);
  mpc_set_ui_ui (z, 3, 2, MPC_RNDNN);
  mpc_pow_si (z, z, 3, MPC_RNDNN);
  if (mpc_cmp_si_si (z, -9, 46) != 0)
    {
      printf ("Error for mpc_pow_si (1)\n");
      exit (1);
    }
  mpc_clear (z);

  test_end ();

  return 0;
}
Ejemplo n.º 9
0
Archivo: pow.c Proyecto: tomi500/MPC
/* 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, MPFR_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) == MPFR_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) == MPFR_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) == MPFR_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) == MPFR_RNDN;
  pi += MPC_RND_IM(rnd) == MPFR_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;

      mpc_log (t, x, MPC_RNDNN);
      mpc_mul (t, t, y, MPC_RNDNN);

      /* Compute q such that |Re (y log x)|, |Im (y log x)| < 2^q.
         We recompute it at each loop since we might get different
         bounds if the precision is not enough. */
      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, MPFR_RNDN, MPFR_RNDZ, pr))) &&
          (z_real || (p > q + 3 + di && mpfr_can_round (mpc_imagref(u), p - q - 3 - di, MPFR_RNDN, MPFR_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, MPFR_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), MPFR_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) == MPFR_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;
}
Ejemplo n.º 10
0
int
mpc_sqrt (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
{
  int ok_w, ok_t = 0;
  mpfr_t    w, t;
  mp_rnd_t  rnd_w, rnd_t;
  mp_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 */
  mp_prec_t prec;
  int inex_w, inex_t = 1, inex, loops = 0;
  /* comparison of the real/imaginary part of b with 0 */
  const int re_cmp = mpfr_cmp_ui (MPC_RE (b), 0);
  const int im_cmp = mpfr_cmp_ui (MPC_IM (b), 0);
  /* we need to know the sign of Im(b) when it is +/-0 */
  const int im_sgn = mpfr_signbit (MPC_IM (b)) == 0? 0 : -1;

  /* special values */
  /* 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_IM (b)))
    {
      mpfr_set_inf (MPC_RE (a), +1);
      mpfr_set_inf (MPC_IM (a), im_sgn);
      return MPC_INEX (0, 0);
    }

  if (mpfr_inf_p (MPC_RE (b)))
    {
      if (mpfr_signbit (MPC_RE (b)))
        {
          if (mpfr_number_p (MPC_IM (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_RE (a), 0, GMP_RNDN);
              mpfr_set_inf (MPC_IM (a), im_sgn);
              return MPC_INEX (0, 0);
            }
          else
            {
              /* sqrt(-Inf +i*NaN) = NaN +/-i*Inf */
              mpfr_set_nan (MPC_RE (a));
              mpfr_set_inf (MPC_IM (a), im_sgn);
              return MPC_INEX (0, 0);
            }
        }
      else
        {
          if (mpfr_number_p (MPC_IM (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_RE (a), +1);
              mpfr_set_ui (MPC_IM (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_RE (b)) || mpfr_nan_p (MPC_IM (b)))
    {
      mpfr_set_nan (MPC_RE (a));
      mpfr_set_nan (MPC_IM (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_RE (a), MPC_RE (b), MPC_RND_RE (rnd));
          mpfr_set_ui (MPC_IM (a), 0, GMP_RNDN);
          if (im_sgn)
            mpc_conj (a, a, MPC_RNDNN);
          return MPC_INEX (inex_w, 0);
        }
      else
        {
          mpfr_init2 (w, MPFR_PREC (MPC_RE (b)));
          mpfr_neg (w, MPC_RE (b), GMP_RNDN);
          if (im_sgn)
            {
              inex_w = -mpfr_sqrt (MPC_IM (a), w, INV_RND (MPC_RND_IM (rnd)));
              mpfr_neg (MPC_IM (a), MPC_IM (a), GMP_RNDN);
            }
          else
            inex_w = mpfr_sqrt (MPC_IM (a), w, MPC_RND_IM (rnd));

          mpfr_set_ui (MPC_RE (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_IM (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_RE (a), y, MPC_RND_RE (rnd));
          inex_t = mpfr_sqrt (MPC_IM (a), y, MPC_RND_IM (rnd));
        }
      else
        {
          mpfr_neg (y, y, GMP_RNDN);
          inex_w = mpfr_sqrt (MPC_RE (a), y, MPC_RND_RE (rnd));
          inex_t = -mpfr_sqrt (MPC_IM (a), y, INV_RND (MPC_RND_IM (rnd)));
          mpfr_neg (MPC_IM (a), MPC_IM (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 = MPFR_PREC (MPC_RE (a));
      rnd_t = MPC_RND_IM(rnd);
      prec_t = MPFR_PREC (MPC_IM (a));
    }
  else
    {
      rnd_w = MPC_RND_IM(rnd);
      prec_w = MPFR_PREC (MPC_IM (a));
      rnd_t = MPC_RND_RE(rnd);
      prec_t = MPFR_PREC (MPC_RE (a));
      if (im_cmp < 0)
        {
          rnd_w = INV_RND(rnd_w);
          rnd_t = INV_RND(rnd_t);
        }
    }

  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_RE (b), GMP_RNDD);
      else
        inex_w |= mpfr_add (w, w, MPC_RE (b), GMP_RNDD);
      inex_w |= mpfr_div_2ui (w, w, 1, GMP_RNDD);
      inex_w |= mpfr_sqrt (w, w, GMP_RNDD);

      ok_w = mpfr_can_round (w, (mp_exp_t) prec - 2, GMP_RNDD, GMP_RNDU,
                             prec_w + (rnd_w == GMP_RNDN));
      if (!inex_w || ok_w)
        {
          /* t = y / 2w, rounded away */
          /* total error bounded by 7 ulps */
          const mp_rnd_t r = im_sgn ? GMP_RNDD : GMP_RNDU;
          inex_t  = mpfr_div (t, MPC_IM (b), w, r);
          inex_t |= mpfr_div_2ui (t, t, 1, r);
          ok_t = mpfr_can_round (t, (mp_exp_t) prec - 3, r, GMP_RNDZ,
                                 prec_t + (rnd_t == GMP_RNDN));
          /* As for w; since t was rounded away, we check whether rounding to 0
             is possible. */
        }
    }
    while ((inex_w && !ok_w) || (inex_t && !ok_t));

  if (re_cmp > 0)
      inex = MPC_INEX (mpfr_set (MPC_RE (a), w, MPC_RND_RE(rnd)),
                       mpfr_set (MPC_IM (a), t, MPC_RND_IM(rnd)));
  else if (im_cmp > 0)
      inex = MPC_INEX (mpfr_set (MPC_RE(a), t, MPC_RND_RE(rnd)),
                       mpfr_set (MPC_IM(a), w, MPC_RND_IM(rnd)));
  else
      inex = MPC_INEX (mpfr_neg (MPC_RE (a), t, MPC_RND_RE(rnd)),
                       mpfr_neg (MPC_IM (a), w, MPC_RND_IM(rnd)));

  mpfr_clear (w);
  mpfr_clear (t);

  return inex;
}
Ejemplo n.º 11
0
/* put in rop the value of exp(2*i*pi*k/n) rounded according to rnd */
int
mpc_rootofunity (mpc_ptr rop, unsigned long n, unsigned long k, mpc_rnd_t rnd)
{
   unsigned long g;
   mpq_t kn;
   mpfr_t t, s, c;
   mpfr_prec_t prec;
   int inex_re, inex_im;
   mpfr_rnd_t rnd_re, rnd_im;

   if (n == 0) {
      /* Compute exp (0 + i*inf). */
      mpfr_set_nan (mpc_realref (rop));
      mpfr_set_nan (mpc_imagref (rop));
      return MPC_INEX (0, 0);
   }

   /* Eliminate common denominator. */
   k %= n;
   g = gcd (k, n);
   k /= g;
   n /= g;

   /* Now 0 <= k < n and gcd(k,n)=1. */

   /* We assume that only n=1, 2, 3, 4, 6 and 12 may yield exact results
      and treat them separately; n=8 is also treated here for efficiency
      reasons. */
   if (n == 1)
     {
       /* necessarily k=0 thus we want exp(0)=1 */
       MPC_ASSERT (k == 0);
       return mpc_set_ui_ui (rop, 1, 0, rnd);
     }
   else if (n == 2)
     {
       /* since gcd(k,n)=1, necessarily k=1, thus we want exp(i*pi)=-1 */
       MPC_ASSERT (k == 1);
       return mpc_set_si_si (rop, -1, 0, rnd);
     }
   else if (n == 4)
     {
       /* since gcd(k,n)=1, necessarily k=1 or k=3, thus we want
          exp(2*i*pi/4)=i or exp(2*i*pi*3/4)=-i */
       MPC_ASSERT (k == 1 || k == 3);
       if (k == 1)
         return mpc_set_ui_ui (rop, 0, 1, rnd);
       else
         return mpc_set_si_si (rop, 0, -1, rnd);
     }
   else if (n == 3 || n == 6)
     {
       MPC_ASSERT ((n == 3 && (k == 1 || k == 2)) ||
                   (n == 6 && (k == 1 || k == 5)));
       /* for n=3, necessarily k=1 or k=2: -1/2+/-1/2*sqrt(3)*i;
          for n=6, necessarily k=1 or k=5: 1/2+/-1/2*sqrt(3)*i */
       inex_re = mpfr_set_si (mpc_realref (rop), (n == 3 ? -1 : 1),
                              MPC_RND_RE (rnd));
       /* inverse the rounding mode for -sqrt(3)/2 for zeta_3^2 and zeta_6^5 */
       rnd_im = MPC_RND_IM (rnd);
       if (k != 1)
         rnd_im = INV_RND (rnd_im);
       inex_im = mpfr_sqrt_ui (mpc_imagref (rop), 3, rnd_im);
       mpc_div_2ui (rop, rop, 1, MPC_RNDNN);
       if (k != 1)
         {
           mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), MPFR_RNDN);
           inex_im = -inex_im;
         }
       return MPC_INEX (inex_re, inex_im);
     }
   else if (n == 12)
     {
       /* necessarily k=1, 5, 7, 11:
          k=1: 1/2*sqrt(3) + 1/2*I
          k=5: -1/2*sqrt(3) + 1/2*I
          k=7: -1/2*sqrt(3) - 1/2*I
          k=11: 1/2*sqrt(3) - 1/2*I */
       MPC_ASSERT (k == 1 || k == 5 || k == 7 || k == 11);
       /* inverse the rounding mode for -sqrt(3)/2 for zeta_12^5 and zeta_12^7 */
       rnd_re = MPC_RND_RE (rnd);
       if (k == 5 || k == 7)
         rnd_re = INV_RND (rnd_re);
       inex_re = mpfr_sqrt_ui (mpc_realref (rop), 3, rnd_re);
       inex_im = mpfr_set_si (mpc_imagref (rop), k < 6 ? 1 : -1,
                              MPC_RND_IM (rnd));
       mpc_div_2ui (rop, rop, 1, MPC_RNDNN);
       if (k == 5 || k == 7)
         {
           mpfr_neg (mpc_realref (rop), mpc_realref (rop), MPFR_RNDN);
           inex_re = -inex_re;
         }
       return MPC_INEX (inex_re, inex_im);
     }
   else if (n == 8)
     {
       /* k=1, 3, 5 or 7:
          k=1: (1/2*I + 1/2)*sqrt(2)
          k=3: (1/2*I - 1/2)*sqrt(2)
          k=5: -(1/2*I + 1/2)*sqrt(2)
          k=7: -(1/2*I - 1/2)*sqrt(2) */
       MPC_ASSERT (k == 1 || k == 3 || k == 5 || k == 7);
       rnd_re = MPC_RND_RE (rnd);
       if (k == 3 || k == 5)
         rnd_re = INV_RND (rnd_re);
       rnd_im = MPC_RND_IM (rnd);
       if (k > 4)
         rnd_im = INV_RND (rnd_im);
       inex_re = mpfr_sqrt_ui (mpc_realref (rop), 2, rnd_re);
       inex_im = mpfr_sqrt_ui (mpc_imagref (rop), 2, rnd_im);
       mpc_div_2ui (rop, rop, 1, MPC_RNDNN);
       if (k == 3 || k == 5)
         {
           mpfr_neg (mpc_realref (rop), mpc_realref (rop), MPFR_RNDN);
           inex_re = -inex_re;
         }
       if (k > 4)
         {
           mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), MPFR_RNDN);
           inex_im = -inex_im;
         }
       return MPC_INEX (inex_re, inex_im);
     }

   prec = MPC_MAX_PREC(rop);

   /* For the error analysis justifying the following algorithm,
      see algorithms.tex. */
   mpfr_init2 (t, 67);
   mpfr_init2 (s, 67);
   mpfr_init2 (c, 67);
   mpq_init (kn);
   mpq_set_ui (kn, k, n);
   mpq_mul_2exp (kn, kn, 1); /* kn=2*k/n < 2 */

   do {
      prec += mpc_ceil_log2 (prec) + 5; /* prec >= 6 */

      mpfr_set_prec (t, prec);
      mpfr_set_prec (s, prec);
      mpfr_set_prec (c, prec);

      mpfr_const_pi (t, MPFR_RNDN);
      mpfr_mul_q (t, t, kn, MPFR_RNDN);
      mpfr_sin_cos (s, c, t, MPFR_RNDN);
   }
   while (   !mpfr_can_round (c, prec - (4 - mpfr_get_exp (c)),
                 MPFR_RNDN, MPFR_RNDZ,
                 MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == MPFR_RNDN))
          || !mpfr_can_round (s, prec - (4 - mpfr_get_exp (s)),
                 MPFR_RNDN, MPFR_RNDZ,
                 MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == MPFR_RNDN)));

   inex_re = mpfr_set (mpc_realref(rop), c, MPC_RND_RE(rnd));
   inex_im = mpfr_set (mpc_imagref(rop), s, MPC_RND_IM(rnd));

   mpfr_clear (t);
   mpfr_clear (s);
   mpfr_clear (c);
   mpq_clear (kn);

   return MPC_INEX(inex_re, inex_im);
}
Ejemplo n.º 12
0
/* 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, y_real, z_real = 0, z_imag = 0;
  mpc_t t, u;
  mp_prec_t p, q, pr, pi, maxprec;
  long Q;

  x_real = mpfr_zero_p (MPC_IM(x));
  y_real = mpfr_zero_p (MPC_IM(y));

  if (y_real && mpfr_zero_p (MPC_RE(y))) /* case y zero */
    {
      if (x_real && mpfr_zero_p (MPC_RE(x))) /* 0^0 = NaN +i*NaN */
        {
          mpfr_set_nan (MPC_RE(z));
          mpfr_set_nan (MPC_IM(z));
          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_IM (y)) == 0)
            || (cx1 == 0
                && mpfr_signbit (MPC_IM (x)) != mpfr_signbit (MPC_RE (y)))
            || (cx1 > 0 && mpfr_signbit (MPC_IM (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 (mpfr_nan_p (MPC_RE(x)) || mpfr_nan_p (MPC_IM(x)) ||
      mpfr_nan_p (MPC_RE(y)) || mpfr_nan_p (MPC_IM(y)) ||
      mpfr_inf_p (MPC_RE(x)) || mpfr_inf_p (MPC_IM(x)) ||
      mpfr_inf_p (MPC_RE(y)) || mpfr_inf_p (MPC_IM(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_RE(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_RE(x), 1) == 0)
        {
          int s1, s2;
          s1 = mpfr_signbit (MPC_RE (y));
          s2 = mpfr_signbit (MPC_IM (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_RE(y)) ||
                     mpfr_cmp_ui (MPC_RE(x), 0) >= 0))
        {
          int s1, s2;
          s1 = mpfr_signbit (MPC_RE (y));
          s2 = mpfr_signbit (MPC_IM (x));

          ret = mpfr_pow (MPC_RE(z), MPC_RE(x), MPC_RE(y), MPC_RND_RE(rnd));
          ret = MPC_INEX(ret, mpfr_set_ui (MPC_IM(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_IM(z), MPC_IM(z), MPC_RND_IM(rnd));
          goto end;
        }

      /* (-1)^(n+I*t) is real for n integer and t real */
      if (mpfr_cmp_si (MPC_RE(x), -1) == 0 && mpfr_integer_p (MPC_RE(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_RE(x), 0) < 0 && is_odd (MPC_RE(y), 1) &&
          (y_real || mpfr_cmp_si (MPC_RE(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_RE(x), 0) == 0 && y_real)) &&
        mpfr_integer_p (MPC_RE(y)))
      { /* x is I or -I, and Re(y) is an integer */
        if (is_odd (MPC_RE(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_RE(x), MPC_IM(x)) == 0 && y_real &&
          mpfr_integer_p (MPC_RE(y)) && is_odd (MPC_RE(y), 0) == 0)
        {
          if (is_odd (MPC_RE(y), -1)) /* y/2 is odd */
            z_imag = 1;
          else
            z_real = 1;
        }

  /* first bound |Re(y log(x))|, |Im(y log(x)| < 2^q */
  mpc_init2 (t, 64);
  mpc_log (t, x, MPC_RNDNN);
  mpc_mul (t, t, y, MPC_RNDNN);

  /* the default maximum exponent for MPFR is emax=2^30-1, thus if
     t > log(2^emax) = emax*log(2), then exp(t) will overflow */
  if (mpfr_cmp_ui_2exp (MPC_RE(t), 372130558, 1) > 0)
    goto overflow;

  /* the default minimum exponent for MPFR is emin=-2^30+1, thus the
     smallest representable value is 2^(emin-1), and if
     t < log(2^(emin-1)) = (emin-1)*log(2), then exp(t) will underflow */
  if (mpfr_cmp_si_2exp (MPC_RE(t), -372130558, 1) < 0)
    goto underflow;

  q = mpfr_get_exp (MPC_RE(t)) > 0 ? mpfr_get_exp (MPC_RE(t)) : 0;
  if (mpfr_get_exp (MPC_IM(t)) > (mp_exp_t) q)
    q = mpfr_get_exp (MPC_IM(t));

  pr = mpfr_get_prec (MPC_RE(z));
  pi = mpfr_get_prec (MPC_IM(z));
  p = (pr > pi) ? pr : pi;
  p += 11; /* experimentally, seems to give less than 10% of failures in
              Ziv's strategy */
  mpc_init2 (u, p);
  pr += MPC_RND_RE(rnd) == GMP_RNDN;
  pi += MPC_RND_IM(rnd) == GMP_RNDN;
  maxprec = MPFR_PREC(MPC_RE(z));
  if (MPFR_PREC(MPC_IM(z)) > maxprec)
    maxprec = MPFR_PREC(MPC_IM(z));
  for (loop = 0;; loop++)
    {
      mp_exp_t dr, di;

      if (p + q > 64) /* otherwise we reuse the initial approximation
                         t of y*log(x), avoiding two computations */
        {
          mpc_set_prec (t, p + q);
          mpc_log (t, x, MPC_RNDNN);
          mpc_mul (t, t, y, MPC_RNDNN);
        }
      mpc_exp (u, t, MPC_RNDNN);
      /* 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_RE(u)) ? mpfr_get_exp (MPC_IM(u))
        : mpfr_get_exp (MPC_RE(u));
      di = mpfr_zero_p (MPC_IM(u)) ? dr : mpfr_get_exp (MPC_IM(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 || mpfr_can_round (MPC_RE(u), p - 3 - dr, GMP_RNDN, GMP_RNDZ, pr)) &&
          (z_real || mpfr_can_round (MPC_IM(u), p - 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_RE(u)));
      /* idem for Im(u) */
      MPC_ASSERT (z_real || mpfr_number_p (MPC_IM(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_RE(y), rnd, maxprec);
              if (ret != -1 && ret != -2)
                goto exact;
            }
          p += dr + di + 64;
        }
      else
        p += p / 2;
      mpc_set_prec (t, p + q);
      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;
      /* 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_IM (y)) == 0)
        || (cx1 == 0
            && mpfr_signbit (MPC_IM (x)) != mpfr_signbit (MPC_RE (y)))
        || (cx1 > 0 && mpfr_signbit (MPC_IM (y)));

      ret = mpfr_set (MPC_RE(z), MPC_RE(u), MPC_RND_RE(rnd));
      /* warning: mpfr_set_ui does not set Im(z) to -0 if Im(rnd) = RNDD */
      ret = MPC_INEX (ret, mpfr_set_ui (MPC_IM (z), 0, MPC_RND_IM (rnd)));

      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_IM(z), MPC_IM(u), MPC_RND_IM(rnd));
      ret = MPC_INEX(mpfr_set_ui (MPC_RE(z), 0, MPC_RND_RE(rnd)), ret);
    }
  else
    ret = mpc_set (z, u, rnd);
 exact:
  mpc_clear (t);
  mpc_clear (u);

 end:
  return ret;

 underflow:
  /* If we have an underflow, we know that |z| is too small to be
     represented, but depending on arg(z), we should return +/-0 +/- I*0.
     We assume t is the approximation of y*log(x), thus we want
     exp(t) = exp(Re(t))+exp(I*Im(t)).
     FIXME: this part of code is not 100% rigorous, since we don't consider
     rounding errors.
  */
  mpc_init2 (u, 64);
  mpfr_const_pi (MPC_RE(u), GMP_RNDN);
  mpfr_div_2exp (MPC_RE(u), MPC_RE(u), 1, GMP_RNDN); /* Pi/2 */
  mpfr_remquo (MPC_RE(u), &Q, MPC_IM(t), MPC_RE(u), GMP_RNDN);
  if (mpfr_sgn (MPC_RE(u)) < 0)
    Q--; /* corresponds to positive remainder */
  mpfr_set_ui (MPC_RE(z), 0, GMP_RNDN);
  mpfr_set_ui (MPC_IM(z), 0, GMP_RNDN);
  switch (Q & 3)
    {
    case 0: /* first quadrant: round to (+0 +0) */
      ret = MPC_INEX(-1, -1);
      break;
    case 1: /* second quadrant: round to (-0 +0) */
      mpfr_neg (MPC_RE(z), MPC_RE(z), GMP_RNDN);
      ret = MPC_INEX(1, -1);
      break;
    case 2: /* third quadrant: round to (-0 -0) */
      mpfr_neg (MPC_RE(z), MPC_RE(z), GMP_RNDN);
      mpfr_neg (MPC_IM(z), MPC_IM(z), GMP_RNDN);
      ret = MPC_INEX(1, 1);
      break;
    case 3: /* fourth quadrant: round to (+0 -0) */
      mpfr_neg (MPC_IM(z), MPC_IM(z), GMP_RNDN);
      ret = MPC_INEX(-1, 1);
      break;
    }
  goto clear_t_and_u;

 overflow:
  /* If we have an overflow, we know that |z| is too large to be
     represented, but depending on arg(z), we should return +/-Inf +/- I*Inf.
     We assume t is the approximation of y*log(x), thus we want
     exp(t) = exp(Re(t))+exp(I*Im(t)).
     FIXME: this part of code is not 100% rigorous, since we don't consider
     rounding errors.
  */
  mpc_init2 (u, 64);
  mpfr_const_pi (MPC_RE(u), GMP_RNDN);
  mpfr_div_2exp (MPC_RE(u), MPC_RE(u), 1, GMP_RNDN); /* Pi/2 */
  /* the quotient is rounded to the nearest integer in mpfr_remquo */
  mpfr_remquo (MPC_RE(u), &Q, MPC_IM(t), MPC_RE(u), GMP_RNDN);
  if (mpfr_sgn (MPC_RE(u)) < 0)
    Q--; /* corresponds to positive remainder */
  switch (Q & 3)
    {
    case 0: /* first quadrant */
      mpfr_set_inf (MPC_RE(z), 1);
      mpfr_set_inf (MPC_IM(z), 1);
      ret = MPC_INEX(1, 1);
      break;
    case 1: /* second quadrant */
      mpfr_set_inf (MPC_RE(z), -1);
      mpfr_set_inf (MPC_IM(z), 1);
      ret = MPC_INEX(-1, 1);
      break;
    case 2: /* third quadrant */
      mpfr_set_inf (MPC_RE(z), -1);
      mpfr_set_inf (MPC_IM(z), -1);
      ret = MPC_INEX(-1, -1);
      break;
    case 3: /* fourth quadrant */
      mpfr_set_inf (MPC_RE(z), 1);
      mpfr_set_inf (MPC_IM(z), -1);
      ret = MPC_INEX(1, -1);
      break;
    }

 clear_t_and_u:
  mpc_clear (t);
  mpc_clear (u);
  return ret;
}
Ejemplo n.º 13
0
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);
}
static void
check_set (void)
{
  long int lo;
  mpz_t mpz;
  mpq_t mpq;
  mpf_t mpf;
  mpfr_t fr;
  mpc_t x, z;
  mpfr_prec_t prec;

  mpz_init (mpz);
  mpq_init (mpq);
  mpf_init2 (mpf, 1000);
  mpfr_init2 (fr, 1000);
  mpc_init2 (x, 1000);
  mpc_init2 (z, 1000);

  mpz_set_ui (mpz, 0x4217);
  mpq_set_si (mpq, -1, 0x4321);
  mpf_set_q (mpf, mpq);

  for (prec = 2; prec <= 1000; prec++)
    {
      unsigned long int u = (unsigned long int) prec;

      mpc_set_prec (z, prec);
      mpfr_set_prec (fr, prec);

      lo = -prec;

      mpfr_set_d (fr, 1.23456789, GMP_RNDN);

      mpc_set_d (z, 1.23456789, MPC_RNDNN);
      if (mpfr_cmp (MPC_RE(z), fr) != 0 || mpfr_cmp_si (MPC_IM(z), 0) != 0)
        PRINT_ERROR ("mpc_set_d", prec, z);

#if defined _MPC_H_HAVE_COMPLEX
      mpc_set_dc (z, I*1.23456789+1.23456789, MPC_RNDNN);
      if (mpfr_cmp (MPC_RE(z), fr) != 0 || mpfr_cmp (MPC_IM(z), fr) != 0)
        PRINT_ERROR ("mpc_set_c", prec, z);
#endif

      mpc_set_ui (z, u, MPC_RNDNN);
      if (mpfr_cmp_ui (MPC_RE(z), u) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0)
        PRINT_ERROR ("mpc_set_ui", prec, z);

      mpc_set_d_d (z, 1.23456789, 1.23456789, MPC_RNDNN);
      if (mpfr_cmp (MPC_RE(z), fr) != 0 || mpfr_cmp (MPC_IM(z), fr) != 0)
        PRINT_ERROR ("mpc_set_d_d", prec, z);

      mpc_set_si (z, lo, MPC_RNDNN);
      if (mpfr_cmp_si (MPC_RE(z), lo) != 0 || mpfr_cmp_ui (MPC_IM(z), 0) != 0)
        PRINT_ERROR ("mpc_set_si", prec, z);

      mpfr_set_ld (fr, 1.23456789L, GMP_RNDN);

      mpc_set_ld_ld (z, 1.23456789L, 1.23456789L, MPC_RNDNN);
      if (mpfr_cmp (MPC_RE(z), fr) != 0 || mpfr_cmp (MPC_IM(z), fr) != 0)
        PRINT_ERROR ("mpc_set_ld_ld", prec, z);

#if defined _MPC_H_HAVE_COMPLEX
      mpc_set_ldc (z, I*1.23456789L+1.23456789L, MPC_RNDNN);
      if (mpfr_cmp (MPC_RE(z), fr) != 0 || mpfr_cmp (MPC_IM(z), fr) != 0)
        PRINT_ERROR ("mpc_set_lc", prec, z);
#endif
      mpc_set_ui_ui (z, u, u, MPC_RNDNN);
      if (mpfr_cmp_ui (MPC_RE(z), u) != 0
          || mpfr_cmp_ui (MPC_IM(z), u) != 0)
        PRINT_ERROR ("mpc_set_ui_ui", prec, z);

      mpc_set_ld (z, 1.23456789L, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_ld", prec, z);

      mpc_set_prec (x, prec);
      mpfr_set_ui(fr, 1, GMP_RNDN);
      mpfr_div_ui(fr, fr, 3, GMP_RNDN);
      mpfr_set(MPC_RE(x), fr, GMP_RNDN);
      mpfr_set(MPC_IM(x), fr, GMP_RNDN);

      mpc_set (z, x, MPC_RNDNN);
      mpfr_clear_flags (); /* mpc_cmp set erange flag when an operand is a
                              NaN */
      if (mpc_cmp (z, x) != 0 || mpfr_erangeflag_p())
        {
          printf ("Error in mpc_set for prec = %lu\n",
                  (unsigned long int) prec);
          MPC_OUT(z);
          MPC_OUT(x);
          exit (1);
        }

      mpc_set_si_si (z, lo, lo, MPC_RNDNN);
      if (mpfr_cmp_si (MPC_RE(z), lo) != 0
          || mpfr_cmp_si (MPC_IM(z), lo) != 0)
        PRINT_ERROR ("mpc_set_si_si", prec, z);

      mpc_set_fr (z, fr, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_fr", prec, z);

      mpfr_set_z (fr, mpz, GMP_RNDN);
      mpc_set_z_z (z, mpz, mpz, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp (MPC_IM(z), fr) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_z_z", prec, z);

      mpc_set_fr_fr (z, fr, fr, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp (MPC_IM(z), fr) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_fr_fr", prec, z);

      mpc_set_z (z, mpz, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_z", prec, z);

      mpfr_set_q (fr, mpq, GMP_RNDN);
      mpc_set_q_q (z, mpq, mpq, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp (MPC_IM(z), fr) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_q_q", prec, z);

      mpc_set_ui_fr (z, u, fr, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp_ui (MPC_RE (z), u) != 0
          || mpfr_cmp (MPC_IM (z), fr) != 0
          || mpfr_erangeflag_p ())
        PRINT_ERROR ("mpc_set_ui_fr", prec, z);

      mpc_set_fr_ui (z, fr, u, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE (z), fr) != 0
          || mpfr_cmp_ui (MPC_IM (z), u) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_fr_ui", prec, z);

      mpc_set_q (z, mpq, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_q", prec, z);

      mpfr_set_f (fr, mpf, GMP_RNDN);
      mpc_set_f_f (z, mpf, mpf, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp (MPC_IM(z), fr) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_f_f", prec, z);

      mpc_set_f (z, mpf, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE(z), fr) != 0
          || mpfr_cmp_ui (MPC_IM(z), 0) != 0
          || mpfr_erangeflag_p())
        PRINT_ERROR ("mpc_set_f", prec, z);

      mpc_set_f_si (z, mpf, lo, MPC_RNDNN);
      mpfr_clear_flags ();
      if (mpfr_cmp (MPC_RE (z), fr) != 0
          || mpfr_cmp_si (MPC_IM (z), lo) != 0
          || mpfr_erangeflag_p ())
        PRINT_ERROR ("mpc_set_f", prec, z);

      mpc_set_nan (z);
      if (!mpfr_nan_p (MPC_RE(z)) || !mpfr_nan_p (MPC_IM(z)))
        PRINT_ERROR ("mpc_set_nan", prec, z);

#ifdef _MPC_H_HAVE_INTMAX_T
      {
        uintmax_t uim = (uintmax_t) prec;
        intmax_t im = (intmax_t) prec;

        mpc_set_uj (z, uim, MPC_RNDNN);
        if (mpfr_cmp_ui (MPC_RE(z), u) != 0
            || mpfr_cmp_ui (MPC_IM(z), 0) != 0)
          PRINT_ERROR ("mpc_set_uj", prec, z);

        mpc_set_sj (z, im, MPC_RNDNN);
        if (mpfr_cmp_ui (MPC_RE(z), u) != 0
            || mpfr_cmp_ui (MPC_IM(z), 0) != 0)
          PRINT_ERROR ("mpc_set_sj (1)", prec, z);

        mpc_set_uj_uj (z, uim, uim, MPC_RNDNN);
        if (mpfr_cmp_ui (MPC_RE(z), u) != 0
            || mpfr_cmp_ui (MPC_IM(z), u) != 0)
          PRINT_ERROR ("mpc_set_uj_uj", prec, z);

        mpc_set_sj_sj (z, im, im, MPC_RNDNN);
        if (mpfr_cmp_ui (MPC_RE(z), u) != 0
            || mpfr_cmp_ui (MPC_IM(z), u) != 0)
          PRINT_ERROR ("mpc_set_sj_sj (1)", prec, z);

        im = LONG_MAX;
        if (sizeof (intmax_t) == 2 * sizeof (unsigned long))
          im = 2 * im * im + 4 * im + 1; /* gives 2^(2n-1)-1 from 2^(n-1)-1 */

        mpc_set_sj (z, im, MPC_RNDNN);
        if (mpfr_get_sj (MPC_RE(z), GMP_RNDN) != im ||
            mpfr_cmp_ui (MPC_IM(z), 0) != 0)
          PRINT_ERROR ("mpc_set_sj (2)", im, z);

        mpc_set_sj_sj (z, im, im, MPC_RNDNN);
        if (mpfr_get_sj (MPC_RE(z), GMP_RNDN) != im ||
            mpfr_get_sj (MPC_IM(z), GMP_RNDN) != im)
          PRINT_ERROR ("mpc_set_sj_sj (2)", im, z);
      }
#endif /* _MPC_H_HAVE_INTMAX_T */

#if defined _MPC_H_HAVE_COMPLEX
      {
         double _Complex c = 1.0 - 2.0*I;
         long double _Complex lc = c;

         mpc_set_dc (z, c, MPC_RNDNN);
         if (mpc_get_dc (z, MPC_RNDNN) != c)
            PRINT_ERROR ("mpc_get_c", prec, z);
         mpc_set_ldc (z, lc, MPC_RNDNN);
         if (mpc_get_ldc (z, MPC_RNDNN) != lc)
            PRINT_ERROR ("mpc_get_lc", prec, z);
      }
#endif
    }

  mpz_clear (mpz);
  mpq_clear (mpq);
  mpf_clear (mpf);
  mpfr_clear (fr);
  mpc_clear (x);
  mpc_clear (z);
}