Beispiel #1
0
static PyObject *
GMPy_Real_Is_Signed(PyObject *x, CTXT_Object *context)
{
    MPFR_Object *tempx;
    int res;

    if (MPFR_Check(x)) {
        res = mpfr_signbit(MPFR(x));
    }
    else {
        CHECK_CONTEXT(context);
        if (!(tempx = GMPy_MPFR_From_Real(x, 1, context))) {
            return NULL;
        }
        res = mpfr_signbit(tempx->f);
        Py_DECREF((PyObject*)tempx);
    }

    if (res) {
        Py_RETURN_TRUE;
    }
    else {
        Py_RETURN_FALSE;
    }
}
Beispiel #2
0
static void
reuse_bug (void)
{
   /* bug found by the automatic builds on
      http://hydra.nixos.org/build/1469029/log/raw */
   mpc_t x, y, z;
   mp_prec_t prec = 2;

   for (prec = 2; prec <= 20; prec ++)
     {
       mpc_init2 (x, prec);
       mpc_init2 (y, prec);
       mpc_init2 (z, prec);
   
       mpfr_set_ui (mpc_realref (x), 0ul, MPFR_RNDN);
       mpfr_set_ui_2exp (mpc_imagref (x), 3ul, -2, MPFR_RNDN);
       mpc_set_ui (y, 8ul, MPC_RNDNN);

       mpc_pow (z, x, y, MPC_RNDNN);
       mpc_pow (y, x, y, MPC_RNDNN);
       if (mpfr_signbit (mpc_imagref (y)) != mpfr_signbit (mpc_imagref (z)))
         {
           printf ("Error: regression, reuse_bug reproduced\n");
           exit (1);
         }

       mpc_clear (x);
       mpc_clear (y);
       mpc_clear (z);
     }
}
Beispiel #3
0
static void
copysign_variant (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y,
                  mpfr_rnd_t rnd_mode, int k)
{
    mpfr_clear_flags ();
    switch (k)
    {
    case 0:
        mpfr_copysign (z, x, y, MPFR_RNDN);
        return;
    case 1:
        (mpfr_copysign) (z, x, y, MPFR_RNDN);
        return;
    case 2:
        mpfr_setsign (z, x, mpfr_signbit (y), MPFR_RNDN);
        return;
    case 3:
        mpfr_setsign (z, x, (mpfr_signbit) (y), MPFR_RNDN);
        return;
    case 4:
        (mpfr_setsign) (z, x, mpfr_signbit (y), MPFR_RNDN);
        return;
    case 5:
        (mpfr_setsign) (z, x, (mpfr_signbit) (y), MPFR_RNDN);
        return;
    }
}
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));
}
Beispiel #5
0
static int
mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* assumes that op is real */
{
   int inex_sin_re = 0, inex_cos_re = 0;
      /* Until further notice, assume computations exact; in particular,
         by definition, for not computed values.                         */
   mpfr_t s, c;
   int inex_s, inex_c;
   int sign_im = mpfr_signbit (mpc_imagref (op));

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

   if (rop_sin != NULL) {
      mpfr_set (mpc_realref (rop_sin), s, MPFR_RNDN); /* exact */
      inex_sin_re = inex_s;
      mpfr_set_zero (mpc_imagref (rop_sin),
         (     ( sign_im && !mpfr_signbit(c))
            || (!sign_im &&  mpfr_signbit(c)) ? -1 : 1));
   }

   if (rop_cos != NULL) {
      mpfr_set (mpc_realref (rop_cos), c, MPFR_RNDN); /* exact */
      inex_cos_re = inex_c;
      mpfr_set_zero (mpc_imagref (rop_cos),
         (     ( sign_im &&  mpfr_signbit(s))
            || (!sign_im && !mpfr_signbit(s)) ? -1 : 1));
   }

   mpfr_clear (s);
   mpfr_clear (c);

   return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
}
Beispiel #6
0
/* comparisons, see description in mpc-tests.h */
int
same_mpfr_value (mpfr_ptr got, mpfr_ptr ref, int known_sign)
{
   /* The sign of zeroes and infinities is checked only when
      known_sign is true.                                    */
   if (mpfr_nan_p (got))
      return mpfr_nan_p (ref);
   if (mpfr_inf_p (got))
      return mpfr_inf_p (ref) &&
            (!known_sign || mpfr_signbit (got) == mpfr_signbit (ref));
   if (mpfr_zero_p (got))
      return mpfr_zero_p (ref) &&
            (!known_sign || mpfr_signbit (got) == mpfr_signbit (ref));
   return mpfr_cmp (got, ref) == 0;
}
Beispiel #7
0
int
tpl_same_mpfr_value (mpfr_ptr x1, mpfr_ptr x2, int known_sign)
{
   /* The sign of zeroes and infinities is checked only when known_sign is
      true.  */
   if (mpfr_nan_p (x1))
      return mpfr_nan_p (x2);
   if (mpfr_inf_p (x1))
      return mpfr_inf_p (x2) &&
            (!known_sign || mpfr_signbit (x1) == mpfr_signbit (x2));
   if (mpfr_zero_p (x1))
      return mpfr_zero_p (x2) &&
            (!known_sign || mpfr_signbit (x1) == mpfr_signbit (x2));
   return mpfr_cmp (x1, x2) == 0;
}
Beispiel #8
0
static void
test_reuse (void)
{
  mpc_t z;
  mpfr_t y;
  int inex;

  mpfr_init2 (y, 2);
  mpc_init2 (z, 2);
  mpc_set_si_si (z, 0, -1, MPC_RNDNN);
  mpfr_neg (mpc_realref (z), mpc_realref (z), MPFR_RNDN);
  mpc_div_2ui (z, z, 4, MPC_RNDNN);
  mpfr_set_ui (y, 512, MPFR_RNDN);
  inex = mpc_pow_fr (z, z, y, MPC_RNDNN);
  if (MPC_INEX_RE(inex) != 0 || MPC_INEX_IM(inex) != 0 ||
      mpfr_cmp_ui_2exp (mpc_realref(z), 1, -2048) != 0 ||
      mpfr_cmp_ui (mpc_imagref(z), 0) != 0 || mpfr_signbit (mpc_imagref(z)) == 0)
    {
      printf ("Error in test_reuse, wrong ternary value or output\n");
      printf ("inex=(%d %d)\n", MPC_INEX_RE(inex), MPC_INEX_IM(inex));
      printf ("z="); mpc_out_str (stdout, 2, 0, z, MPC_RNDNN); printf ("\n");
      exit (1);
    }
  mpfr_clear (y);
  mpc_clear (z);
}
int
mpfi_put_q (mpfi_ptr a, mpq_srcptr b)
{
  int inexact_left = 0;
  int inexact_right = 0;
  int inexact = 0;

  if ( MPFI_NAN_P (a) )
    MPFR_RET_NAN;

  if (mpfr_cmp_q (&(a->left), b) > 0 ) {
    inexact_left = mpfr_set_q (&(a->left), b, MPFI_RNDD);
  }
  else if (mpfr_cmp_q (&(a->right), b) < 0 ) {
    inexact_right = mpfr_set_q (&(a->right), b, MPFI_RNDU);

    /* do not allow +0 as upper bound */
    if (mpfr_zero_p (&(a->right)) && !mpfr_signbit (&(a->right))) {
      mpfr_neg (&(a->right), &(a->right), MPFI_RNDD);
    }
  }

  if (inexact_left)
    inexact += 1;
  if (inexact_right)
    inexact += 2;

  return inexact;
}
Beispiel #10
0
void r_flipsign(real y, real x)
{
	int new_sign;

	new_sign = (mpfr_signbit(x) == 0);
	mpfr_setsign(y, x, new_sign, MPFR_RNDN);
}
Beispiel #11
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_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);
}
void
print_fp (FILE *fout, mpfr_t f, const char *suffix)
{
  if (mpfr_inf_p (f))
    mpfr_fprintf (fout, "\t%sINF%s", mpfr_signbit (f) ? "-" : "", suffix);
  else
    mpfr_fprintf (fout, "\t%Ra%s", f, suffix);
}
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);
}
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 #16
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;
}
Beispiel #17
0
static char *
pretty_zero (mpfr_srcptr zero)
{
  char *pretty;

  pretty = mpc_alloc_str (3);

  pretty[0] = mpfr_signbit (zero) ? '-' : '+';
  pretty[1] = '0';
  pretty[2] = '\0';

  return pretty;
}
Beispiel #18
0
static PyObject *
GMPy_Context_NextToward(PyObject *self, PyObject *args)
{
    MPFR_Object *result, *tempx, *tempy;
    CTXT_Object *context = NULL;
    int direction;
    mpfr_rnd_t temp_round;

    if (self && CTXT_Check(self)) {
        context = (CTXT_Object*)self;
    }
    else {
        CHECK_CONTEXT(context);
    }

    if (PyTuple_GET_SIZE(args) != 2) {
        TYPE_ERROR("next_toward() requires 2 arguments");
        return NULL;
    }

    tempx = GMPy_MPFR_From_Real(PyTuple_GET_ITEM(args, 0), 1, context);
    tempy = GMPy_MPFR_From_Real(PyTuple_GET_ITEM(args, 1), 1, context);
    if (!tempx || !tempy) {
        TYPE_ERROR("next_toward() argument type not supported");
        Py_XDECREF((PyObject*)tempx);
        Py_XDECREF((PyObject*)tempy);
        return NULL;
    }

    if (!(result = GMPy_MPFR_New(mpfr_get_prec(tempx->f), context))) {
        Py_DECREF((PyObject*)tempx);
        Py_DECREF((PyObject*)tempy);
        return NULL;
    }

    mpfr_clear_flags();
    mpfr_set(result->f, tempx->f, GET_MPFR_ROUND(context));
    mpfr_nexttoward(result->f, tempy->f);
    result->rc = 0;
    direction = mpfr_signbit(tempy->f);
    Py_DECREF((PyObject*)tempx);
    Py_DECREF((PyObject*)tempy);
    temp_round = GET_MPFR_ROUND(context);
    if (direction)
        context->ctx.mpfr_round = MPFR_RNDD;
    else
         context->ctx.mpfr_round = MPFR_RNDU;
    _GMPy_MPFR_Cleanup(&result, context);
    context->ctx.mpfr_round = temp_round;
    return (PyObject*)result;
}
Beispiel #19
0
int
mpfi_sub (mpfi_ptr a, mpfi_srcptr b, mpfi_srcptr c)
{
  mpfr_t tmp;
  int inexact_left, inexact_right, inexact = 0;

  if (MPFI_IS_ZERO (c)) {
    return mpfi_set (a, b);
  }
  else if (MPFI_IS_ZERO (b)) {
    return mpfi_neg (a, c);
  }
  else {
    mpfr_init2 (tmp, mpfr_get_prec (&(a->left)));
    inexact_left = mpfr_sub (tmp, &(b->left), &(c->right), MPFI_RNDD);
    inexact_right = mpfr_sub (&(a->right), &(b->right), &(c->left), MPFI_RNDU);
    mpfr_set (&(a->left), tmp, MPFI_RNDD); /* exact */
    mpfr_clear (tmp);

    /* do not allow -0 as lower bound */
    if (mpfr_zero_p (&(a->left)) && mpfr_signbit (&(a->left))) {
      mpfr_neg (&(a->left), &(a->left), MPFI_RNDU);
    }
    /* do not allow +0 as upper bound */
    if (mpfr_zero_p (&(a->right)) && !mpfr_signbit (&(a->right))) {
      mpfr_neg (&(a->right), &(a->right), MPFI_RNDD);
    }

    if (MPFI_NAN_P (a))
      MPFR_RET_NAN;
    if (inexact_left)
      inexact += 1;
    if (inexact_right)
      inexact += 2;

    return inexact;
  }
}
Beispiel #20
0
static void
reuse_bug (void)
{
  mpc_t z1;

  /* reuse bug found by Paul Zimmermann 20081021 */
  mpc_init2 (z1, 2);
  /* RE (z1^2) overflows, IM(z^2) = -0 */
  mpfr_set_str (mpc_realref (z1), "0.11", 2, MPFR_RNDN);
  mpfr_mul_2si (mpc_realref (z1), mpc_realref (z1), mpfr_get_emax (), MPFR_RNDN);
  mpfr_set_ui (mpc_imagref (z1), 0, MPFR_RNDN);
  mpc_conj (z1, z1, MPC_RNDNN);
  mpc_sqr (z1, z1, MPC_RNDNN);
  if (!mpfr_inf_p (mpc_realref (z1)) || mpfr_signbit (mpc_realref (z1))
      ||!mpfr_zero_p (mpc_imagref (z1)) || !mpfr_signbit (mpc_imagref (z1)))
    {
      printf ("Error: Regression, bug 20081021 reproduced\n");
      MPC_OUT (z1);
      exit (1);
    }

  mpc_clear (z1);
}
int
mpfi_interv_fr (mpfi_ptr a, mpfr_srcptr b, mpfr_srcptr c)
{
  int inexact_left, inexact_right, inexact=0;

  if ( mpfr_nan_p (b) || mpfr_nan_p (c) ) {
    mpfr_set_nan (&(a->left));
    mpfr_set_nan (&(a->right));
    MPFR_RET_NAN;
  }

  if ( mpfr_cmp (b, c) <= 0 ) {
    inexact_left = mpfr_set (&(a->left), b, MPFI_RNDD);
    inexact_right = mpfr_set (&(a->right), c, MPFI_RNDU);
  }
  else {
    inexact_left = mpfr_set (&(a->left), c, MPFI_RNDD);
    inexact_right = mpfr_set (&(a->right), b, MPFI_RNDU);
  }
  /* a cannot be a NaN, it has been tested before */
  if (inexact_left)
    inexact += 1;
  if (inexact_right)
    inexact += 2;

  /* do not allow -0 as lower bound */
  if (mpfr_zero_p (&(a->left)) && mpfr_signbit (&(a->left))) {
    mpfr_neg (&(a->left), &(a->left), MPFI_RNDU);
  }
  /* do not allow +0 as upper bound */
  if (mpfr_zero_p (&(a->right)) && !mpfr_signbit (&(a->right))) {
    mpfr_neg (&(a->right), &(a->right), MPFI_RNDD);
  }

  return inexact;
}
Beispiel #22
0
SeedValue seed_mpfr_signbit (SeedContext ctx,
                             SeedObject function,
                             SeedObject this_object,
                             gsize argument_count,
                             const SeedValue args[],
                             SeedException *exception)
{
    mpfr_ptr rop;
    gboolean ret;

    CHECK_ARG_COUNT("mpfr.signbit", 0);
    rop = seed_object_get_private(this_object);
    ret = mpfr_signbit(rop);

    return seed_value_from_boolean(ctx, ret, exception);
}
Beispiel #23
0
int
mpfi_sech (mpfi_ptr a, mpfi_srcptr b)
{
  mpfr_t tmp;
  int inexact_left, inexact_right, inexact=0;

  if ( MPFI_NAN_P (b) ) {
    mpfr_set_nan (&(a->left));
    mpfr_set_nan (&(a->right));
    MPFR_RET_NAN;
  }

  if ( MPFI_IS_NONNEG (b) ) {
    mpfr_init2 (tmp, mpfr_get_prec (&(a->left)));
    inexact_left = mpfr_sech (tmp, &(b->right), MPFI_RNDD);
    inexact_right = mpfr_sech (&(a->right), &(b->left), MPFI_RNDU);
    mpfr_set (&(a->left), tmp, MPFI_RNDD); /* exact */
    mpfr_clear (tmp);
  }
  else if ( MPFI_HAS_ZERO (b) ) {
    mpfr_init2 (tmp, mpfr_get_prec (&(b->left)));
    mpfr_neg (tmp, &(b->left), MPFI_RNDD); /* exact */
    if (mpfr_cmp (tmp, &(b->right)) > 0)
      inexact_left = mpfr_sech (&(a->left), tmp, MPFI_RNDD);
    else
      inexact_left = mpfr_sech (&(a->left), &(b->right), MPFI_RNDD);
    inexact_right = mpfr_set_ui (&(a->right), 1, MPFI_RNDU);
    mpfr_clear (tmp);
  }
  else { /* b <= 0 */
    inexact_left = mpfr_sech (&(a->left), &(b->left), MPFI_RNDD);
    inexact_right = mpfr_sech (&(a->right), &(b->right), MPFI_RNDU);
  }

  /* do not allow +0 as upper bound */
  if (mpfr_zero_p (&(a->right)) && !mpfr_signbit (&(a->right))) {
    mpfr_neg (&(a->right), &(a->right), MPFI_RNDD);
  }

  if (inexact_left)
    inexact += 1;
  if (inexact_right)
    inexact += 2;

  return inexact;
}
Beispiel #24
0
	void HOTBM::emulate(TestCase* tc)
	{
		/* Get inputs / outputs */
		mpz_class sx = tc->getInputValue ("X");

		// int outSign = 0;

		mpfr_t mpX, mpR;
		mpfr_inits(mpX, mpR, 0, NULL);

		/* Convert a random signal to an mpfr_t in [0,1[ */
		mpfr_set_z(mpX, sx.get_mpz_t(), GMP_RNDN);
		mpfr_div_2si(mpX, mpX, wI, GMP_RNDN);

		/* Compute the function */
		f.eval(mpR, mpX);

		/* Compute the signal value */
		if (mpfr_signbit(mpR))
			{
				// outSign = 1;
				mpfr_abs(mpR, mpR, GMP_RNDN);
			}
		mpfr_mul_2si(mpR, mpR, wO, GMP_RNDN);

		/* NOT A TYPO. HOTBM only guarantees faithful
		 * rounding, so we will round down here,
		 * add both the upper and lower neighbor.
		 */
		mpz_t rd_t;
		mpz_init (rd_t);
		mpfr_get_z(rd_t, mpR, GMP_RNDD);
		mpz_class rd (rd_t), ru = rd + 1;
		tc->addExpectedOutput ("R", rd);
		tc->addExpectedOutput ("R", ru);
		
		mpz_clear (rd_t);
		mpfr_clear (mpX);
		mpfr_clear (mpR);
	}
