Beispiel #1
0
void
mpc_swap (mpc_ptr a, mpc_ptr b)
{
  /* assumes real and imaginary parts do not overlap */
  mpfr_swap (MPC_RE(a), MPC_RE(b));
  mpfr_swap (MPC_IM(a), MPC_IM(b));
}
Beispiel #2
0
int
mpc_asinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  /* asinh(op) = -i*asin(i*op) */
  int inex;
  mpc_t z, a;
  mpfr_t tmp;

  /* z = i*op */
  MPC_RE (z)[0] = MPC_IM (op)[0];
  MPC_IM (z)[0] = MPC_RE (op)[0];
  MPFR_CHANGE_SIGN (MPC_RE (z));

  /* Note reversal of precisions due to later multiplication by -i */
  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));

  inex = mpc_asin (a, z,
                   RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));

  /* if a = asin(i*op) = x+i*y, and we want y-i*x */

  /* change a to -i*a */
  tmp[0] = MPC_RE (a)[0];
  MPC_RE (a)[0] = MPC_IM (a)[0];
  MPC_IM (a)[0] = tmp[0];
  MPFR_CHANGE_SIGN (MPC_IM (a));

  mpc_set (rop, a, MPC_RNDNN);   /* exact */

  mpc_clear (a);

  return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
}
Beispiel #3
0
int
mpc_atanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  /* atanh(op) = -i*atan(i*op) */
  int inex;
  mpfr_t tmp;
  mpc_t z, a;

  MPC_RE (z)[0] = MPC_IM (op)[0];
  MPC_IM (z)[0] = MPC_RE (op)[0];
  MPFR_CHANGE_SIGN (MPC_RE (z));

  /* Note reversal of precisions due to later multiplication by -i */
  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));

  inex = mpc_atan (a, z,
                   RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));

  /* change a to -i*a, i.e., x+i*y to y-i*x */
  tmp[0] = MPC_RE (a)[0];
  MPC_RE (a)[0] = MPC_IM (a)[0];
  MPC_IM (a)[0] = tmp[0];
  MPFR_CHANGE_SIGN (MPC_IM (a));

  mpc_set (rop, a, rnd);

  mpc_clear (a);

  return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
}
Beispiel #4
0
static void
check_different_precisions()
{
  /* check reuse when real and imaginary part have different precisions. */
  mpc_t z, expected, got;  
  int res;

  mpc_init2(z, 128);
  mpc_init2(expected, 128);
  mpc_init2(got, 128);

  /* change precision of one part */
  mpfr_set_prec (MPC_IM (z), 32);
  mpfr_set_prec (MPC_IM (expected), 32);
  mpfr_set_prec (MPC_IM (got), 32);

  mpfr_set_str (MPC_RE (z), "0x100000000fp-32", 16, GMP_RNDN);
  mpfr_set_str (MPC_IM (z), "-1", 2, GMP_RNDN);
  mpfr_set_str (MPC_RE (expected), "+1", 2, GMP_RNDN);
  mpfr_set_str (MPC_IM (expected), "0x100000000fp-32", 16, GMP_RNDN);

  mpc_set (got, z, MPC_RNDNN);
  res = mpc_mul_i (got, got, +1, MPC_RNDNN);
  if (MPC_INEX_RE(res) != 0 || MPC_INEX_IM(res) >=0)
    {
      printf("Wrong inexact flag for mpc_mul_i(z, z, n)\n"
             "     got (re=%2d, im=%2d)\nexpected (re= 0, im=-1)\n",
             MPC_INEX_RE(res), MPC_INEX_IM(res));
      exit(1);
    }
  if (mpc_cmp(got, expected) != 0)
    {
      printf ("Error for mpc_mul_i(z, z, n) for\n");
      OUT (z);
      printf ("n=+1\n");
      OUT (expected);
      OUT (got);

      exit (1);
    }

  mpc_neg (expected, expected, MPC_RNDNN);
  mpc_set (got, z, MPC_RNDNN);
  mpc_mul_i (got, got, -1, MPC_RNDNN);
  if (mpc_cmp(got, expected) != 0)
    {
      printf ("Error for mpc_mul_i(z, z, n) for\n");
      OUT (z);
      printf ("n=-1\n");
      OUT (expected);
      OUT (got);

      exit (1);
    }

  mpc_clear (z);
  mpc_clear (expected);
  mpc_clear (got);
}
static int
mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* assumes that op is real */
{
   int inex_sin_re = 0, inex_cos_re = 0;
      /* Until further notice, assume computations exact; in particular,
         by definition, for not computed values.                         */
   mpfr_t s, c;
   int inex_s, inex_c;
   int sign_im_op = mpfr_signbit (MPC_IM (op));

   /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */
   /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */
   if (rop_sin != 0)
      mpfr_init2 (s, MPC_PREC_RE (rop_sin));
   else
      mpfr_init2 (s, 2); /* We need only the sign. */
   if (rop_cos != NULL)
      mpfr_init2 (c, MPC_PREC_RE (rop_cos));
   else
      mpfr_init2 (c, 2);
   inex_s = mpfr_sin (s, MPC_RE (op), MPC_RND_RE (rnd_sin));
   inex_c = mpfr_cos (c, MPC_RE (op), MPC_RND_RE (rnd_cos));
      /* We cannot use mpfr_sin_cos since we may need two distinct rounding
         modes and the exact return values. If we need only the sign, an
         arbitrary rounding mode will work.                                 */

   if (rop_sin != NULL) {
      mpfr_set (MPC_RE (rop_sin), s, GMP_RNDN); /* exact */
      inex_sin_re = inex_s;
      mpfr_set_ui (MPC_IM (rop_sin), 0ul, GMP_RNDN);
      if (   ( sign_im_op && !mpfr_signbit (c))
          || (!sign_im_op &&  mpfr_signbit (c)))
         MPFR_CHANGE_SIGN (MPC_IM (rop_sin));
      /* FIXME: simpler implementation with mpfr-3:
         mpfr_set_zero (MPC_IM (rop_sin),
            (   ( mpfr_signbit (MPC_IM(op)) && !mpfr_signbit(c))
             || (!mpfr_signbit (MPC_IM(op)) &&  mpfr_signbit(c)) ? -1 : 1);
         there is no need to use the variable sign_im_op then, needed now in
         the case rop_sin == op                                              */
   }

   if (rop_cos != NULL) {
      mpfr_set (MPC_RE (rop_cos), c, GMP_RNDN); /* exact */
      inex_cos_re = inex_c;
      mpfr_set_ui (MPC_IM (rop_cos), 0ul, GMP_RNDN);
      if (   ( sign_im_op &&  mpfr_signbit (s))
          || (!sign_im_op && !mpfr_signbit (s)))
         MPFR_CHANGE_SIGN (MPC_IM (rop_cos));
      /* FIXME: see previous MPFR_CHANGE_SIGN */
   }

   mpfr_clear (s);
   mpfr_clear (c);

   return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
}
int
mpc_neg (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
{
  int inex_re, inex_im;

  inex_re = mpfr_neg (MPC_RE(a), MPC_RE(b), MPC_RND_RE(rnd));
  inex_im = mpfr_neg (MPC_IM(a), MPC_IM(b), MPC_RND_IM(rnd));

  return MPC_INEX(inex_re, inex_im);
}
Beispiel #7
0
int
mpc_mul_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
{
  int inex_re, inex_im;

  inex_re = mpfr_mul_ui (MPC_RE(a), MPC_RE(b), c, MPC_RND_RE(rnd));
  inex_im = mpfr_mul_ui (MPC_IM(a), MPC_IM(b), c, MPC_RND_IM(rnd));

  return MPC_INEX(inex_re, inex_im);
}
/* return 0 iff both the real and imaginary parts are exact */
int
mpc_add_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
{
  int inex_re, inex_im;

  inex_re = mpfr_add (MPC_RE(a), MPC_RE(b), c, MPC_RND_RE(rnd));
  inex_im = mpfr_set (MPC_IM(a), MPC_IM(b), MPC_RND_IM(rnd));

  return MPC_INEX(inex_re, inex_im);
}
Beispiel #9
0
int
mpc_cosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  /* cosh(op) = cos(i*op) */
  mpc_t z;

  /* z = i*op without copying significand */
  MPC_RE (z)[0] = MPC_IM (op)[0];
  MPC_IM (z)[0] = MPC_RE (op)[0];
  MPFR_CHANGE_SIGN (MPC_RE (z));

  return mpc_cos (rop, z, rnd);
}
Beispiel #10
0
char *
mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd)
{
  size_t needed_size;
  char *real_str;
  char *imag_str;
  char *complex_str = NULL;

  if (base < 2 || base > 36)
    return NULL;

  real_str = get_pretty_str (base, n, MPC_RE (op), MPC_RND_RE (rnd));
  imag_str = get_pretty_str (base, n, MPC_IM (op), MPC_RND_IM (rnd));

  needed_size = strlen (real_str) + strlen (imag_str) + 4;

  complex_str = mpc_alloc_str (needed_size);
MPC_ASSERT (complex_str != NULL);

  strcpy (complex_str, "(");
  strcat (complex_str, real_str);
  strcat (complex_str, " ");
  strcat (complex_str, imag_str);
  strcat (complex_str, ")");

  mpc_free_str (real_str);
  mpc_free_str (imag_str);

  return complex_str;
}
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);
}
static int
mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* assumes that op is purely imaginary */
{
   int inex_sin_im = 0, inex_cos_re = 0;
      /* assume exact if not computed */
   int overlap;
   mpc_t op_loc;

   overlap = (rop_sin == op || rop_cos == op);
   if (overlap) {
      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
      mpc_set (op_loc, op, MPC_RNDNN);
   }
   else
      op_loc [0] = op [0];

   if (rop_sin != NULL) {
      /* sin(+-O +i*y) = +-0 +i*sinh(y) */
      mpfr_set (MPC_RE(rop_sin), MPC_RE(op_loc), GMP_RNDN);
      inex_sin_im = mpfr_sinh (MPC_IM(rop_sin), MPC_IM(op_loc), MPC_RND_IM(rnd_sin));
   }

   if (rop_cos != NULL) {
      /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0,
         cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
         where y >= 0 */

      if (mpfr_zero_p (MPC_IM (op_loc)))
        inex_cos_re = mpfr_set_ui (MPC_RE (rop_cos), 1ul, MPC_RND_RE (rnd_cos));
      else
        inex_cos_re = mpfr_cosh (MPC_RE (rop_cos), MPC_IM (op_loc), MPC_RND_RE (rnd_cos));

      mpfr_set_ui (MPC_IM (rop_cos), 0ul, MPC_RND_IM (rnd_cos));
      if (mpfr_signbit (MPC_RE (op_loc)) ==  mpfr_signbit (MPC_IM (op_loc)))
         MPFR_CHANGE_SIGN (MPC_IM (rop_cos));
   }

   if (overlap)
      mpc_clear (op_loc);

   return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0));
}
Beispiel #13
0
/* the rounding mode is mpfr_rnd_t here since we return an mpfr number */
int
mpc_norm (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
{
    mpfr_t u, v;
    mp_prec_t prec;
    int inexact, overflow;

    prec = MPFR_PREC(a);

    /* handling of special values; consistent with abs in that
       norm = abs^2; so norm (+-inf, nan) = norm (nan, +-inf) = +inf */
    if (   (mpfr_nan_p (MPC_RE (b)) || mpfr_nan_p (MPC_IM (b)))
            || (mpfr_inf_p (MPC_RE (b)) || mpfr_inf_p (MPC_IM (b))))
        return mpc_abs (a, b, rnd);

    mpfr_init (u);
    mpfr_init (v);

    if (!mpfr_zero_p(MPC_RE(b)) && !mpfr_zero_p(MPC_IM(b)) &&
            2 * SAFE_ABS (mp_exp_t, MPFR_EXP (MPC_RE (b)) - MPFR_EXP (MPC_IM (b)))
            > (mp_exp_t)prec)
        /* If real and imaginary part have very different magnitudes, then the */
        /* generic code increases the precision too much. Instead, compute the */
        /* squarings _exactly_.                                                */
    {
        mpfr_set_prec (u, 2 * MPFR_PREC (MPC_RE (b)));
        mpfr_set_prec (v, 2 * MPFR_PREC (MPC_IM (b)));
        mpfr_sqr (u, MPC_RE (b), GMP_RNDN);
        mpfr_sqr (v, MPC_IM (b), GMP_RNDN);
        inexact = mpfr_add (a, u, v, rnd);
    }
    else
    {
        do
        {
            prec += mpc_ceil_log2 (prec) + 3;

            mpfr_set_prec (u, prec);
            mpfr_set_prec (v, prec);

            inexact = mpfr_sqr (u, MPC_RE(b), GMP_RNDN);  /* err<=1/2ulp */
            inexact |= mpfr_sqr (v, MPC_IM(b), GMP_RNDN); /* err<=1/2ulp*/
            inexact |= mpfr_add (u, u, v, GMP_RNDN);      /* err <= 3/2 ulps */

            overflow = mpfr_inf_p (u);
        }
        while (!overflow && inexact &&
                mpfr_can_round (u, prec - 2, GMP_RNDN, rnd, MPFR_PREC(a)) == 0);

        inexact |= mpfr_set (a, u, rnd);
    }
    mpfr_clear (u);
    mpfr_clear (v);

    return inexact;
}
Beispiel #14
0
int
mpc_acosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  /* acosh(z) =
      NaN + i*NaN, if z=0+i*NaN
     -i*acos(z), if sign(Im(z)) = -
      i*acos(z), if sign(Im(z)) = +
      http://functions.wolfram.com/ElementaryFunctions/ArcCosh/27/02/03/01/01/
  */
  mpc_t a;
  mpfr_t tmp;
  int inex;

  if (mpfr_zero_p (MPC_RE (op)) && mpfr_nan_p (MPC_IM (op)))
    {
      mpfr_set_nan (MPC_RE (rop));
      mpfr_set_nan (MPC_IM (rop));
      return 0;
    }
  
  /* Note reversal of precisions due to later multiplication by i or -i */
  mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));

  if (mpfr_signbit (MPC_IM (op)))
    {
      inex = mpc_acos (a, op,
                       RNDC (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));

      /* change a to -i*a, i.e., -y+i*x to x+i*y */
      tmp[0] = MPC_RE (a)[0];
      MPC_RE (a)[0] = MPC_IM (a)[0];
      MPC_IM (a)[0] = tmp[0];
      MPFR_CHANGE_SIGN (MPC_IM (a));
      inex = MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
    }
  else
    {
      inex = mpc_acos (a, op,
                       RNDC (MPC_RND_IM (rnd), INV_RND(MPC_RND_RE (rnd))));

      /* change a to i*a, i.e., y-i*x to x+i*y */
      tmp[0] = MPC_RE (a)[0];
      MPC_RE (a)[0] = MPC_IM (a)[0];
      MPC_IM (a)[0] = tmp[0];
      MPFR_CHANGE_SIGN (MPC_RE (a));
      inex = MPC_INEX (-MPC_INEX_IM (inex), MPC_INEX_RE (inex));
    }

  mpc_set (rop, a, rnd);

  mpc_clear (a);

  return inex;
}
int
mpc_pow_fr (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd)
{
  mpc_t yy;
  int inex;

  /* avoid copying the significand of y by copying only the struct */
  MPC_RE(yy)[0] = y[0];
  mpfr_init2 (MPC_IM(yy), MPFR_PREC_MIN);
  mpfr_set_ui (MPC_IM(yy), 0, GMP_RNDN);
  inex = mpc_pow (z, x, yy, rnd);
  mpfr_clear (MPC_IM(yy));
  return inex;
}
Beispiel #16
0
size_t
mpc_out_str (FILE *stream, int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd) {
    size_t size = 3; /* for '(', ' ' and ')' */

    if (stream == NULL)
        stream = stdout; /* fprintf does not allow NULL as first argument */

    fprintf (stream, "(");
    size += mpfr_out_str (stream, base, n, MPC_RE(op), MPC_RND_RE(rnd));
    fprintf (stream, " ");
    size += mpfr_out_str (stream, base, n, MPC_IM(op), MPC_RND_RE(rnd));
    fprintf (stream, ")");

    return size;
}
Beispiel #17
0
int
main (void)
{
  mpc_t z, x;
  mp_prec_t prec;

  test_start ();

  mpc_init2 (z, 1000);
  mpc_init2 (x, 1000);

  check_file ("inp_str.dat");

  for (prec = 2; prec <= 1000; prec+=7)
    {
      mpc_set_prec (z, prec);
      mpc_set_prec (x, prec);

      mpc_set_si_si (x, 1, 1, MPC_RNDNN);
      check_io_str (z, x);

      mpc_set_si_si (x, -1, 1, MPC_RNDNN);
      check_io_str (z, x);

      mpfr_set_inf (MPC_RE(x), -1);
      mpfr_set_inf (MPC_IM(x), +1);
      check_io_str (z, x);

      test_default_random (x,  -1024, 1024, 128, 25);
      check_io_str (z, x);
    }

#ifndef NO_STREAM_REDIRECTION
  mpc_set_si_si (x, 1, -4, MPC_RNDNN);
  mpc_div_ui (x, x, 3, MPC_RNDDU);

  check_stdout(z, x);
#endif

  mpc_clear (z);
  mpc_clear (x);

  test_end ();

  return 0;
}
Beispiel #18
0
int
mpc_fr_div (mpc_ptr a, mpfr_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
{
   mpc_t bc;
   int inexact;

   MPC_RE (bc)[0] = b [0];
   mpfr_init (MPC_IM (bc));
   /* we consider the operand b to have imaginary part +0 */
   mpfr_set_ui (MPC_IM (bc), 0, GMP_RNDN);

   inexact = mpc_div (a, bc, c, rnd);

   mpfr_clear (MPC_IM (bc));

   return inexact;
}
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);
}
int
mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base,
mpc_rnd_t rnd_mode)
{
   size_t white, nread = 0;
   int inex = -1;
   int c;
   char *str;

   if (stream == NULL)
      stream = stdin;

   white = skip_whitespace (stream);
   c = getc (stream);
   if (c != EOF) {
     if (c == '(') {
       char *real_str;
       char *imag_str;
       size_t n;
       int ret;

       nread++; /* the opening parenthesis */
       white = skip_whitespace (stream);
       real_str = extract_string (stream);
       nread += strlen(real_str);

       c = getc (stream);
       if (!isspace ((unsigned int) c)) {
         if (c != EOF)
           ungetc (c, stream);
         mpc_free_str (real_str);
         goto error;
       }
       else
         ungetc (c, stream);

       white += skip_whitespace (stream);
       imag_str = extract_string (stream);
       nread += strlen (imag_str);

       str = mpc_alloc_str (nread + 2);
       ret = sprintf (str, "(%s %s", real_str, imag_str);
       MPC_ASSERT (ret >= 0);
       n = (size_t) ret;
       MPC_ASSERT (n == nread + 1);
       mpc_free_str (real_str);
       mpc_free_str (imag_str);

       white += skip_whitespace (stream);
       c = getc (stream);
       if (c == ')') {
         str = mpc_realloc_str (str, nread +2, nread + 3);
         str [nread+1] = (char) c;
         str [nread+2] = '\0';
         nread++;
       }
       else if (c != EOF)
         ungetc (c, stream);
     }
     else {
       if (c != EOF)
         ungetc (c, stream);
       str = extract_string (stream);
       nread += strlen (str);
     }

     inex = mpc_set_str (rop, str, base, rnd_mode);

     mpc_free_str (str);
   }

error:
   if (inex == -1) {
      mpfr_set_nan (MPC_RE(rop));
      mpfr_set_nan (MPC_IM(rop));
   }
   if (read != NULL)
     *read = white + nread;
   return inex;
}
Beispiel #21
0
int
same_mpc_value (mpc_ptr got, mpc_ptr ref, known_signs_t known_signs)
{
   return    same_mpfr_value (MPC_RE (got), MPC_RE (ref), known_signs.re)
          && same_mpfr_value (MPC_IM (got), MPC_IM (ref), known_signs.im);
}
void
mpc_set_prec (mpc_t x, mpfr_prec_t prec)
{
  mpfr_set_prec (MPC_RE(x), prec);
  mpfr_set_prec (MPC_IM(x), prec);
}
static int
mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* assumes that op (that is, its real or imaginary part) is not finite */
{
   int overlap;
   mpc_t op_loc;

   overlap = (rop_sin == op || rop_cos == op);
   if (overlap) {
      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
      mpc_set (op_loc, op, MPC_RNDNN);
   }
   else
      op_loc [0] = op [0];

   if (rop_sin != NULL) {
      if (mpfr_nan_p (MPC_RE (op_loc)) || mpfr_nan_p (MPC_IM (op_loc))) {
         mpc_set (rop_sin, op_loc, rnd_sin);
         if (mpfr_nan_p (MPC_IM (op_loc))) {
            /* sin(x +i*NaN) = NaN +i*NaN, except for x=0 */
            /* sin(-0 +i*NaN) = -0 +i*NaN */
            /* sin(+0 +i*NaN) = +0 +i*NaN */
            if (!mpfr_zero_p (MPC_RE (op_loc)))
               mpfr_set_nan (MPC_RE (rop_sin));
         }
         else /* op = NaN + i*y */
            if (!mpfr_inf_p (MPC_IM (op_loc)) && !mpfr_zero_p (MPC_IM (op_loc)))
            /* sin(NaN -i*Inf) = NaN -i*Inf */
            /* sin(NaN -i*0) = NaN -i*0 */
            /* sin(NaN +i*0) = NaN +i*0 */
            /* sin(NaN +i*Inf) = NaN +i*Inf */
            /* sin(NaN +i*y) = NaN +i*NaN, when 0<|y|<Inf */
            mpfr_set_nan (MPC_IM (rop_sin));
      }
      else if (mpfr_inf_p (MPC_RE (op_loc))) {
         mpfr_set_nan (MPC_RE (rop_sin));

         if (!mpfr_inf_p (MPC_IM (op_loc)) && !mpfr_zero_p (MPC_IM (op_loc)))
            /* sin(+/-Inf +i*y) = NaN +i*NaN, when 0<|y|<Inf */
            mpfr_set_nan (MPC_IM (rop_sin));
         else
            /* sin(+/-Inf -i*Inf) = NaN -i*Inf */
            /* sin(+/-Inf +i*Inf) = NaN +i*Inf */
            /* sin(+/-Inf -i*0) = NaN -i*0 */
            /* sin(+/-Inf +i*0) = NaN +i*0 */
            mpfr_set (MPC_IM (rop_sin), MPC_IM (op_loc), MPC_RND_IM (rnd_sin));
      }
      else if (mpfr_zero_p (MPC_RE (op_loc))) {
         /* sin(-0 -i*Inf) = -0 -i*Inf */
         /* sin(+0 -i*Inf) = +0 -i*Inf */
         /* sin(-0 +i*Inf) = -0 +i*Inf */
         /* sin(+0 +i*Inf) = +0 +i*Inf */
         mpc_set (rop_sin, op_loc, rnd_sin);
      }
      else {
         /* sin(x -i*Inf) = +Inf*(sin(x) -i*cos(x)) */
         /* sin(x +i*Inf) = +Inf*(sin(x) +i*cos(x)) */
         mpfr_t s, c;
         mpfr_init2 (s, 2);
         mpfr_init2 (c, 2);
         mpfr_sin_cos (s, c, MPC_RE (op_loc), GMP_RNDZ);
         mpfr_set_inf (MPC_RE (rop_sin), MPFR_SIGN (s));
         mpfr_set_inf (MPC_IM (rop_sin), MPFR_SIGN (c)*MPFR_SIGN (MPC_IM (op_loc)));
         mpfr_clear (s);
         mpfr_clear (c);
      }
   }

   if (rop_cos != NULL) {
      if (mpfr_nan_p (MPC_RE (op_loc))) {
         /* cos(NaN + i * NaN) = NaN + i * NaN */
         /* cos(NaN - i * Inf) = +Inf + i * NaN */
         /* cos(NaN + i * Inf) = +Inf + i * NaN */
         /* cos(NaN - i * 0) = NaN - i * 0 */
         /* cos(NaN + i * 0) = NaN + i * 0 */
         /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
         if (mpfr_inf_p (MPC_IM (op_loc)))
            mpfr_set_inf (MPC_RE (rop_cos), +1);
         else
            mpfr_set_nan (MPC_RE (rop_cos));

         if (mpfr_zero_p (MPC_IM (op_loc)))
            mpfr_set (MPC_IM (rop_cos), MPC_IM (op_loc), MPC_RND_IM (rnd_cos));
         else
            mpfr_set_nan (MPC_IM (rop_cos));
      }
      else if (mpfr_nan_p (MPC_IM (op_loc))) {
          /* cos(-Inf + i * NaN) = NaN + i * NaN */
          /* cos(+Inf + i * NaN) = NaN + i * NaN */
          /* cos(-0 + i * NaN) = NaN - i * 0 */
          /* cos(+0 + i * NaN) = NaN + i * 0 */
          /* cos(x + i * NaN) = NaN + i * NaN, when x != 0 */
         if (mpfr_zero_p (MPC_RE (op_loc)))
            mpfr_set (MPC_IM (rop_cos), MPC_RE (op_loc), MPC_RND_IM (rnd_cos));
         else
            mpfr_set_nan (MPC_IM (rop_cos));

         mpfr_set_nan (MPC_RE (rop_cos));
      }
      else if (mpfr_inf_p (MPC_RE (op_loc))) {
         /* cos(-Inf -i*Inf) = cos(+Inf +i*Inf) = -Inf +i*NaN */
         /* cos(-Inf +i*Inf) = cos(+Inf -i*Inf) = +Inf +i*NaN */
         /* cos(-Inf -i*0) = cos(+Inf +i*0) = NaN -i*0 */
         /* cos(-Inf +i*0) = cos(+Inf -i*0) = NaN +i*0 */
         /* cos(-Inf +i*y) = cos(+Inf +i*y) = NaN +i*NaN, when y != 0 */

         const int same_sign =
            mpfr_signbit (MPC_RE (op_loc)) == mpfr_signbit (MPC_IM (op_loc));

         if (mpfr_inf_p (MPC_IM (op_loc)))
            mpfr_set_inf (MPC_RE (rop_cos), (same_sign ? -1 : +1));
         else
            mpfr_set_nan (MPC_RE (rop_cos));

         if (mpfr_zero_p (MPC_IM (op_loc)))
            mpfr_setsign (MPC_IM (rop_cos), MPC_IM (op_loc), same_sign,
                          MPC_RND_IM(rnd_cos));
         else
            mpfr_set_nan (MPC_IM (rop_cos));
      }
      else if (mpfr_zero_p (MPC_RE (op_loc))) {
         /* cos(-0 -i*Inf) = cos(+0 +i*Inf) = +Inf -i*0 */
         /* cos(-0 +i*Inf) = cos(+0 -i*Inf) = +Inf +i*0 */
         const int same_sign =
            mpfr_signbit (MPC_RE (op_loc)) == mpfr_signbit (MPC_IM (op_loc));

         mpfr_setsign (MPC_IM (rop_cos), MPC_RE (op_loc), same_sign,
                       MPC_RND_IM (rnd_cos));
         mpfr_set_inf (MPC_RE (rop_cos), +1);
      }
      else {
         /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
         /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
         mpfr_t s, c;
         mpfr_init2 (c, 2);
         mpfr_init2 (s, 2);
         mpfr_sin_cos (s, c, MPC_RE (op_loc), GMP_RNDN);
         mpfr_set_inf (MPC_RE (rop_cos), mpfr_sgn (c));
         mpfr_set_inf (MPC_IM (rop_cos),
            (mpfr_sgn (MPC_IM (op_loc)) == mpfr_sgn (s) ? -1 : +1));
         mpfr_clear (s);
         mpfr_clear (c);
      }
   }

   if (overlap)
      mpc_clear (op_loc);

   return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
      /* everything is exact */
}
Beispiel #24
0
static void
check_file (const char* file_name)
{
  FILE *fp;

  int tmp;
  int base;
  int inex_re;
  int inex_im;
  mpc_t expected, got;
  mpc_rnd_t rnd = MPC_RNDNN;
  int inex = 0, expected_inex;
  size_t expected_size, size;
  known_signs_t ks = {1, 1};

  fp = open_data_file (file_name);

  mpc_init2 (expected, 53);
  mpc_init2 (got, 53);

  /* read data file */
  line_number = 1;
  nextchar = getc (fp);
  skip_whitespace_comments (fp);

  while (nextchar != EOF)
    {
      /* 1. read a line of data: expected result, base, rounding mode */
      read_ternary (fp, &inex_re);
      read_ternary (fp, &inex_im);
      read_mpc (fp, expected, &ks);
      if (inex_re == TERNARY_ERROR || inex_im == TERNARY_ERROR)
         expected_inex = -1;
      else
         expected_inex = MPC_INEX (inex_re, inex_im);
      read_int (fp, &tmp, "size");
      expected_size = (size_t)tmp;
      read_int (fp, &base, "base");
      read_mpc_rounding_mode (fp, &rnd);

      /* 2. read string at the same precision as the expected result */
      while (nextchar != '"')
        nextchar = getc (fp);
      mpfr_set_prec (MPC_RE (got), MPC_PREC_RE (expected));
      mpfr_set_prec (MPC_IM (got), MPC_PREC_IM (expected));
      inex = mpc_inp_str (got, fp, &size, base, rnd);

      /* 3. compare this result with the expected one */
      if (inex != expected_inex || !same_mpc_value (got, expected, ks)
          || size != expected_size)
        {
          printf ("mpc_inp_str failed (line %lu) with rounding mode %s\n",
                  line_number, rnd_mode[rnd]);
          if (inex != expected_inex)
            printf("     got inexact value: %d\nexpected inexact value: %d\n",
                   inex, expected_inex);
          if (size !=  expected_size)
            printf ("     got size: %lu\nexpected size: %lu\n     ",
                    (unsigned long int) size, (unsigned long int) expected_size);
          printf ("    ");
          OUT (got);
          OUT (expected);

          exit (1);
        }

      while ((nextchar = getc (fp)) != '"');
      nextchar = getc (fp);

      skip_whitespace_comments (fp);
    }

  mpc_clear (expected);
  mpc_clear (got);
  close_data_file (fp);
}
Beispiel #25
0
int
mpc_mul_i (mpc_ptr a, mpc_srcptr b, int sign, mpc_rnd_t rnd)
/* if sign is >= 0, multiply by i, otherwise by -i */
{
  int   inex_re, inex_im;
  mpfr_t tmp;

  /* Treat the most probable case of compatible precisions first */
  if (     MPFR_PREC (MPC_RE (b)) == MPFR_PREC (MPC_IM (a))
        && MPFR_PREC (MPC_IM (b)) == MPFR_PREC (MPC_RE (a)))
  {
     if (a == b)
        mpfr_swap (MPC_RE (a), MPC_IM (a));
     else
     {
        mpfr_set (MPC_RE (a), MPC_IM (b), GMP_RNDN);
        mpfr_set (MPC_IM (a), MPC_RE (b), GMP_RNDN);
     }
     if (sign >= 0)
        MPFR_CHANGE_SIGN (MPC_RE (a));
     else
        MPFR_CHANGE_SIGN (MPC_IM (a));
     inex_re = 0;
     inex_im = 0;
  }
  else
  {
     if (a == b)
     {
        mpfr_init2 (tmp, MPFR_PREC (MPC_RE (a)));
        if (sign >= 0)
        {
           inex_re = mpfr_neg (tmp, MPC_IM (b), MPC_RND_RE (rnd));
           inex_im = mpfr_set (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd));
        }
        else
        {
           inex_re = mpfr_set (tmp, MPC_IM (b), MPC_RND_RE (rnd));
           inex_im = mpfr_neg (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd));
        }
        mpfr_clear (MPC_RE (a));
        MPC_RE (a)[0] = tmp [0];
     }
     else
        if (sign >= 0)
        {
           inex_re = mpfr_neg (MPC_RE (a), MPC_IM (b), MPC_RND_RE (rnd));
           inex_im = mpfr_set (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd));
        }
        else
        {
           inex_re = mpfr_set (MPC_RE (a), MPC_IM (b), MPC_RND_RE (rnd));
           inex_im = mpfr_neg (MPC_IM (a), MPC_RE (b), MPC_RND_IM (rnd));
        }
  }

  return MPC_INEX(inex_re, inex_im);
}
Beispiel #26
0
/* If x^y is exactly representable (with maybe a larger precision than z),
   round it in z and return the (mpc) inexact flag in [0, 10].

   If x^y is not exactly representable, return -1.

   If intermediate computations lead to numbers of more than maxprec bits,
   then abort and return -2 (in that case, to avoid loops, mpc_pow_exact
   should be called again with a larger value of maxprec).

   Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real).
*/
static int
mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd,
               mp_prec_t maxprec)
{
  mp_exp_t ec, ed, ey, emin, emax;
  mpz_t my, a, b, c, d, u;
  unsigned long int t;
  int ret = -2;

  mpz_init (my);
  mpz_init (a);
  mpz_init (b);
  mpz_init (c);
  mpz_init (d);
  mpz_init (u);

  ey = mpfr_get_z_exp (my, y);
  /* normalize so that my is odd */
  t = mpz_scan1 (my, 0);
  ey += t;
  mpz_tdiv_q_2exp (my, my, t);

  if (mpfr_zero_p (MPC_RE(x)))
    {
      mpz_set_ui (c, 0);
      ec = 0;
    }
  else
    ec = mpfr_get_z_exp (c, MPC_RE(x));
  if (mpfr_zero_p (MPC_IM(x)))
    {
      mpz_set_ui (d, 0);
      ed = ec;
    }
  else
    {
      ed = mpfr_get_z_exp (d, MPC_IM(x));
      if (mpfr_zero_p (MPC_RE(x)))
        ec = ed;
    }
  /* x = c*2^ec + I * d*2^ed */
  /* equalize the exponents of x */
  if (ec < ed)
    {
      mpz_mul_2exp (d, d, ed - ec);
      if (mpz_sizeinbase (d, 2) > maxprec)
        goto end;
      ed = ec;
    }
  else if (ed < ec)
    {
      mpz_mul_2exp (c, c, ec - ed);
      if (mpz_sizeinbase (c, 2) > maxprec)
        goto end;
      ec = ed;
    }
  /* now ec=ed and x = (c + I * d) * 2^ec */

  /* divide by two if possible */
  if (mpz_cmp_ui (c, 0) == 0)
    {
      t = mpz_scan1 (d, 0);
      mpz_tdiv_q_2exp (d, d, t);
      ec += t;
    }
  else if (mpz_cmp_ui (d, 0) == 0)
    {
      t = mpz_scan1 (c, 0);
      mpz_tdiv_q_2exp (c, c, t);
      ec += t;
    }
  else /* neither c nor d is zero */
    {
      unsigned long v;
      t = mpz_scan1 (c, 0);
      v = mpz_scan1 (d, 0);
      if (v < t)
        t = v;
      mpz_tdiv_q_2exp (c, c, t);
      mpz_tdiv_q_2exp (d, d, t);
      ec += t;
    }

  /* now either one of c, d is odd */

  while (ey < 0)
    {
      /* check if x is a square */
      if (ec & 1)
        {
          mpz_mul_2exp (c, c, 1);
          mpz_mul_2exp (d, d, 1);
          ec --;
        }
      /* now ec is even */
      if (mpc_perfect_square_p (a, b, c, d) == 0)
        break;
      mpz_swap (a, c);
      mpz_swap (b, d);
      ec /= 2;
      ey ++;
    }

  if (ey < 0)
    {
      ret = -1; /* not representable */
      goto end;
    }

  /* Now ey >= 0, it thus suffices to check that x^my is representable.
     If my > 0, this is always true. If my < 0, we first try to invert
     (c+I*d)*2^ec.
  */
  if (mpz_cmp_ui (my, 0) < 0)
    {
      /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient
         condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|.
         Assume a prime p <> 2 divides c^2 + d^2,
         then if p does not divide c or d, 1 / (c + I*d) cannot be exact.
         If p divides both c and d, then we can write c = p*c', d = p*d',
         and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d)
         is exact, then 1/(c' + I*d') is exact too, and we are back to the
         previous case. In conclusion, a necessary and sufficient condition
         is that c^2 + d^2 is a power of two.
      */
      /* FIXME: we could first compute c^2+d^2 mod a limb for example */
      mpz_mul (a, c, c);
      mpz_addmul (a, d, d);
      t = mpz_scan1 (a, 0);
      if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */
        {
          ret = -1; /* not representable */
          goto end;
        }
      /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */
      mpz_neg (d, d);
      ec = -ec - t;
      mpz_neg (my, my);
    }

  /* now ey >= 0 and my >= 0, and we want to compute
     [(c + I * d) * 2^ec] ^ (my * 2^ey).

     We first compute [(c + I * d) * 2^ec]^my, then square ey times. */
  t = mpz_sizeinbase (my, 2) - 1;
  mpz_set (a, c);
  mpz_set (b, d);
  ed = ec;
  /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */
  while (t-- > 0)
    {
      unsigned long v, w;
      /* square a + I*b */
      mpz_mul (u, a, b);
      mpz_mul (a, a, a);
      mpz_submul (a, b, b);
      mpz_mul_2exp (b, u, 1);
      ed *= 2;
      if (mpz_tstbit (my, t)) /* multiply by c + I*d */
        {
          mpz_mul (u, a, c);
          mpz_submul (u, b, d); /* ac-bd */
          mpz_mul (b, b, c);
          mpz_addmul (b, a, d); /* bc+ad */
          mpz_swap (a, u);
          ed += ec;
        }
      /* remove powers of two in (a,b) */
      if (mpz_cmp_ui (a, 0) == 0)
        {
          w = mpz_scan1 (b, 0);
          mpz_tdiv_q_2exp (b, b, w);
          ed += w;
        }
      else if (mpz_cmp_ui (b, 0) == 0)
        {
          w = mpz_scan1 (a, 0);
          mpz_tdiv_q_2exp (a, a, w);
          ed += w;
        }
      else
        {
          w = mpz_scan1 (a, 0);
          v = mpz_scan1 (b, 0);
          if (v < w)
            w = v;
          mpz_tdiv_q_2exp (a, a, w);
          mpz_tdiv_q_2exp (b, b, w);
          ed += w;
        }
      if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec)
        goto end;
    }
  /* now a+I*b = (c+I*d)^my */

  while (ey-- > 0)
    {
      unsigned long sa, sb;

      /* square a + I*b */
      mpz_mul (u, a, b);
      mpz_mul (a, a, a);
      mpz_submul (a, b, b);
      mpz_mul_2exp (b, u, 1);
      ed *= 2;

      /* divide by largest 2^n possible, to avoid many loops for e.g.,
         (2+2*I)^16777216 */
      sa = mpz_scan1 (a, 0);
      sb = mpz_scan1 (b, 0);
      sa = (sa <= sb) ? sa : sb;
      mpz_tdiv_q_2exp (a, a, sa);
      mpz_tdiv_q_2exp (b, b, sa);
      ed += sa;

      if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec)
        goto end;
    }

  /* save emin, emax */
  emin = mpfr_get_emin ();
  emax = mpfr_get_emax ();
  mpfr_set_emin (mpfr_get_emin_min ());
  mpfr_set_emax (mpfr_get_emax_max ());
  ret = mpfr_set_z (MPC_RE(z), a, MPC_RND_RE(rnd));
  ret = MPC_INEX(ret, mpfr_set_z (MPC_IM(z), b, MPC_RND_IM(rnd)));
  mpfr_mul_2si (MPC_RE(z), MPC_RE(z), ed, MPC_RND_RE(rnd));
  mpfr_mul_2si (MPC_IM(z), MPC_IM(z), ed, MPC_RND_IM(rnd));
  /* restore emin, emax */
  mpfr_set_emin (emin);
  mpfr_set_emax (emax);

 end:
  mpz_clear (my);
  mpz_clear (a);
  mpz_clear (b);
  mpz_clear (c);
  mpz_clear (d);
  mpz_clear (u);

  return ret;
}
Beispiel #27
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;
}
Beispiel #28
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;
}
int
mpc_asin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  mpfr_prec_t p, p_re, p_im, incr_p = 0;
  mpfr_rnd_t rnd_re, rnd_im;
  mpc_t z1;
  int inex;

  /* special values */
  if (mpfr_nan_p (MPC_RE (op)) || mpfr_nan_p (MPC_IM (op)))
    {
      if (mpfr_inf_p (MPC_RE (op)) || mpfr_inf_p (MPC_IM (op)))
        {
          mpfr_set_nan (MPC_RE (rop));
          mpfr_set_inf (MPC_IM (rop), mpfr_signbit (MPC_IM (op)) ? -1 : +1);
        }
      else if (mpfr_zero_p (MPC_RE (op)))
        {
          mpfr_set (MPC_RE (rop), MPC_RE (op), GMP_RNDN);
          mpfr_set_nan (MPC_IM (rop));
        }
      else
        {
          mpfr_set_nan (MPC_RE (rop));
          mpfr_set_nan (MPC_IM (rop));
        }

      return 0;
    }

  if (mpfr_inf_p (MPC_RE (op)) || mpfr_inf_p (MPC_IM (op)))
    {
      int inex_re;
      if (mpfr_inf_p (MPC_RE (op)))
        {
          inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
                                   MPC_RND_RE (rnd));
          mpfr_set_inf (MPC_IM (rop), -mpfr_signbit (MPC_IM (op)));

          if (mpfr_inf_p (MPC_IM (op)))
            mpfr_div_2ui (MPC_RE (rop), MPC_RE (rop), 1, GMP_RNDN);
        }
      else
        {
          int s;
          s = mpfr_signbit (MPC_RE (op));
          inex_re = mpfr_set_ui (MPC_RE (rop), 0, GMP_RNDN);
          if (s)
            mpfr_neg (MPC_RE (rop), MPC_RE (rop), GMP_RNDN);
          mpfr_set_inf (MPC_IM (rop), -mpfr_signbit (MPC_IM (op)));
        }

      return MPC_INEX (inex_re, 0);
    }

  /* pure real argument */
  if (mpfr_zero_p (MPC_IM (op)))
    {
      int inex_re;
      int inex_im;
      int s_im;
      s_im = mpfr_signbit (MPC_IM (op));

      if (mpfr_cmp_ui (MPC_RE (op), 1) > 0)
        {
          if (s_im)
            inex_im = -mpfr_acosh (MPC_IM (rop), MPC_RE (op),
                                   INV_RND (MPC_RND_IM (rnd)));
          else
            inex_im = mpfr_acosh (MPC_IM (rop), MPC_RE (op),
                                  MPC_RND_IM (rnd));
          inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
                                   MPC_RND_RE (rnd));
          if (s_im)
            mpc_conj (rop, rop, MPC_RNDNN);
        }
      else if (mpfr_cmp_si (MPC_RE (op), -1) < 0)
        {
          mpfr_t minus_op_re;
          minus_op_re[0] = MPC_RE (op)[0];
          MPFR_CHANGE_SIGN (minus_op_re);

          if (s_im)
            inex_im = -mpfr_acosh (MPC_IM (rop), minus_op_re,
                                   INV_RND (MPC_RND_IM (rnd)));
          else
            inex_im = mpfr_acosh (MPC_IM (rop), minus_op_re,
                                  MPC_RND_IM (rnd));
          inex_re = set_pi_over_2 (MPC_RE (rop), -mpfr_signbit (MPC_RE (op)),
                                   MPC_RND_RE (rnd));
          if (s_im)
            mpc_conj (rop, rop, MPC_RNDNN);
        }
      else
        {
          inex_im = mpfr_set_ui (MPC_IM (rop), 0, MPC_RND_IM (rnd));
          if (s_im)
            mpfr_neg (MPC_IM (rop), MPC_IM (rop), GMP_RNDN);
          inex_re = mpfr_asin (MPC_RE (rop), MPC_RE (op), MPC_RND_RE (rnd));
        }

      return MPC_INEX (inex_re, inex_im);
    }

  /* pure imaginary argument */
  if (mpfr_zero_p (MPC_RE (op)))
    {
      int inex_im;
      int s;
      s = mpfr_signbit (MPC_RE (op));
      mpfr_set_ui (MPC_RE (rop), 0, GMP_RNDN);
      if (s)
        mpfr_neg (MPC_RE (rop), MPC_RE (rop), GMP_RNDN);
      inex_im = mpfr_asinh (MPC_IM (rop), MPC_IM (op), MPC_RND_IM (rnd));

      return MPC_INEX (0, inex_im);
    }

  /* regular complex: asin(z) = -i*log(i*z+sqrt(1-z^2)) */
  p_re = mpfr_get_prec (MPC_RE(rop));
  p_im = mpfr_get_prec (MPC_IM(rop));
  rnd_re = MPC_RND_RE(rnd);
  rnd_im = MPC_RND_IM(rnd);
  p = p_re >= p_im ? p_re : p_im;
  mpc_init2 (z1, p);
  while (1)
  {
    mpfr_exp_t ex, ey, err;

    p += mpc_ceil_log2 (p) + 3 + incr_p; /* incr_p is zero initially */
    incr_p = p / 2;
    mpfr_set_prec (MPC_RE(z1), p);
    mpfr_set_prec (MPC_IM(z1), p);

    /* z1 <- z^2 */
    mpc_sqr (z1, op, MPC_RNDNN);
    /* err(x) <= 1/2 ulp(x), err(y) <= 1/2 ulp(y) */
    /* z1 <- 1-z1 */
    ex = mpfr_get_exp (MPC_RE(z1));
    mpfr_ui_sub (MPC_RE(z1), 1, MPC_RE(z1), GMP_RNDN);
    mpfr_neg (MPC_IM(z1), MPC_IM(z1), GMP_RNDN);
    ex = ex - mpfr_get_exp (MPC_RE(z1));
    ex = (ex <= 0) ? 0 : ex;
    /* err(x) <= 2^ex * ulp(x) */
    ex = ex + mpfr_get_exp (MPC_RE(z1)) - p;
    /* err(x) <= 2^ex */
    ey = mpfr_get_exp (MPC_IM(z1)) - p - 1;
    /* err(y) <= 2^ey */
    ex = (ex >= ey) ? ex : ey; /* err(x), err(y) <= 2^ex, i.e., the norm
                                  of the error is bounded by |h|<=2^(ex+1/2) */
    /* z1 <- sqrt(z1): if z1 = z + h, then sqrt(z1) = sqrt(z) + h/2/sqrt(t) */
    ey = mpfr_get_exp (MPC_RE(z1)) >= mpfr_get_exp (MPC_IM(z1))
      ? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
    /* we have |z1| >= 2^(ey-1) thus 1/|z1| <= 2^(1-ey) */
    mpc_sqrt (z1, z1, MPC_RNDNN);
    ex = (2 * ex + 1) - 2 - (ey - 1); /* |h^2/4/|t| <= 2^ex */
    ex = (ex + 1) / 2; /* ceil(ex/2) */
    /* express ex in terms of ulp(z1) */
    ey = mpfr_get_exp (MPC_RE(z1)) <= mpfr_get_exp (MPC_IM(z1))
      ? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
    ex = ex - ey + p;
    /* take into account the rounding error in the mpc_sqrt call */
    err = (ex <= 0) ? 1 : ex + 1;
    /* err(x) <= 2^err * ulp(x), err(y) <= 2^err * ulp(y) */
    /* z1 <- i*z + z1 */
    ex = mpfr_get_exp (MPC_RE(z1));
    ey = mpfr_get_exp (MPC_IM(z1));
    mpfr_sub (MPC_RE(z1), MPC_RE(z1), MPC_IM(op), GMP_RNDN);
    mpfr_add (MPC_IM(z1), MPC_IM(z1), MPC_RE(op), GMP_RNDN);
    if (mpfr_cmp_ui (MPC_RE(z1), 0) == 0 || mpfr_cmp_ui (MPC_IM(z1), 0) == 0)
      continue;
    ex -= mpfr_get_exp (MPC_RE(z1)); /* cancellation in x */
    ey -= mpfr_get_exp (MPC_IM(z1)); /* cancellation in y */
    ex = (ex >= ey) ? ex : ey; /* maximum cancellation */
    err += ex;
    err = (err <= 0) ? 1 : err + 1; /* rounding error in sub/add */
    /* z1 <- log(z1): if z1 = z + h, then log(z1) = log(z) + h/t with
       |t| >= min(|z1|,|z|) */
    ex = mpfr_get_exp (MPC_RE(z1));
    ey = mpfr_get_exp (MPC_IM(z1));
    ex = (ex >= ey) ? ex : ey;
    err += ex - p; /* revert to absolute error <= 2^err */
    mpc_log (z1, z1, GMP_RNDN);
    err -= ex - 1; /* 1/|t| <= 1/|z| <= 2^(1-ex) */
    /* express err in terms of ulp(z1) */
    ey = mpfr_get_exp (MPC_RE(z1)) <= mpfr_get_exp (MPC_IM(z1))
      ? mpfr_get_exp (MPC_RE(z1)) : mpfr_get_exp (MPC_IM(z1));
    err = err - ey + p;
    /* take into account the rounding error in the mpc_log call */
    err = (err <= 0) ? 1 : err + 1;
    /* z1 <- -i*z1 */
    mpfr_swap (MPC_RE(z1), MPC_IM(z1));
    mpfr_neg (MPC_IM(z1), MPC_IM(z1), GMP_RNDN);
    if (mpfr_can_round (MPC_RE(z1), p - err, GMP_RNDN, GMP_RNDZ,
                        p_re + (rnd_re == GMP_RNDN)) &&
        mpfr_can_round (MPC_IM(z1), p - err, GMP_RNDN, GMP_RNDZ,
                        p_im + (rnd_im == GMP_RNDN)))
      break;
  }

  inex = mpc_set (rop, z1, rnd);
  mpc_clear (z1);

  return inex;
}
int
mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* Feature not documented in the texinfo file: One of rop_sin or
      rop_cos may be NULL, in which case it is not computed, and the
      corresponding ternary inexact value is set to 0 (exact).       */
{
   if (!mpc_fin_p (op))
      return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else if (mpfr_zero_p (MPC_IM (op)))
      return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else if (mpfr_zero_p (MPC_RE (op)))
      return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else {
      /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
                           and  cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).

         For Re(sin(op)) (and analogously, the other parts), we use the
         following algorithm, with rounding to nearest for all operations
         and working precision w:

         (1) x = o(sin(a))
         (2) y = o(cosh(b))
         (3) r = o(x*y)
         then the error on r is at most 4 ulps, since we can write
         r = sin(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
         thus for w >= 2, r = sin(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
         thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
      */
      mpfr_t s, c, sh, ch, sch, csh;
      mpfr_prec_t prec;
      int ok;
      int inex_re, inex_im, inex_sin, inex_cos;

      prec = 2;
      if (rop_sin != NULL)
         prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
      if (rop_cos != NULL)
         prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));

      mpfr_init2 (s, 2);
      mpfr_init2 (c, 2);
      mpfr_init2 (sh, 2);
      mpfr_init2 (ch, 2);
      mpfr_init2 (sch, 2);
      mpfr_init2 (csh, 2);

      do {
         ok = 1;
         prec += mpc_ceil_log2 (prec) + 5;

         mpfr_set_prec (s, prec);
         mpfr_set_prec (c, prec);
         mpfr_set_prec (sh, prec);
         mpfr_set_prec (ch, prec);
         mpfr_set_prec (sch, prec);
         mpfr_set_prec (csh, prec);

         mpfr_sin_cos (s, c, MPC_RE(op), GMP_RNDN);
         mpfr_sinh_cosh (sh, ch, MPC_IM(op), GMP_RNDN);

         if (rop_sin != NULL) {
            /* real part of sine */
            mpfr_mul (sch, s, ch, GMP_RNDN);
            ok = (!mpfr_number_p (sch))
                  || mpfr_can_round (sch, prec - 2, GMP_RNDN, GMP_RNDZ,
                        MPC_PREC_RE (rop_sin)
                        + (MPC_RND_RE (rnd_sin) == GMP_RNDN));

            if (ok) {
               /* imaginary part of sine */
               mpfr_mul (csh, c, sh, GMP_RNDN);
               ok = (!mpfr_number_p (csh))
                     || mpfr_can_round (csh, prec - 2, GMP_RNDN, GMP_RNDZ,
                           MPC_PREC_IM (rop_sin)
                           + (MPC_RND_IM (rnd_sin) == GMP_RNDN));
            }
         }

         if (rop_cos != NULL && ok) {
            /* real part of cosine */
            mpfr_mul (c, c, ch, GMP_RNDN);
            ok = (!mpfr_number_p (c))
                  || mpfr_can_round (c, prec - 2, GMP_RNDN, GMP_RNDZ,
                        MPC_PREC_RE (rop_cos)
                        + (MPC_RND_RE (rnd_cos) == GMP_RNDN));

            if (ok) {
               /* imaginary part of cosine */
               mpfr_mul (s, s, sh, GMP_RNDN);
               mpfr_neg (s, s, GMP_RNDN);
               ok = (!mpfr_number_p (s))
                     || mpfr_can_round (s, prec - 2, GMP_RNDN, GMP_RNDZ,
                           MPC_PREC_IM (rop_cos)
                           + (MPC_RND_IM (rnd_cos) == GMP_RNDN));
            }
         }
      } while (ok == 0);

      if (rop_sin != NULL) {
         inex_re = mpfr_set (MPC_RE (rop_sin), sch, MPC_RND_RE (rnd_sin));
         if (mpfr_inf_p (sch))
            inex_re = mpfr_sgn (sch);
         inex_im = mpfr_set (MPC_IM (rop_sin), csh, MPC_RND_IM (rnd_sin));
         if (mpfr_inf_p (csh))
            inex_im = mpfr_sgn (csh);
         inex_sin = MPC_INEX (inex_re, inex_im);
      }
      else
         inex_sin = MPC_INEX (0,0); /* return exact if not computed */

      if (rop_cos != NULL) {
         inex_re = mpfr_set (MPC_RE (rop_cos), c, MPC_RND_RE (rnd_cos));
         if (mpfr_inf_p (c))
            inex_re = mpfr_sgn (c);
         inex_im = mpfr_set (MPC_IM (rop_cos), s, MPC_RND_IM (rnd_cos));
         if (mpfr_inf_p (s))
            inex_im = mpfr_sgn (s);
         inex_cos = MPC_INEX (inex_re, inex_im);
      }
      else
         inex_cos = MPC_INEX (0,0); /* return exact if not computed */

      mpfr_clear (s);
      mpfr_clear (c);
      mpfr_clear (sh);
      mpfr_clear (ch);
      mpfr_clear (sch);
      mpfr_clear (csh);

      return (MPC_INEX12 (inex_sin, inex_cos));
   }
}