Beispiel #1
0
static void
bug20090227 (void)
{
  mpfr_t x, y, r1, r2;
  int inex1, inex2;

  mpfr_init2 (x, 118);
  mpfr_init2 (y, 181);
  mpfr_init2 (r1, 140);
  mpfr_init2 (r2, 140);
  mpfr_set_si (x, -1, MPFR_RNDN);
  mpfr_set_str_binary (y, "1.100100100001111110110101010001000100001011010001100001000110100110001001100011001100010100010111000000011011100000111001101000100101001000000100100111000001000100010100110011111010");
  inex1 = mpfr_remainder (r1, x, y, MPFR_RNDU);
  /* since the quotient is -1, r1 is the rounding of x+y */
  inex2 = mpfr_add (r2, x, y, MPFR_RNDU);
  if (mpfr_cmp (r1, r2))
    {
      printf ("Error in mpfr_remainder (bug20090227)\n");
      printf ("Expected ");
      mpfr_dump (r2);
      printf ("Got      ");
      mpfr_dump (r1);
      exit (1);
    }
  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (r1);
  mpfr_clear (r2);
}
Beispiel #2
0
real remainder(const real & a, const real & b)
{
	real x;
	
	mpfr_remainder(x.r, a.r, b.r, MPFR_RNDN);
	return x;
}
SeedValue seed_mpfr_remainder (SeedContext ctx,
                               SeedObject function,
                               SeedObject this_object,
                               gsize argument_count,
                               const SeedValue args[],
                               SeedException *exception)
{
    mpfr_rnd_t rnd;
    mpfr_ptr rop, op1, op2;
    gint ret;

    CHECK_ARG_COUNT("mpfr.remainder", 3);

    rop = seed_object_get_private(this_object);
    rnd = seed_value_to_mpfr_rnd_t(ctx, args[2], exception);

    if ( seed_value_is_object_of_class(ctx, args[0], mpfr_class) &&
         seed_value_is_object_of_class(ctx, args[1], mpfr_class))
    {
        op1 = seed_object_get_private(args[0]);
        op2 = seed_object_get_private(args[1]);
    }
    else
    {
        TYPE_EXCEPTION("mpfr.remainder", "mpfr_t");
    }

    ret = mpfr_remainder(rop, op1, op2, rnd);

    return seed_value_from_int(ctx, ret, exception);
}
Beispiel #4
0
int
main (int argc, char *argv[])
{
  mpfr_t x, y, r;
  long q[1];

  if (argc == 3) /* usage: tremquo x y (rnd=MPFR_RNDN implicit) */
    {
      mpfr_init2 (x, GMP_NUMB_BITS);
      mpfr_init2 (y, GMP_NUMB_BITS);
      mpfr_init2 (r, GMP_NUMB_BITS);
      mpfr_set_str (x, argv[1], 10, MPFR_RNDN);
      mpfr_set_str (y, argv[2], 10, MPFR_RNDN);
      mpfr_remquo (r, q, x, y, MPFR_RNDN);
      printf ("r=");
      mpfr_out_str (stdout, 10, 0, r, MPFR_RNDN);
      printf (" q=%ld\n", q[0]);
      mpfr_clear (x);
      mpfr_clear (y);
      mpfr_clear (r);
      return 0;
    }

  tests_start_mpfr ();

  bug20090227 ();

  mpfr_init (x);
  mpfr_init (y);
  mpfr_init (r);

  /* special values */
  mpfr_set_nan (x);
  mpfr_set_ui (y, 1, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN(mpfr_nan_p (r));

  mpfr_set_ui (x, 1, MPFR_RNDN);
  mpfr_set_nan (y);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN(mpfr_nan_p (r));

  mpfr_set_inf (x, 1); /* +Inf */
  mpfr_set_ui (y, 1, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (r));

  mpfr_set_inf (x, 1); /* +Inf */
  mpfr_set_ui (y, 0, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (r));

  mpfr_set_inf (x, 1); /* +Inf */
  mpfr_set_inf (y, 1);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (r));

  mpfr_set_ui (x, 0, MPFR_RNDN);
  mpfr_set_inf (y, 1);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 0) == 0 && MPFR_IS_POS (r));
  MPFR_ASSERTN (q[0] == (long) 0);

  mpfr_set_ui (x, 0, MPFR_RNDN);
  mpfr_neg (x, x, MPFR_RNDN); /* -0 */
  mpfr_set_inf (y, 1);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 0) == 0 && MPFR_IS_NEG (r));
  MPFR_ASSERTN (q[0] == (long) 0);

  mpfr_set_ui (x, 17, MPFR_RNDN);
  mpfr_set_inf (y, 1);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp (r, x) == 0);
  MPFR_ASSERTN (q[0] == (long) 0);

  mpfr_set_ui (x, 17, MPFR_RNDN);
  mpfr_set_ui (y, 0, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (r));

  mpfr_set_ui (x, 0, MPFR_RNDN);
  mpfr_set_ui (y, 17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 0) == 0 && MPFR_IS_POS (r));
  MPFR_ASSERTN (q[0] == (long) 0);

  mpfr_set_ui (x, 0, MPFR_RNDN);
  mpfr_neg (x, x, MPFR_RNDN);
  mpfr_set_ui (y, 17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 0) == 0 && MPFR_IS_NEG (r));
  MPFR_ASSERTN (q[0] == (long) 0);

  mpfr_set_prec (x, 53);
  mpfr_set_prec (y, 53);

  /* check four possible sign combinations */
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_set_ui (y, 17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 8) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);
  mpfr_set_si (x, -42, MPFR_RNDN);
  mpfr_set_ui (y, 17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (r, -8) == 0);
  MPFR_ASSERTN (q[0] == (long) -2);
  mpfr_set_si (x, -42, MPFR_RNDN);
  mpfr_set_si (y, -17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (r, -8) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_set_si (y, -17, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (r, 8) == 0);
  MPFR_ASSERTN (q[0] == (long) -2);

  mpfr_set_prec (x, 100);
  mpfr_set_prec (y, 50);
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_nextabove (x); /* 42 + 2^(-94) */
  mpfr_set_ui (y, 21, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui_2exp (r, 1, -94) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);

  mpfr_set_prec (x, 50);
  mpfr_set_prec (y, 100);
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_nextabove (x); /* 42 + 2^(-44) */
  mpfr_set_ui (y, 21, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui_2exp (r, 1, -44) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);

  mpfr_set_prec (x, 100);
  mpfr_set_prec (y, 50);
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_set_ui (y, 21, MPFR_RNDN);
  mpfr_nextabove (y); /* 21 + 2^(-45) */
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* r should be 42 - 2*(21 + 2^(-45)) = -2^(-44) */
  MPFR_ASSERTN (mpfr_cmp_si_2exp (r, -1, -44) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);

  mpfr_set_prec (x, 50);
  mpfr_set_prec (y, 100);
  mpfr_set_ui (x, 42, MPFR_RNDN);
  mpfr_set_ui (y, 21, MPFR_RNDN);
  mpfr_nextabove (y); /* 21 + 2^(-95) */
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* r should be 42 - 2*(21 + 2^(-95)) = -2^(-94) */
  MPFR_ASSERTN (mpfr_cmp_si_2exp (r, -1, -94) == 0);
  MPFR_ASSERTN (q[0] == (long) 2);

  /* exercise large quotient */
  mpfr_set_ui_2exp (x, 1, 65, MPFR_RNDN);
  mpfr_set_ui (y, 1, MPFR_RNDN);
  /* quotient is 2^65 */
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (r, 0) == 0);
  MPFR_ASSERTN (q[0] % 1073741824L == 0L);

  /* another large quotient */
  mpfr_set_prec (x, 65);
  mpfr_set_prec (y, 65);
  mpfr_const_pi (x, MPFR_RNDN);
  mpfr_mul_2exp (x, x, 63, MPFR_RNDN);
  mpfr_const_log2 (y, MPFR_RNDN);
  mpfr_set_prec (r, 10);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* q should be 41803643793084085130, r should be 605/2048 */
  MPFR_ASSERTN (mpfr_cmp_ui_2exp (r, 605, -11) == 0);
  MPFR_ASSERTN ((q[0] > 0) && ((q[0] % 1073741824L) == 733836170L));

  /* check cases where quotient is 1.5 +/- eps */
  mpfr_set_prec (x, 65);
  mpfr_set_prec (y, 65);
  mpfr_set_prec (r, 63);
  mpfr_set_ui (x, 3, MPFR_RNDN);
  mpfr_set_ui (y, 2, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* x/y = 1.5, quotient should be 2 (even rule), remainder should be -1 */
  MPFR_ASSERTN (mpfr_cmp_si (r, -1) == 0);
  MPFR_ASSERTN (q[0] == 2L);
  mpfr_set_ui (x, 3, MPFR_RNDN);
  mpfr_nextabove (x); /* 3 + 2^(-63) */
  mpfr_set_ui (y, 2, MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* x/y = 1.5 + 2^(-64), quo should be 2, r should be -1 + 2^(-63) */
  MPFR_ASSERTN (mpfr_add_ui (r, r, 1, MPFR_RNDN) == 0);
  MPFR_ASSERTN (mpfr_cmp_ui_2exp (r, 1, -63) == 0);
  MPFR_ASSERTN (q[0] == 2L);
  mpfr_set_ui (x, 3, MPFR_RNDN);
  mpfr_set_ui (y, 2, MPFR_RNDN);
  mpfr_nextabove (y); /* 2 + 2^(-63) */
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  /* x/y = 1.5 - eps, quo should be 1, r should be 1 - 2^(-63) */
  MPFR_ASSERTN (mpfr_sub_ui (r, r, 1, MPFR_RNDN) == 0);
  MPFR_ASSERTN (mpfr_cmp_si_2exp (r, -1, -63) == 0);
  MPFR_ASSERTN (q[0] == 1L);

  /* bug founds by Kaveh Ghazi, 3 May 2007 */
  mpfr_set_ui (x, 2, MPFR_RNDN);
  mpfr_set_ui (y, 3, MPFR_RNDN);
  mpfr_remainder (r, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (r, -1) == 0);

  mpfr_set_si (x, -1, MPFR_RNDN);
  mpfr_set_ui (y, 1, MPFR_RNDN);
  mpfr_remainder (r, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (r, 0) == 0 && MPFR_SIGN (r) < 0);

  /* check argument reuse */
  mpfr_set_si (x, -1, MPFR_RNDN);
  mpfr_set_ui (y, 1, MPFR_RNDN);
  mpfr_remainder (x, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si (x, 0) == 0 && MPFR_SIGN (x) < 0);

  mpfr_set_ui_2exp (x, 1, mpfr_get_emax () - 1, MPFR_RNDN);
  mpfr_set_ui_2exp (y, 1, mpfr_get_emin (), MPFR_RNDN);
  mpfr_remquo (r, q, x, y, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_zero_p (r) && MPFR_SIGN (r) > 0);
  MPFR_ASSERTN (q[0] == 0);

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (r);

  tests_end_mpfr ();

  return 0;
}
Beispiel #5
0
/* (y, z) <- (sin(x), cos(x)), return value is 0 iff both results are exact
   ie, iff x = 0 */
int
mpfr_sin_cos (mpfr_ptr y, mpfr_ptr z, mpfr_srcptr x, mp_rnd_t rnd_mode)
{
  mp_prec_t prec, m;
  int neg, reduce;
  mpfr_t c, xr;
  mpfr_srcptr xx;
  mp_exp_t err, expx;
  MPFR_ZIV_DECL (loop);

  if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
    {
      if (MPFR_IS_NAN(x) || MPFR_IS_INF(x))
        {
          MPFR_SET_NAN (y);
          MPFR_SET_NAN (z);
          MPFR_RET_NAN;
        }
      else /* x is zero */
        {
          MPFR_ASSERTD (MPFR_IS_ZERO (x));
          MPFR_SET_ZERO (y);
          MPFR_SET_SAME_SIGN (y, x);
          /* y = 0, thus exact, but z is inexact in case of underflow
             or overflow */
          return mpfr_set_ui (z, 1, rnd_mode);
        }
    }

  MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode),
                  ("sin[%#R]=%R cos[%#R]=%R", y, y, z, z));

  prec = MAX (MPFR_PREC (y), MPFR_PREC (z));
  m = prec + MPFR_INT_CEIL_LOG2 (prec) + 13;
  expx = MPFR_GET_EXP (x);

  mpfr_init (c);
  mpfr_init (xr);

  MPFR_ZIV_INIT (loop, m);
  for (;;)
    {
      /* the following is copied from sin.c */
      if (expx >= 2) /* reduce the argument */
        {
          reduce = 1;
          mpfr_set_prec (c, expx + m - 1);
          mpfr_set_prec (xr, m);
          mpfr_const_pi (c, GMP_RNDN);
          mpfr_mul_2ui (c, c, 1, GMP_RNDN);
          mpfr_remainder (xr, x, c, GMP_RNDN);
          mpfr_div_2ui (c, c, 1, GMP_RNDN);
          if (MPFR_SIGN (xr) > 0)
            mpfr_sub (c, c, xr, GMP_RNDZ);
          else
            mpfr_add (c, c, xr, GMP_RNDZ);
          if (MPFR_IS_ZERO(xr) || MPFR_EXP(xr) < (mp_exp_t) 3 - (mp_exp_t) m
              || MPFR_EXP(c) < (mp_exp_t) 3 - (mp_exp_t) m)
            goto next_step;
          xx = xr;
        }
      else /* the input argument is already reduced */
        {
          reduce = 0;
          xx = x;
        }

      neg = MPFR_IS_NEG (xx); /* gives sign of sin(x) */
      mpfr_set_prec (c, m);
      mpfr_cos (c, xx, GMP_RNDZ);
      /* If no argument reduction was performed, the error is at most ulp(c),
         otherwise it is at most ulp(c) + 2^(2-m). Since |c| < 1, we have
         ulp(c) <= 2^(-m), thus the error is bounded by 2^(3-m) in that later
         case. */
      if (reduce == 0)
        err = m;
      else
        err = MPFR_GET_EXP (c) + (mp_exp_t) (m - 3);
      if (!mpfr_can_round (c, err, GMP_RNDN, rnd_mode,
                           MPFR_PREC (z) + (rnd_mode == GMP_RNDN)))
        goto next_step;

      mpfr_set (z, c, rnd_mode);
      mpfr_sqr (c, c, GMP_RNDU);
      mpfr_ui_sub (c, 1, c, GMP_RNDN);
      err = 2 + (- MPFR_GET_EXP (c)) / 2;
      mpfr_sqrt (c, c, GMP_RNDN);
      if (neg)
        MPFR_CHANGE_SIGN (c);

      /* the absolute error on c is at most 2^(err-m), which we must put
         in the form 2^(EXP(c)-err). If there was an argument reduction,
         we need to add 2^(2-m); since err >= 2, the error is bounded by
         2^(err+1-m) in that case. */
      err = MPFR_GET_EXP (c) + (mp_exp_t) m - (err + reduce);
      if (mpfr_can_round (c, err, GMP_RNDN, rnd_mode,
                          MPFR_PREC (y) + (rnd_mode == GMP_RNDN)))
        break;
      /* check for huge cancellation */
      if (err < (mp_exp_t) MPFR_PREC (y))
        m += MPFR_PREC (y) - err;
      /* Check if near 1 */
      if (MPFR_GET_EXP (c) == 1
          && MPFR_MANT (c)[MPFR_LIMB_SIZE (c)-1] == MPFR_LIMB_HIGHBIT)
        m += m;

    next_step:
      MPFR_ZIV_NEXT (loop, m);
      mpfr_set_prec (c, m);
    }
  MPFR_ZIV_FREE (loop);

  mpfr_set (y, c, rnd_mode);

  mpfr_clear (c);
  mpfr_clear (xr);

  MPFR_RET (1); /* Always inexact */
}
Beispiel #6
0
int
mpfr_cos (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
{
  mpfr_prec_t K0, K, precy, m, k, l;
  int inexact, reduce = 0;
  mpfr_t r, s, xr, c;
  mpfr_exp_t exps, cancel = 0, expx;
  MPFR_ZIV_DECL (loop);
  MPFR_SAVE_EXPO_DECL (expo);
  MPFR_GROUP_DECL (group);

  MPFR_LOG_FUNC (
    ("x[%Pu]=%*.Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
    ("y[%Pu]=%*.Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
     inexact));

  if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
    {
      if (MPFR_IS_NAN (x) || MPFR_IS_INF (x))
        {
          MPFR_SET_NAN (y);
          MPFR_RET_NAN;
        }
      else
        {
          MPFR_ASSERTD (MPFR_IS_ZERO (x));
          return mpfr_set_ui (y, 1, rnd_mode);
        }
    }

  MPFR_SAVE_EXPO_MARK (expo);

  /* cos(x) = 1-x^2/2 + ..., so error < 2^(2*EXP(x)-1) */
  expx = MPFR_GET_EXP (x);
  MPFR_SMALL_INPUT_AFTER_SAVE_EXPO (y, __gmpfr_one, -2 * expx,
                                    1, 0, rnd_mode, expo, {});

  /* Compute initial precision */
  precy = MPFR_PREC (y);

  if (precy >= MPFR_SINCOS_THRESHOLD)
    {
      MPFR_SAVE_EXPO_FREE (expo);
      return mpfr_cos_fast (y, x, rnd_mode);
    }

  K0 = __gmpfr_isqrt (precy / 3);
  m = precy + 2 * MPFR_INT_CEIL_LOG2 (precy) + 2 * K0;

  if (expx >= 3)
    {
      reduce = 1;
      /* As expx + m - 1 will silently be converted into mpfr_prec_t
         in the mpfr_init2 call, the assert below may be useful to
         avoid undefined behavior. */
      MPFR_ASSERTN (expx + m - 1 <= MPFR_PREC_MAX);
      mpfr_init2 (c, expx + m - 1);
      mpfr_init2 (xr, m);
    }

  MPFR_GROUP_INIT_2 (group, m, r, s);
  MPFR_ZIV_INIT (loop, m);
  for (;;)
    {
      /* If |x| >= 4, first reduce x cmod (2*Pi) into xr, using mpfr_remainder:
         let e = EXP(x) >= 3, and m the target precision:
         (1) c <- 2*Pi              [precision e+m-1, nearest]
         (2) xr <- remainder (x, c) [precision m, nearest]
         We have |c - 2*Pi| <= 1/2ulp(c) = 2^(3-e-m)
                 |xr - x - k c| <= 1/2ulp(xr) <= 2^(1-m)
                 |k| <= |x|/(2*Pi) <= 2^(e-2)
         Thus |xr - x - 2kPi| <= |k| |c - 2Pi| + 2^(1-m) <= 2^(2-m).
         It follows |cos(xr) - cos(x)| <= 2^(2-m). */
      if (reduce)
        {
          mpfr_const_pi (c, MPFR_RNDN);
          mpfr_mul_2ui (c, c, 1, MPFR_RNDN); /* 2Pi */
          mpfr_remainder (xr, x, c, MPFR_RNDN);
          if (MPFR_IS_ZERO(xr))
            goto ziv_next;
          /* now |xr| <= 4, thus r <= 16 below */
          mpfr_mul (r, xr, xr, MPFR_RNDU); /* err <= 1 ulp */
        }
      else
        mpfr_mul (r, x, x, MPFR_RNDU); /* err <= 1 ulp */

      /* now |x| < 4 (or xr if reduce = 1), thus |r| <= 16 */

      /* we need |r| < 1/2 for mpfr_cos2_aux, i.e., EXP(r) - 2K <= -1 */
      K = K0 + 1 + MAX(0, MPFR_GET_EXP(r)) / 2;
      /* since K0 >= 0, if EXP(r) < 0, then K >= 1, thus EXP(r) - 2K <= -3;
         otherwise if EXP(r) >= 0, then K >= 1/2 + EXP(r)/2, thus
         EXP(r) - 2K <= -1 */

      MPFR_SET_EXP (r, MPFR_GET_EXP (r) - 2 * K); /* Can't overflow! */

      /* s <- 1 - r/2! + ... + (-1)^l r^l/(2l)! */
      l = mpfr_cos2_aux (s, r);
      /* l is the error bound in ulps on s */
      MPFR_SET_ONE (r);
      for (k = 0; k < K; k++)
        {
          mpfr_sqr (s, s, MPFR_RNDU);            /* err <= 2*olderr */
          MPFR_SET_EXP (s, MPFR_GET_EXP (s) + 1); /* Can't overflow */
          mpfr_sub (s, s, r, MPFR_RNDN);         /* err <= 4*olderr */
          if (MPFR_IS_ZERO(s))
            goto ziv_next;
          MPFR_ASSERTD (MPFR_GET_EXP (s) <= 1);
        }

      /* The absolute error on s is bounded by (2l+1/3)*2^(2K-m)
         2l+1/3 <= 2l+1.
         If |x| >= 4, we need to add 2^(2-m) for the argument reduction
         by 2Pi: if K = 0, this amounts to add 4 to 2l+1/3, i.e., to add
         2 to l; if K >= 1, this amounts to add 1 to 2*l+1/3. */
      l = 2 * l + 1;
      if (reduce)
        l += (K == 0) ? 4 : 1;
      k = MPFR_INT_CEIL_LOG2 (l) + 2*K;
      /* now the error is bounded by 2^(k-m) = 2^(EXP(s)-err) */

      exps = MPFR_GET_EXP (s);
      if (MPFR_LIKELY (MPFR_CAN_ROUND (s, exps + m - k, precy, rnd_mode)))
        break;

      if (MPFR_UNLIKELY (exps == 1))
        /* s = 1 or -1, and except x=0 which was already checked above,
           cos(x) cannot be 1 or -1, so we can round if the error is less
           than 2^(-precy) for directed rounding, or 2^(-precy-1) for rounding
           to nearest. */
        {
          if (m > k && (m - k >= precy + (rnd_mode == MPFR_RNDN)))
            {
              /* If round to nearest or away, result is s = 1 or -1,
                 otherwise it is round(nexttoward (s, 0)). However in order to
                 have the inexact flag correctly set below, we set |s| to
                 1 - 2^(-m) in all cases. */
              mpfr_nexttozero (s);
              break;
            }
        }

      if (exps < cancel)
        {
          m += cancel - exps;
          cancel = exps;
        }

    ziv_next:
      MPFR_ZIV_NEXT (loop, m);
      MPFR_GROUP_REPREC_2 (group, m, r, s);
      if (reduce)
        {
          mpfr_set_prec (xr, m);
          mpfr_set_prec (c, expx + m - 1);
        }
    }
  MPFR_ZIV_FREE (loop);
  inexact = mpfr_set (y, s, rnd_mode);
  MPFR_GROUP_CLEAR (group);
  if (reduce)
    {
      mpfr_clear (xr);
      mpfr_clear (c);
    }

  MPFR_SAVE_EXPO_FREE (expo);
  return mpfr_check_range (y, inexact, rnd_mode);
}
Beispiel #7
0
int
mpfr_sin (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
{
  mpfr_t c, xr;
  mpfr_srcptr xx;
  mpfr_exp_t expx, err;
  mpfr_prec_t precy, m;
  int inexact, sign, reduce;
  MPFR_ZIV_DECL (loop);
  MPFR_SAVE_EXPO_DECL (expo);

  MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode),
                  ("y[%#R]=%R inexact=%d", y, y, inexact));

  if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
    {
      if (MPFR_IS_NAN (x) || MPFR_IS_INF (x))
        {
          MPFR_SET_NAN (y);
          MPFR_RET_NAN;

        }
      else /* x is zero */
        {
          MPFR_ASSERTD (MPFR_IS_ZERO (x));
          MPFR_SET_ZERO (y);
          MPFR_SET_SAME_SIGN (y, x);
          MPFR_RET (0);
        }
    }

  /* sin(x) = x - x^3/6 + ... so the error is < 2^(3*EXP(x)-2) */
  MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -2 * MPFR_GET_EXP (x), 2, 0,
                                    rnd_mode, {});

  MPFR_SAVE_EXPO_MARK (expo);

  /* Compute initial precision */
  precy = MPFR_PREC (y);

  if (precy >= MPFR_SINCOS_THRESHOLD)
    return mpfr_sin_fast (y, x, rnd_mode);

  m = precy + MPFR_INT_CEIL_LOG2 (precy) + 13;
  expx = MPFR_GET_EXP (x);

  mpfr_init (c);
  mpfr_init (xr);

  MPFR_ZIV_INIT (loop, m);
  for (;;)
    {
      /* first perform argument reduction modulo 2*Pi (if needed),
         also helps to determine the sign of sin(x) */
      if (expx >= 2) /* If Pi < x < 4, we need to reduce too, to determine
                        the sign of sin(x). For 2 <= |x| < Pi, we could avoid
                        the reduction. */
        {
          reduce = 1;
          /* As expx + m - 1 will silently be converted into mpfr_prec_t
             in the mpfr_set_prec call, the assert below may be useful to
             avoid undefined behavior. */
          MPFR_ASSERTN (expx + m - 1 <= MPFR_PREC_MAX);
          mpfr_set_prec (c, expx + m - 1);
          mpfr_set_prec (xr, m);
          mpfr_const_pi (c, MPFR_RNDN);
          mpfr_mul_2ui (c, c, 1, MPFR_RNDN);
          mpfr_remainder (xr, x, c, MPFR_RNDN);
          /* The analysis is similar to that of cos.c:
             |xr - x - 2kPi| <= 2^(2-m). Thus we can decide the sign
             of sin(x) if xr is at distance at least 2^(2-m) of both
             0 and +/-Pi. */
          mpfr_div_2ui (c, c, 1, MPFR_RNDN);
          /* Since c approximates Pi with an error <= 2^(2-expx-m) <= 2^(-m),
             it suffices to check that c - |xr| >= 2^(2-m). */
          if (MPFR_SIGN (xr) > 0)
            mpfr_sub (c, c, xr, MPFR_RNDZ);
          else
            mpfr_add (c, c, xr, MPFR_RNDZ);
          if (MPFR_IS_ZERO(xr)
              || MPFR_EXP(xr) < (mpfr_exp_t) 3 - (mpfr_exp_t) m
              || MPFR_EXP(c) < (mpfr_exp_t) 3 - (mpfr_exp_t) m)
            goto ziv_next;

          /* |xr - x - 2kPi| <= 2^(2-m), thus |sin(xr) - sin(x)| <= 2^(2-m) */
          xx = xr;
        }
      else /* the input argument is already reduced */
        {
          reduce = 0;
          xx = x;
        }

      sign = MPFR_SIGN(xx);
      /* now that the argument is reduced, precision m is enough */
      mpfr_set_prec (c, m);
      mpfr_cos (c, xx, MPFR_RNDZ);    /* can't be exact */
      mpfr_nexttoinf (c);           /* now c = cos(x) rounded away */
      mpfr_mul (c, c, c, MPFR_RNDU); /* away */
      mpfr_ui_sub (c, 1, c, MPFR_RNDZ);
      mpfr_sqrt (c, c, MPFR_RNDZ);
      if (MPFR_IS_NEG_SIGN(sign))
        MPFR_CHANGE_SIGN(c);

      /* Warning: c may be 0! */
      if (MPFR_UNLIKELY (MPFR_IS_ZERO (c)))
        {
          /* Huge cancellation: increase prec a lot! */
          m = MAX (m, MPFR_PREC (x));
          m = 2 * m;
        }
      else
        {
          /* the absolute error on c is at most 2^(3-m-EXP(c)),
             plus 2^(2-m) if there was an argument reduction.
             Since EXP(c) <= 1, 3-m-EXP(c) >= 2-m, thus the error
             is at most 2^(3-m-EXP(c)) in case of argument reduction. */
          err = 2 * MPFR_GET_EXP (c) + (mpfr_exp_t) m - 3 - (reduce != 0);
          if (MPFR_CAN_ROUND (c, err, precy, rnd_mode))
            break;

          /* check for huge cancellation (Near 0) */
          if (err < (mpfr_exp_t) MPFR_PREC (y))
            m += MPFR_PREC (y) - err;
          /* Check if near 1 */
          if (MPFR_GET_EXP (c) == 1)
            m += m;
        }

    ziv_next:
      /* Else generic increase */
      MPFR_ZIV_NEXT (loop, m);
    }
  MPFR_ZIV_FREE (loop);

  inexact = mpfr_set (y, c, rnd_mode);
  /* inexact cannot be 0, since this would mean that c was representable
     within the target precision, but in that case mpfr_can_round will fail */

  mpfr_clear (c);
  mpfr_clear (xr);

  MPFR_SAVE_EXPO_FREE (expo);
  return mpfr_check_range (y, inexact, rnd_mode);
}