Beispiel #25
0
int
mpfi_log10 (mpfi_ptr a, mpfi_srcptr b)
{
  int inexact_left, inexact_right, inexact=0;

  inexact_left = mpfr_log10 (&(a->left), &(b->left), MPFI_RNDD);
  inexact_right = mpfr_log10 (&(a->right), &(b->right), MPFI_RNDU);

  /* do not allow +0 as upper bound */
  if (mpfr_zero_p (&(a->right)) && !mpfr_signbit (&(a->right))) {
    mpfr_neg (&(a->right), &(a->right), MPFI_RNDD);
  }

  if ( MPFI_NAN_P (a) )
    MPFR_RET_NAN;

  if (inexact_left)
    inexact += 1;
  if (inexact_right)
    inexact += 2;
  return inexact;
}
Beispiel #26
0
/* return mpfr_cmp (mpc_abs (a), mpc_abs (b)) */
int
mpc_cmp_abs (mpc_srcptr a, mpc_srcptr b)
{
   mpc_t z1, z2;
   mpfr_t n1, n2;
   mpfr_prec_t prec;
   int inex1, inex2, ret;

   /* Handle numbers containing one NaN as mpfr_cmp. */
   if (   mpfr_nan_p (mpc_realref (a)) || mpfr_nan_p (mpc_imagref (a))
       || mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b)))
     {
       mpfr_t nan;
       mpfr_init (nan);
       mpfr_set_nan (nan);
       ret = mpfr_cmp (nan, nan);
       mpfr_clear (nan);
       return ret;
     }

   /* Handle infinities. */
   if (mpc_inf_p (a))
      if (mpc_inf_p (b))
         return 0;
      else
         return 1;
   else if (mpc_inf_p (b))
      return -1;

   /* Replace all parts of a and b by their absolute values, then order
      them by size. */
   z1 [0] = a [0];
   z2 [0] = b [0];
   if (mpfr_signbit (mpc_realref (a)))
      MPFR_CHANGE_SIGN (mpc_realref (z1));
   if (mpfr_signbit (mpc_imagref (a)))
      MPFR_CHANGE_SIGN (mpc_imagref (z1));
   if (mpfr_signbit (mpc_realref (b)))
      MPFR_CHANGE_SIGN (mpc_realref (z2));
   if (mpfr_signbit (mpc_imagref (b)))
      MPFR_CHANGE_SIGN (mpc_imagref (z2));
   if (mpfr_cmp (mpc_realref (z1), mpc_imagref (z1)) > 0)
      mpfr_swap (mpc_realref (z1), mpc_imagref (z1));
   if (mpfr_cmp (mpc_realref (z2), mpc_imagref (z2)) > 0)
      mpfr_swap (mpc_realref (z2), mpc_imagref (z2));

   /* Handle cases in which only one part differs. */
   if (mpfr_cmp (mpc_realref (z1), mpc_realref (z2)) == 0)
      return mpfr_cmp (mpc_imagref (z1), mpc_imagref (z2));
   if (mpfr_cmp (mpc_imagref (z1), mpc_imagref (z2)) == 0)
      return mpfr_cmp (mpc_realref (z1), mpc_realref (z2));

   /* Implement the algorithm in algorithms.tex. */
   mpfr_init (n1);
   mpfr_init (n2);
   prec = MPC_MAX (50, MPC_MAX (MPC_MAX_PREC (z1), MPC_MAX_PREC (z2)) / 100);
   do {
      mpfr_set_prec (n1, prec);
      mpfr_set_prec (n2, prec);
      inex1 = mpc_norm (n1, z1, MPFR_RNDD);
      inex2 = mpc_norm (n2, z2, MPFR_RNDD);
      ret = mpfr_cmp (n1, n2);
      if (ret != 0)
        goto end;
      else
         if (inex1 == 0) /* n1 = norm(z1) */
            if (inex2)   /* n2 < norm(z2) */
              {
                ret = -1;
                goto end;
              }
            else /* n2 = norm(z2) */
              {
                ret = 0;
                goto end;
              }
         else /* n1 < norm(z1) */
            if (inex2 == 0)
              {
                ret = 1;
                goto end;
              }
      prec *= 2;
   } while (1);
 end:
   mpfr_clear (n1);
   mpfr_clear (n2);
   return ret;
}
Beispiel #27
0
Datei: pow.c Projekt: tomi500/MPC
/* If x^y is exactly representable (with maybe a larger precision than z),
   round it in z and return the (mpc) inexact flag in [0, 10].

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

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

   Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real).

   Warning: z and x might be the same variable, same for Re(z) or Im(z) and y.

   In case -1 or -2 is returned, z is not modified.
*/
static int
mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd,
               mpfr_prec_t maxprec)
{
  mpfr_exp_t ec, ed, ey;
  mpz_t my, a, b, c, d, u;
  unsigned long int t;
  int ret = -2;
  int sign_rex = mpfr_signbit (mpc_realref(x));
  int sign_imx = mpfr_signbit (mpc_imagref(x));
  int x_imag = mpfr_zero_p (mpc_realref(x));
  int z_is_y = 0;
  mpfr_t copy_of_y;

  if (mpc_realref (z) == y || mpc_imagref (z) == y)
    {
      z_is_y = 1;
      mpfr_init2 (copy_of_y, mpfr_get_prec (y));
      mpfr_set (copy_of_y, y, MPFR_RNDN);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  ret = mpfr_set_z (mpc_realref(z), a, MPC_RND_RE(rnd));
  ret = MPC_INEX(ret, mpfr_set_z (mpc_imagref(z), b, MPC_RND_IM(rnd)));
  mpfr_mul_2si (mpc_realref(z), mpc_realref(z), ed, MPC_RND_RE(rnd));
  mpfr_mul_2si (mpc_imagref(z), mpc_imagref(z), ed, MPC_RND_IM(rnd));

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

  if (ret >= 0 && x_imag)
    fix_sign (z, sign_rex, sign_imx, (z_is_y) ? copy_of_y : y);

  if (z_is_y)
    mpfr_clear (copy_of_y);

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

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

      return 0;
    }

  if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
    {
      int inex_re;
      if (mpfr_inf_p (mpc_realref (op)))
        {
          int inf_im = mpfr_inf_p (mpc_imagref (op));

          inex_re = set_pi_over_2 (mpc_realref (rop),
             (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
          mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));

          if (inf_im)
            mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN);
        }
      else
        {
          mpfr_set_zero (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1));
          inex_re = 0;
          mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));
        }

      return MPC_INEX (inex_re, 0);
    }

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

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

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

      return MPC_INEX (inex_re, inex_im);
    }

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

      return MPC_INEX (0, inex_im);
    }

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

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

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

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

  return inex;
}
Beispiel #30
0
static PyObject *
GMPy_Real_Mod(PyObject *x, PyObject *y, CTXT_Object *context)
{
    MPFR_Object *tempx = NULL, *tempy = NULL, *temp, *result;

    CHECK_CONTEXT(context);

    result = GMPy_MPFR_New(0, context);
    temp = GMPy_MPFR_New(0, context);
    if (!result || !temp) {
        Py_XDECREF((PyObject*)result);
        Py_XDECREF((PyObject*)temp);
        return NULL;
    }

    if (IS_REAL(x) && IS_REAL(y)) {
        tempx = GMPy_MPFR_From_Real(x, 1, context);
        tempy = GMPy_MPFR_From_Real(y, 1, context);
        if (!tempx || !tempy) {
            SYSTEM_ERROR("could not convert Real to mpfr");
            goto error;
        }
        if (mpfr_zero_p(tempy->f)) {
            context->ctx.divzero = 1;
            if (context->ctx.traps & TRAP_DIVZERO) {
                GMPY_DIVZERO("mod() modulo by zero");
                goto error;
            }
        }

        if (mpfr_nan_p(tempx->f) || mpfr_nan_p(tempy->f) || mpfr_inf_p(tempx->f)) {
            context->ctx.invalid = 1;
            if (context->ctx.traps & TRAP_INVALID) {
                GMPY_INVALID("mod() invalid operation");
                goto error;
            }
            else {
                mpfr_set_nan(result->f);
            }
        }
        else if (mpfr_inf_p(tempy->f)) {
            context->ctx.invalid = 1;
            if (context->ctx.traps & TRAP_INVALID) {
                GMPY_INVALID("mod() invalid operation");
                goto error;
            }
            if (mpfr_signbit(tempy->f)) {
                mpfr_set_inf(result->f, -1);
            }
            else {
                result->rc = mpfr_set(result->f, tempx->f,
                                      GET_MPFR_ROUND(context));
            }
        }
        else {
            mpfr_fmod(result->f, tempx->f, tempy->f, GET_MPFR_ROUND(context));

            if (!mpfr_zero_p(result->f)) {
                if ((mpfr_sgn(tempy->f) < 0) != (mpfr_sgn(result->f) < 0)) {
                    mpfr_add(result->f, result->f, tempy->f, GET_MPFR_ROUND(context));
                }
            }
            else {
                mpfr_copysign(result->f, result->f, tempy->f, GET_MPFR_ROUND(context));
            }

            Py_DECREF((PyObject*)temp);
        }
        GMPY_MPFR_CHECK_RANGE(result, context);
        GMPY_MPFR_SUBNORMALIZE(result, context);

        Py_DECREF((PyObject*)tempx);
        Py_DECREF((PyObject*)tempy);
        return (PyObject*)result;
    }

    Py_DECREF((PyObject*)temp);
    Py_DECREF((PyObject*)result);
    Py_RETURN_NOTIMPLEMENTED;

  error:
    Py_XDECREF((PyObject*)tempx);
    Py_XDECREF((PyObject*)tempy);
    Py_DECREF((PyObject*)temp);
    Py_DECREF((PyObject*)result);
    return NULL;
}