Ejemplo n.º 1
0
int
mpfr_atan2 (mpfr_ptr dest, mpfr_srcptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
{
  mpfr_t tmp, pi;
  int inexact;
  mpfr_prec_t prec;
  mpfr_exp_t e;
  MPFR_SAVE_EXPO_DECL (expo);
  MPFR_ZIV_DECL (loop);

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

  /* Special cases */
  if (MPFR_ARE_SINGULAR (x, y))
    {
      /* atan2(0, 0) does not raise the "invalid" floating-point
         exception, nor does atan2(y, 0) raise the "divide-by-zero"
         floating-point exception.
         -- atan2(±0, -0) returns ±pi.313)
         -- atan2(±0, +0) returns ±0.
         -- atan2(±0, x) returns ±pi, for x < 0.
         -- atan2(±0, x) returns ±0, for x > 0.
         -- atan2(y, ±0) returns -pi/2 for y < 0.
         -- atan2(y, ±0) returns pi/2 for y > 0.
         -- atan2(±oo, -oo) returns ±3pi/4.
         -- atan2(±oo, +oo) returns ±pi/4.
         -- atan2(±oo, x) returns ±pi/2, for finite x.
         -- atan2(±y, -oo) returns ±pi, for finite y > 0.
         -- atan2(±y, +oo) returns ±0, for finite y > 0.
      */
      if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y))
        {
          MPFR_SET_NAN (dest);
          MPFR_RET_NAN;
        }
      if (MPFR_IS_ZERO (y))
        {
          if (MPFR_IS_NEG (x)) /* +/- PI */
            {
            set_pi:
              if (MPFR_IS_NEG (y))
                {
                  inexact =  mpfr_const_pi (dest, MPFR_INVERT_RND (rnd_mode));
                  MPFR_CHANGE_SIGN (dest);
                  return -inexact;
                }
              else
                return mpfr_const_pi (dest, rnd_mode);
            }
          else /* +/- 0 */
            {
            set_zero:
              MPFR_SET_ZERO (dest);
              MPFR_SET_SAME_SIGN (dest, y);
              return 0;
            }
        }
      if (MPFR_IS_ZERO (x))
        {
          return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode);
        }
      if (MPFR_IS_INF (y))
        {
          if (!MPFR_IS_INF (x)) /* +/- PI/2 */
            return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode);
          else if (MPFR_IS_POS (x)) /* +/- PI/4 */
            return pi_div_2ui (dest, 2, MPFR_IS_NEG (y), rnd_mode);
          else /* +/- 3*PI/4: Ugly since we have to round properly */
            {
              mpfr_t tmp2;
              MPFR_ZIV_DECL (loop2);
              mpfr_prec_t prec2 = MPFR_PREC (dest) + 10;

              MPFR_SAVE_EXPO_MARK (expo);
              mpfr_init2 (tmp2, prec2);
              MPFR_ZIV_INIT (loop2, prec2);
              for (;;)
                {
                  mpfr_const_pi (tmp2, MPFR_RNDN);
                  mpfr_mul_ui (tmp2, tmp2, 3, MPFR_RNDN); /* Error <= 2  */
                  mpfr_div_2ui (tmp2, tmp2, 2, MPFR_RNDN);
                  if (mpfr_round_p (MPFR_MANT (tmp2), MPFR_LIMB_SIZE (tmp2),
                                    MPFR_PREC (tmp2) - 2,
                                    MPFR_PREC (dest) + (rnd_mode == MPFR_RNDN)))
                    break;
                  MPFR_ZIV_NEXT (loop2, prec2);
                  mpfr_set_prec (tmp2, prec2);
                }
              MPFR_ZIV_FREE (loop2);
              if (MPFR_IS_NEG (y))
                MPFR_CHANGE_SIGN (tmp2);
              inexact = mpfr_set (dest, tmp2, rnd_mode);
              mpfr_clear (tmp2);
              MPFR_SAVE_EXPO_FREE (expo);
              return mpfr_check_range (dest, inexact, rnd_mode);
            }
        }
      MPFR_ASSERTD (MPFR_IS_INF (x));
      if (MPFR_IS_NEG (x))
        goto set_pi;
      else
        goto set_zero;
    }

  /* When x is a power of two, we call directly atan(y/x) since y/x is
     exact. */
  if (MPFR_UNLIKELY (MPFR_IS_POWER_OF_2 (x)))
    {
      int r;
      mpfr_t yoverx;
      unsigned int saved_flags = __gmpfr_flags;

      mpfr_init2 (yoverx, MPFR_PREC (y));
      if (MPFR_LIKELY (mpfr_div_2si (yoverx, y, MPFR_GET_EXP (x) - 1,
                                     MPFR_RNDN) == 0))
        {
          /* Here the flags have not changed due to mpfr_div_2si. */
          r = mpfr_atan (dest, yoverx, rnd_mode);
          mpfr_clear (yoverx);
          return r;
        }
      else
        {
          /* Division is inexact because of a small exponent range */
          mpfr_clear (yoverx);
          __gmpfr_flags = saved_flags;
        }
    }

  MPFR_SAVE_EXPO_MARK (expo);

  /* Set up initial prec */
  prec = MPFR_PREC (dest) + 3 + MPFR_INT_CEIL_LOG2 (MPFR_PREC (dest));
  mpfr_init2 (tmp, prec);

  MPFR_ZIV_INIT (loop, prec);
  if (MPFR_IS_POS (x))
    /* use atan2(y,x) = atan(y/x) */
    for (;;)
      {
        int div_inex;
        MPFR_BLOCK_DECL (flags);

        MPFR_BLOCK (flags, div_inex = mpfr_div (tmp, y, x, MPFR_RNDN));
        if (div_inex == 0)
          {
            /* Result is exact. */
            inexact = mpfr_atan (dest, tmp, rnd_mode);
            goto end;
          }

        /* Error <= ulp (tmp) except in case of underflow or overflow. */

        /* If the division underflowed, since |atan(z)/z| < 1, we have
           an underflow. */
        if (MPFR_UNDERFLOW (flags))
          {
            int sign;

            /* In the case MPFR_RNDN with 2^(emin-2) < |y/x| < 2^(emin-1):
               The smallest significand value S > 1 of |y/x| is:
                 * 1 / (1 - 2^(-px))                        if py <= px,
                 * (1 - 2^(-px) + 2^(-py)) / (1 - 2^(-px))  if py >= px.
               Therefore S - 1 > 2^(-pz), where pz = max(px,py). We have:
               atan(|y/x|) > atan(z), where z = 2^(emin-2) * (1 + 2^(-pz)).
                           > z - z^3 / 3.
                           > 2^(emin-2) * (1 + 2^(-pz) - 2^(2 emin - 5))
               Assuming pz <= -2 emin + 5, we can round away from zero
               (this is what mpfr_underflow always does on MPFR_RNDN).
               In the case MPFR_RNDN with |y/x| <= 2^(emin-2), we round
               toward zero, as |atan(z)/z| < 1. */
            MPFR_ASSERTN (MPFR_PREC_MAX <=
                          2 * (mpfr_uexp_t) - MPFR_EMIN_MIN + 5);
            if (rnd_mode == MPFR_RNDN && MPFR_IS_ZERO (tmp))
              rnd_mode = MPFR_RNDZ;
            sign = MPFR_SIGN (tmp);
            mpfr_clear (tmp);
            MPFR_SAVE_EXPO_FREE (expo);
            return mpfr_underflow (dest, rnd_mode, sign);
          }

        mpfr_atan (tmp, tmp, MPFR_RNDN);   /* Error <= 2*ulp (tmp) since
                                             abs(D(arctan)) <= 1 */
        /* TODO: check that the error bound is correct in case of overflow. */
        /* FIXME: Error <= ulp(tmp) ? */
        if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - 2, MPFR_PREC (dest),
                                         rnd_mode)))
          break;
        MPFR_ZIV_NEXT (loop, prec);
        mpfr_set_prec (tmp, prec);
      }
  else /* x < 0 */
    /*  Use sign(y)*(PI - atan (|y/x|)) */
    {
      mpfr_init2 (pi, prec);
      for (;;)
        {
          mpfr_div (tmp, y, x, MPFR_RNDN);   /* Error <= ulp (tmp) */
          /* If tmp is 0, we have |y/x| <= 2^(-emin-2), thus
             atan|y/x| < 2^(-emin-2). */
          MPFR_SET_POS (tmp);               /* no error */
          mpfr_atan (tmp, tmp, MPFR_RNDN);   /* Error <= 2*ulp (tmp) since
                                               abs(D(arctan)) <= 1 */
          mpfr_const_pi (pi, MPFR_RNDN);     /* Error <= ulp(pi) /2 */
          e = MPFR_NOTZERO(tmp) ? MPFR_GET_EXP (tmp) : __gmpfr_emin - 1;
          mpfr_sub (tmp, pi, tmp, MPFR_RNDN);          /* see above */
          if (MPFR_IS_NEG (y))
            MPFR_CHANGE_SIGN (tmp);
          /* Error(tmp) <= (1/2+2^(EXP(pi)-EXP(tmp)-1)+2^(e-EXP(tmp)+1))*ulp
                        <= 2^(MAX (MAX (EXP(PI)-EXP(tmp)-1, e-EXP(tmp)+1),
                                        -1)+2)*ulp(tmp) */
          e = MAX (MAX (MPFR_GET_EXP (pi)-MPFR_GET_EXP (tmp) - 1,
                        e - MPFR_GET_EXP (tmp) + 1), -1) + 2;
          if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - e, MPFR_PREC (dest),
                                           rnd_mode)))
            break;
          MPFR_ZIV_NEXT (loop, prec);
          mpfr_set_prec (tmp, prec);
          mpfr_set_prec (pi, prec);
        }
      mpfr_clear (pi);
    }
  inexact = mpfr_set (dest, tmp, rnd_mode);

 end:
  MPFR_ZIV_FREE (loop);
  mpfr_clear (tmp);
  MPFR_SAVE_EXPO_FREE (expo);
  return mpfr_check_range (dest, inexact, rnd_mode);
}
Ejemplo n.º 2
0
Archivo: trint.c Proyecto: epowers/mpfr
int
main (int argc, char *argv[])
{
  mp_size_t s;
  mpz_t z;
  mpfr_prec_t p;
  mpfr_t x, y, t, u, v;
  int r;
  int inexact, sign_t;

  tests_start_mpfr ();

  mpfr_init (x);
  mpfr_init (y);
  mpz_init (z);
  mpfr_init (t);
  mpfr_init (u);
  mpfr_init (v);
  mpz_set_ui (z, 1);
  for (s = 2; s < 100; s++)
    {
      /* z has exactly s bits */

      mpz_mul_2exp (z, z, 1);
      if (randlimb () % 2)
        mpz_add_ui (z, z, 1);
      mpfr_set_prec (x, s);
      mpfr_set_prec (t, s);
      mpfr_set_prec (u, s);
      if (mpfr_set_z (x, z, MPFR_RNDN))
        {
          printf ("Error: mpfr_set_z should be exact (s = %u)\n",
                  (unsigned int) s);
          exit (1);
        }
      if (randlimb () % 2)
        mpfr_neg (x, x, MPFR_RNDN);
      if (randlimb () % 2)
        mpfr_div_2ui (x, x, randlimb () % s, MPFR_RNDN);
      for (p = 2; p < 100; p++)
        {
          int trint;
          mpfr_set_prec (y, p);
          mpfr_set_prec (v, p);
          for (r = 0; r < MPFR_RND_MAX ; r++)
            for (trint = 0; trint < 3; trint++)
              {
                if (trint == 2)
                  inexact = mpfr_rint (y, x, (mpfr_rnd_t) r);
                else if (r == MPFR_RNDN)
                  inexact = mpfr_round (y, x);
                else if (r == MPFR_RNDZ)
                  inexact = (trint ? mpfr_trunc (y, x) :
                             mpfr_rint_trunc (y, x, MPFR_RNDZ));
                else if (r == MPFR_RNDU)
                  inexact = (trint ? mpfr_ceil (y, x) :
                             mpfr_rint_ceil (y, x, MPFR_RNDU));
                else /* r = MPFR_RNDD */
                  inexact = (trint ? mpfr_floor (y, x) :
                             mpfr_rint_floor (y, x, MPFR_RNDD));
                if (mpfr_sub (t, y, x, MPFR_RNDN))
                  err ("subtraction 1 should be exact",
                       s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                sign_t = mpfr_cmp_ui (t, 0);
                if (trint != 0 &&
                    (((inexact == 0) && (sign_t != 0)) ||
                     ((inexact < 0) && (sign_t >= 0)) ||
                     ((inexact > 0) && (sign_t <= 0))))
                  err ("wrong inexact flag", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                if (inexact == 0)
                  continue; /* end of the test for exact results */

                if (((r == MPFR_RNDD || (r == MPFR_RNDZ && MPFR_SIGN (x) > 0))
                     && inexact > 0) ||
                    ((r == MPFR_RNDU || (r == MPFR_RNDZ && MPFR_SIGN (x) < 0))
                     && inexact < 0))
                  err ("wrong rounding direction",
                       s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                if (inexact < 0)
                  {
                    mpfr_add_ui (v, y, 1, MPFR_RNDU);
                    if (mpfr_cmp (v, x) <= 0)
                      err ("representable integer between x and its "
                           "rounded value", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                  }
                else
                  {
                    mpfr_sub_ui (v, y, 1, MPFR_RNDD);
                    if (mpfr_cmp (v, x) >= 0)
                      err ("representable integer between x and its "
                           "rounded value", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                  }
                if (r == MPFR_RNDN)
                  {
                    int cmp;
                    if (mpfr_sub (u, v, x, MPFR_RNDN))
                      err ("subtraction 2 should be exact",
                           s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                    cmp = mpfr_cmp_abs (t, u);
                    if (cmp > 0)
                      err ("faithful rounding, but not the nearest integer",
                           s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                    if (cmp < 0)
                      continue;
                    /* |t| = |u|: x is the middle of two consecutive
                       representable integers. */
                    if (trint == 2)
                      {
                        /* halfway case for mpfr_rint in MPFR_RNDN rounding
                           mode: round to an even integer or significand. */
                        mpfr_div_2ui (y, y, 1, MPFR_RNDZ);
                        if (!mpfr_integer_p (y))
                          err ("halfway case for mpfr_rint, result isn't an"
                               " even integer", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                        /* If floor(x) and ceil(x) aren't both representable
                           integers, the significand must be even. */
                        mpfr_sub (v, v, y, MPFR_RNDN);
                        mpfr_abs (v, v, MPFR_RNDN);
                        if (mpfr_cmp_ui (v, 1) != 0)
                          {
                            mpfr_div_2si (y, y, MPFR_EXP (y) - MPFR_PREC (y)
                                          + 1, MPFR_RNDN);
                            if (!mpfr_integer_p (y))
                              err ("halfway case for mpfr_rint, significand isn't"
                                   " even", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                          }
                      }
                    else
                      { /* halfway case for mpfr_round: x must have been
                           rounded away from zero. */
                        if ((MPFR_SIGN (x) > 0 && inexact < 0) ||
                            (MPFR_SIGN (x) < 0 && inexact > 0))
                          err ("halfway case for mpfr_round, bad rounding"
                               " direction", s, x, y, p, (mpfr_rnd_t) r, trint, inexact);
                      }
                  }
              }
        }
    }
  mpfr_clear (x);
  mpfr_clear (y);
  mpz_clear (z);
  mpfr_clear (t);
  mpfr_clear (u);
  mpfr_clear (v);

  special ();
  coverage_03032011 ();

#if __MPFR_STDC (199901L)
  if (argc > 1 && strcmp (argv[1], "-s") == 0)
    test_against_libc ();
#endif

  tests_end_mpfr ();
  return 0;
}
Ejemplo n.º 3
0
Archivo: yn.c Proyecto: Kirija/XPIR
int
mpfr_yn (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r)
{
  int inex;
  unsigned long absn;
  MPFR_SAVE_EXPO_DECL (expo);

  MPFR_LOG_FUNC
    (("n=%ld x[%Pu]=%.*Rg rnd=%d", n, mpfr_get_prec (z), mpfr_log_prec, z, r),
     ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (res), mpfr_log_prec, res, inex));

  absn = SAFE_ABS (unsigned long, n);

  if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (z)))
    {
      if (MPFR_IS_NAN (z))
        {
          MPFR_SET_NAN (res); /* y(n,NaN) = NaN */
          MPFR_RET_NAN;
        }
      /* y(n,z) tends to zero when z goes to +Inf, oscillating around
         0. We choose to return +0 in that case. */
      else if (MPFR_IS_INF (z))
        {
          if (MPFR_SIGN(z) > 0)
            return mpfr_set_ui (res, 0, r);
          else /* y(n,-Inf) = NaN */
            {
              MPFR_SET_NAN (res);
              MPFR_RET_NAN;
            }
        }
      else /* y(n,z) tends to -Inf for n >= 0 or n even, to +Inf otherwise,
              when z goes to zero */
        {
          MPFR_SET_INF(res);
          if (n >= 0 || ((unsigned long) n & 1) == 0)
            MPFR_SET_NEG(res);
          else
            MPFR_SET_POS(res);
          mpfr_set_divby0 ();
          MPFR_RET(0);
        }
    }

  /* for z < 0, y(n,z) is imaginary except when j(n,|z|) = 0, which we
     assume does not happen for a rational z. */
  if (MPFR_SIGN(z) < 0)
    {
      MPFR_SET_NAN (res);
      MPFR_RET_NAN;
    }

  /* now z is not singular, and z > 0 */

  MPFR_SAVE_EXPO_MARK (expo);

  /* Deal with tiny arguments. We have:
     y0(z) = 2 log(z)/Pi + 2 (euler - log(2))/Pi + O(log(z)*z^2), more
     precisely for 0 <= z <= 1/2, with g(z) = 2/Pi + 2(euler-log(2))/Pi/log(z),
                g(z) - 0.41*z^2 < y0(z)/log(z) < g(z)
     thus since log(z) is negative:
             g(z)*log(z) < y0(z) < (g(z) - z^2/2)*log(z)
     and since |g(z)| >= 0.63 for 0 <= z <= 1/2, the relative error on
     y0(z)/log(z) is bounded by 0.41*z^2/0.63 <= 0.66*z^2.
     Note: we use both the main term in log(z) and the constant term, because
     otherwise the relative error would be only in 1/log(|log(z)|).
  */
  if (n == 0 && MPFR_EXP(z) < - (mpfr_exp_t) (MPFR_PREC(res) / 2))
    {
      mpfr_t l, h, t, logz;
      mpfr_prec_t prec;
      int ok, inex2;

      prec = MPFR_PREC(res) + 10;
      mpfr_init2 (l, prec);
      mpfr_init2 (h, prec);
      mpfr_init2 (t, prec);
      mpfr_init2 (logz, prec);
      /* first enclose log(z) + euler - log(2) = log(z/2) + euler */
      mpfr_log (logz, z, MPFR_RNDD);    /* lower bound of log(z) */
      mpfr_set (h, logz, MPFR_RNDU);    /* exact */
      mpfr_nextabove (h);              /* upper bound of log(z) */
      mpfr_const_euler (t, MPFR_RNDD);  /* lower bound of euler */
      mpfr_add (l, logz, t, MPFR_RNDD); /* lower bound of log(z) + euler */
      mpfr_nextabove (t);              /* upper bound of euler */
      mpfr_add (h, h, t, MPFR_RNDU);    /* upper bound of log(z) + euler */
      mpfr_const_log2 (t, MPFR_RNDU);   /* upper bound of log(2) */
      mpfr_sub (l, l, t, MPFR_RNDD);    /* lower bound of log(z/2) + euler */
      mpfr_nextbelow (t);              /* lower bound of log(2) */
      mpfr_sub (h, h, t, MPFR_RNDU);    /* upper bound of log(z/2) + euler */
      mpfr_const_pi (t, MPFR_RNDU);     /* upper bound of Pi */
      mpfr_div (l, l, t, MPFR_RNDD);    /* lower bound of (log(z/2)+euler)/Pi */
      mpfr_nextbelow (t);              /* lower bound of Pi */
      mpfr_div (h, h, t, MPFR_RNDD);    /* upper bound of (log(z/2)+euler)/Pi */
      mpfr_mul_2ui (l, l, 1, MPFR_RNDD); /* lower bound on g(z)*log(z) */
      mpfr_mul_2ui (h, h, 1, MPFR_RNDU); /* upper bound on g(z)*log(z) */
      /* we now have l <= g(z)*log(z) <= h, and we need to add -z^2/2*log(z)
         to h */
      mpfr_mul (t, z, z, MPFR_RNDU);     /* upper bound on z^2 */
      /* since logz is negative, a lower bound corresponds to an upper bound
         for its absolute value */
      mpfr_neg (t, t, MPFR_RNDD);
      mpfr_div_2ui (t, t, 1, MPFR_RNDD);
      mpfr_mul (t, t, logz, MPFR_RNDU); /* upper bound on z^2/2*log(z) */
      mpfr_add (h, h, t, MPFR_RNDU);
      inex = mpfr_prec_round (l, MPFR_PREC(res), r);
      inex2 = mpfr_prec_round (h, MPFR_PREC(res), r);
      /* we need h=l and inex=inex2 */
      ok = (inex == inex2) && mpfr_equal_p (l, h);
      if (ok)
        mpfr_set (res, h, r); /* exact */
      mpfr_clear (l);
      mpfr_clear (h);
      mpfr_clear (t);
      mpfr_clear (logz);
      if (ok)
        goto end;
    }

  /* small argument check for y1(z) = -2/Pi/z + O(log(z)):
     for 0 <= z <= 1, |y1(z) + 2/Pi/z| <= 0.25 */
  if (n == 1 && MPFR_EXP(z) + 1 < - (mpfr_exp_t) MPFR_PREC(res))
    {
      mpfr_t y;
      mpfr_prec_t prec;
      mpfr_exp_t err1;
      int ok;
      MPFR_BLOCK_DECL (flags);

      /* since 2/Pi > 0.5, and |y1(z)| >= |2/Pi/z|, if z <= 2^(-emax-1),
         then |y1(z)| > 2^emax */
      prec = MPFR_PREC(res) + 10;
      mpfr_init2 (y, prec);
      mpfr_const_pi (y, MPFR_RNDU); /* Pi*(1+u)^2, where here and below u
                                      represents a quantity <= 1/2^prec */
      mpfr_mul (y, y, z, MPFR_RNDU); /* Pi*z * (1+u)^4, upper bound */
      MPFR_BLOCK (flags, mpfr_ui_div (y, 2, y, MPFR_RNDZ));
      /* 2/Pi/z * (1+u)^6, lower bound, with possible overflow */
      if (MPFR_OVERFLOW (flags))
        {
          mpfr_clear (y);
          MPFR_SAVE_EXPO_FREE (expo);
          return mpfr_overflow (res, r, -1);
        }
      mpfr_neg (y, y, MPFR_RNDN);
      /* (1+u)^6 can be written 1+7u [for another value of u], thus the
         error on 2/Pi/z is less than 7ulp(y). The truncation error is less
         than 1/4, thus if ulp(y)>=1/4, the total error is less than 8ulp(y),
         otherwise it is less than 1/4+7/8 <= 2. */
      if (MPFR_EXP(y) + 2 >= MPFR_PREC(y)) /* ulp(y) >= 1/4 */
        err1 = 3;
      else /* ulp(y) <= 1/8 */
        err1 = (mpfr_exp_t) MPFR_PREC(y) - MPFR_EXP(y) + 1;
      ok = MPFR_CAN_ROUND (y, prec - err1, MPFR_PREC(res), r);
      if (ok)
        inex = mpfr_set (res, y, r);
      mpfr_clear (y);
      if (ok)
        goto end;
    }

  /* we can use the asymptotic expansion as soon as z > p log(2)/2,
     but to get some margin we use it for z > p/2 */
  if (mpfr_cmp_ui (z, MPFR_PREC(res) / 2 + 3) > 0)
    {
      inex = mpfr_yn_asympt (res, n, z, r);
      if (inex != 0)
        goto end;
    }

  /* General case */
  {
    mpfr_prec_t prec;
    mpfr_exp_t err1, err2, err3;
    mpfr_t y, s1, s2, s3;
    MPFR_ZIV_DECL (loop);

    mpfr_init (y);
    mpfr_init (s1);
    mpfr_init (s2);
    mpfr_init (s3);

    prec = MPFR_PREC(res) + 2 * MPFR_INT_CEIL_LOG2 (MPFR_PREC (res)) + 13;
    MPFR_ZIV_INIT (loop, prec);
    for (;;)
      {
        mpfr_set_prec (y, prec);
        mpfr_set_prec (s1, prec);
        mpfr_set_prec (s2, prec);
        mpfr_set_prec (s3, prec);

        mpfr_mul (y, z, z, MPFR_RNDN);
        mpfr_div_2ui (y, y, 2, MPFR_RNDN); /* z^2/4 */

        /* store (z/2)^n temporarily in s2 */
        mpfr_pow_ui (s2, z, absn, MPFR_RNDN);
        mpfr_div_2si (s2, s2, absn, MPFR_RNDN);

        /* compute S1 * (z/2)^(-n) */
        if (n == 0)
          {
            mpfr_set_ui (s1, 0, MPFR_RNDN);
            err1 = 0;
          }
        else
          err1 = mpfr_yn_s1 (s1, y, absn - 1);
        mpfr_div (s1, s1, s2, MPFR_RNDN); /* (z/2)^(-n) * S1 */
        /* See algorithms.tex: the relative error on s1 is bounded by
           (3n+3)*2^(e+1-prec). */
        err1 = MPFR_INT_CEIL_LOG2 (3 * absn + 3) + err1 + 1;
        /* rel_err(s1) <= 2^(err1-prec), thus err(s1) <= 2^err1 ulps */

        /* compute (z/2)^n * S3 */
        mpfr_neg (y, y, MPFR_RNDN); /* -z^2/4 */
        err3 = mpfr_yn_s3 (s3, y, s2, absn); /* (z/2)^n * S3 */
        /* the error on s3 is bounded by 2^err3 ulps */

        /* add s1+s3 */
        err1 += MPFR_EXP(s1);
        mpfr_add (s1, s1, s3, MPFR_RNDN);
        /* the error is bounded by 1/2 + 2^err1*2^(- EXP(s1))
           + 2^err3*2^(EXP(s3) - EXP(s1)) */
        err3 += MPFR_EXP(s3);
        err1 = (err3 > err1) ? err3 + 1 : err1 + 1;
        err1 -= MPFR_EXP(s1);
        err1 = (err1 >= 0) ? err1 + 1 : 1;
        /* now the error on s1 is bounded by 2^err1*ulp(s1) */

        /* compute S2 */
        mpfr_div_2ui (s2, z, 1, MPFR_RNDN); /* z/2 */
        mpfr_log (s2, s2, MPFR_RNDN); /* log(z/2) */
        mpfr_const_euler (s3, MPFR_RNDN);
        err2 = MPFR_EXP(s2) > MPFR_EXP(s3) ? MPFR_EXP(s2) : MPFR_EXP(s3);
        mpfr_add (s2, s2, s3, MPFR_RNDN); /* log(z/2) + gamma */
        err2 -= MPFR_EXP(s2);
        mpfr_mul_2ui (s2, s2, 1, MPFR_RNDN); /* 2*(log(z/2) + gamma) */
        mpfr_jn (s3, absn, z, MPFR_RNDN); /* Jn(z) */
        mpfr_mul (s2, s2, s3, MPFR_RNDN); /* 2*(log(z/2) + gamma)*Jn(z) */
        err2 += 4; /* the error on s2 is bounded by 2^err2 ulps, see
                      algorithms.tex */

        /* add all three sums */
        err1 += MPFR_EXP(s1); /* the error on s1 is bounded by 2^err1 */
        err2 += MPFR_EXP(s2); /* the error on s2 is bounded by 2^err2 */
        mpfr_sub (s2, s2, s1, MPFR_RNDN); /* s2 - (s1+s3) */
        err2 = (err1 > err2) ? err1 + 1 : err2 + 1;
        err2 -= MPFR_EXP(s2);
        err2 = (err2 >= 0) ? err2 + 1 : 1;
        /* now the error on s2 is bounded by 2^err2*ulp(s2) */
        mpfr_const_pi (y, MPFR_RNDN); /* error bounded by 1 ulp */
        mpfr_div (s2, s2, y, MPFR_RNDN); /* error bounded by
                                           2^(err2+1)*ulp(s2) */
        err2 ++;

        if (MPFR_LIKELY (MPFR_CAN_ROUND (s2, prec - err2, MPFR_PREC(res), r)))
          break;
        MPFR_ZIV_NEXT (loop, prec);
      }
    MPFR_ZIV_FREE (loop);

    /* Assume two's complement for the test n & 1 */
    inex = mpfr_set4 (res, s2, r, n >= 0 || (n & 1) == 0 ?
                      MPFR_SIGN (s2) : - MPFR_SIGN (s2));

    mpfr_clear (y);
    mpfr_clear (s1);
    mpfr_clear (s2);
    mpfr_clear (s3);
  }

 end:
  MPFR_SAVE_EXPO_FREE (expo);
  return mpfr_check_range (res, inex, r);
}
Ejemplo n.º 4
0
/* Put in y an approximation of erfc(x) for large x, using formulae 7.1.23 and
   7.1.24 from Abramowitz and Stegun.
   Returns e such that the error is bounded by 2^e ulp(y),
   or returns 0 in case of underflow.
*/
static mpfr_exp_t
mpfr_erfc_asympt (mpfr_ptr y, mpfr_srcptr x)
{
    mpfr_t t, xx, err;
    unsigned long k;
    mpfr_prec_t prec = MPFR_PREC(y);
    mpfr_exp_t exp_err;

    mpfr_init2 (t, prec);
    mpfr_init2 (xx, prec);
    mpfr_init2 (err, 31);
    /* let u = 2^(1-p), and let us represent the error as (1+u)^err
       with a bound for err */
    mpfr_mul (xx, x, x, MPFR_RNDD); /* err <= 1 */
    mpfr_ui_div (xx, 1, xx, MPFR_RNDU); /* upper bound for 1/(2x^2), err <= 2 */
    mpfr_div_2ui (xx, xx, 1, MPFR_RNDU); /* exact */
    mpfr_set_ui (t, 1, MPFR_RNDN); /* current term, exact */
    mpfr_set (y, t, MPFR_RNDN);    /* current sum  */
    mpfr_set_ui (err, 0, MPFR_RNDN);
    for (k = 1; ; k++)
    {
        mpfr_mul_ui (t, t, 2 * k - 1, MPFR_RNDU); /* err <= 4k-3 */
        mpfr_mul (t, t, xx, MPFR_RNDU);           /* err <= 4k */
        /* for -1 < x < 1, and |nx| < 1, we have |(1+x)^n| <= 1+7/4|nx|.
           Indeed, for x>=0: log((1+x)^n) = n*log(1+x) <= n*x. Let y=n*x < 1,
           then exp(y) <= 1+7/4*y.
           For x<=0, let x=-x, we can prove by induction that (1-x)^n >= 1-n*x.*/
        mpfr_mul_2si (err, err, MPFR_GET_EXP (y) - MPFR_GET_EXP (t), MPFR_RNDU);
        mpfr_add_ui (err, err, 14 * k, MPFR_RNDU); /* 2^(1-p) * t <= 2 ulp(t) */
        mpfr_div_2si (err, err, MPFR_GET_EXP (y) - MPFR_GET_EXP (t), MPFR_RNDU);
        if (MPFR_GET_EXP (t) + (mpfr_exp_t) prec <= MPFR_GET_EXP (y))
        {
            /* the truncation error is bounded by |t| < ulp(y) */
            mpfr_add_ui (err, err, 1, MPFR_RNDU);
            break;
        }
        if (k & 1)
            mpfr_sub (y, y, t, MPFR_RNDN);
        else
            mpfr_add (y, y, t, MPFR_RNDN);
    }
    /* the error on y is bounded by err*ulp(y) */
    mpfr_mul (t, x, x, MPFR_RNDU); /* rel. err <= 2^(1-p) */
    mpfr_div_2ui (err, err, 3, MPFR_RNDU);  /* err/8 */
    mpfr_add (err, err, t, MPFR_RNDU);      /* err/8 + xx */
    mpfr_mul_2ui (err, err, 3, MPFR_RNDU);  /* err + 8*xx */
    mpfr_exp (t, t, MPFR_RNDU); /* err <= 1/2*ulp(t) + err(x*x)*t
                                <= 1/2*ulp(t)+2*|x*x|*ulp(t)
                                <= (2*|x*x|+1/2)*ulp(t) */
    mpfr_mul (t, t, x, MPFR_RNDN); /* err <= 1/2*ulp(t) + (4*|x*x|+1)*ulp(t)
                                   <= (4*|x*x|+3/2)*ulp(t) */
    mpfr_const_pi (xx, MPFR_RNDZ); /* err <= ulp(Pi) */
    mpfr_sqrt (xx, xx, MPFR_RNDN); /* err <= 1/2*ulp(xx) + ulp(Pi)/2/sqrt(Pi)
                                   <= 3/2*ulp(xx) */
    mpfr_mul (t, t, xx, MPFR_RNDN); /* err <= (8 |xx| + 13/2) * ulp(t) */
    mpfr_div (y, y, t, MPFR_RNDN); /* the relative error on input y is bounded
                                   by (1+u)^err with u = 2^(1-p), that on
                                   t is bounded by (1+u)^(8 |xx| + 13/2),
                                   thus that on output y is bounded by
                                   8 |xx| + 7 + err. */

    if (MPFR_IS_ZERO(y))
    {
        /* If y is zero, most probably we have underflow. We check it directly
           using the fact that erfc(x) <= exp(-x^2)/sqrt(Pi)/x for x >= 0.
           We compute an upper approximation of exp(-x^2)/sqrt(Pi)/x.
        */
        mpfr_mul (t, x, x, MPFR_RNDD); /* t <= x^2 */
        mpfr_neg (t, t, MPFR_RNDU);    /* -x^2 <= t */
        mpfr_exp (t, t, MPFR_RNDU);    /* exp(-x^2) <= t */
        mpfr_const_pi (xx, MPFR_RNDD); /* xx <= sqrt(Pi), cached */
        mpfr_mul (xx, xx, x, MPFR_RNDD); /* xx <= sqrt(Pi)*x */
        mpfr_div (y, t, xx, MPFR_RNDN); /* if y is zero, this means that the upper
                                        approximation of exp(-x^2)/sqrt(Pi)/x
                                        is nearer from 0 than from 2^(-emin-1),
                                        thus we have underflow. */
        exp_err = 0;
    }
    else
    {
        mpfr_add_ui (err, err, 7, MPFR_RNDU);
        exp_err = MPFR_GET_EXP (err);
    }

    mpfr_clear (t);
    mpfr_clear (xx);
    mpfr_clear (err);
    return exp_err;
}
Ejemplo n.º 5
0
Archivo: div_ui.c Proyecto: Kirija/XPIR
/* returns 0 if result exact, non-zero otherwise */
int
mpfr_div_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mpfr_rnd_t rnd_mode)
{
  long i;
  int sh;
  mp_size_t xn, yn, dif;
  mp_limb_t *xp, *yp, *tmp, c, d;
  mpfr_exp_t exp;
  int inexact, middle = 1, nexttoinf;
  MPFR_TMP_DECL(marker);

  MPFR_LOG_FUNC
    (("x[%Pu]=%.*Rg u=%lu rnd=%d",
      mpfr_get_prec(x), mpfr_log_prec, x, u, 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_SET_NAN (y);
          MPFR_RET_NAN;
        }
      else if (MPFR_IS_INF (x))
        {
          MPFR_SET_INF (y);
          MPFR_SET_SAME_SIGN (y, x);
          MPFR_RET (0);
        }
      else
        {
          MPFR_ASSERTD (MPFR_IS_ZERO(x));
          if (u == 0) /* 0/0 is NaN */
            {
              MPFR_SET_NAN(y);
              MPFR_RET_NAN;
            }
          else
            {
              MPFR_SET_ZERO(y);
              MPFR_SET_SAME_SIGN (y, x);
              MPFR_RET(0);
            }
        }
    }
  else if (MPFR_UNLIKELY (u <= 1))
    {
      if (u < 1)
        {
          /* x/0 is Inf since x != 0*/
          MPFR_SET_INF (y);
          MPFR_SET_SAME_SIGN (y, x);
          mpfr_set_divby0 ();
          MPFR_RET (0);
        }
      else /* y = x/1 = x */
        return mpfr_set (y, x, rnd_mode);
    }
  else if (MPFR_UNLIKELY (IS_POW2 (u)))
    return mpfr_div_2si (y, x, MPFR_INT_CEIL_LOG2 (u), rnd_mode);

  MPFR_SET_SAME_SIGN (y, x);

  MPFR_TMP_MARK (marker);
  xn = MPFR_LIMB_SIZE (x);
  yn = MPFR_LIMB_SIZE (y);

  xp = MPFR_MANT (x);
  yp = MPFR_MANT (y);
  exp = MPFR_GET_EXP (x);

  dif = yn + 1 - xn;

  /* we need to store yn+1 = xn + dif limbs of the quotient */
  /* don't use tmp=yp since the mpn_lshift call below requires yp >= tmp+1 */
  tmp = MPFR_TMP_LIMBS_ALLOC (yn + 1);

  c = (mp_limb_t) u;
  MPFR_ASSERTN (u == c);
  if (dif >= 0)
    c = mpn_divrem_1 (tmp, dif, xp, xn, c); /* used all the dividend */
  else /* dif < 0 i.e. xn > yn, don't use the (-dif) low limbs from x */
    c = mpn_divrem_1 (tmp, 0, xp - dif, yn + 1, c);

  inexact = (c != 0);

  /* First pass in estimating next bit of the quotient, in case of RNDN    *
   * In case we just have the right number of bits (postpone this ?),      *
   * we need to check whether the remainder is more or less than half      *
   * the divisor. The test must be performed with a subtraction, so as     *
   * to prevent carries.                                                   */

  if (MPFR_LIKELY (rnd_mode == MPFR_RNDN))
    {
      if (c < (mp_limb_t) u - c) /* We have u > c */
        middle = -1;
      else if (c > (mp_limb_t) u - c)
        middle = 1;
      else
        middle = 0; /* exactly in the middle */
    }

  /* If we believe that we are right in the middle or exact, we should check
     that we did not neglect any word of x (division large / 1 -> small). */

  for (i=0; ((inexact == 0) || (middle == 0)) && (i < -dif); i++)
    if (xp[i])
      inexact = middle = 1; /* larger than middle */

  /*
     If the high limb of the result is 0 (xp[xn-1] < u), remove it.
     Otherwise, compute the left shift to be performed to normalize.
     In the latter case, we discard some low bits computed. They
     contain information useful for the rounding, hence the updating
     of middle and inexact.
  */

  if (tmp[yn] == 0)
    {
      MPN_COPY(yp, tmp, yn);
      exp -= GMP_NUMB_BITS;
    }
  else
    {
      int shlz;

      count_leading_zeros (shlz, tmp[yn]);

      /* shift left to normalize */
      if (MPFR_LIKELY (shlz != 0))
        {
          mp_limb_t w = tmp[0] << shlz;

          mpn_lshift (yp, tmp + 1, yn, shlz);
          yp[0] += tmp[0] >> (GMP_NUMB_BITS - shlz);

          if (w > (MPFR_LIMB_ONE << (GMP_NUMB_BITS - 1)))
            { middle = 1; }
          else if (w < (MPFR_LIMB_ONE << (GMP_NUMB_BITS - 1)))
            { middle = -1; }
          else
            { middle = (c != 0); }

          inexact = inexact || (w != 0);
          exp -= shlz;
        }
      else
        { /* this happens only if u == 1 and xp[xn-1] >=
Ejemplo n.º 6
0
static void
underflow (mpfr_exp_t e)
{
  mpfr_t x, y, z1, z2;
  mpfr_exp_t emin;
  int i, k;
  int prec;
  int rnd;
  int div;
  int inex1, inex2;
  unsigned int flags1, flags2;

  /* Test mul_2si(x, e - k), div_2si(x, k - e) and div_2ui(x, k - e)
   * with emin = e, x = 1 + i/16, i in { -1, 0, 1 }, and k = 1 to 4,
   * by comparing the result with the one of a simple division.
   */
  emin = mpfr_get_emin ();
  set_emin (e);
  mpfr_inits2 (8, x, y, (mpfr_ptr) 0);
  for (i = 15; i <= 17; i++)
    {
      inex1 = mpfr_set_ui_2exp (x, i, -4, MPFR_RNDN);
      MPFR_ASSERTN (inex1 == 0);
      for (prec = 6; prec >= 3; prec -= 3)
        {
          mpfr_inits2 (prec, z1, z2, (mpfr_ptr) 0);
          RND_LOOP (rnd)
            for (k = 1; k <= 4; k++)
              {
                /* The following one is assumed to be correct. */
                inex1 = mpfr_mul_2si (y, x, e, MPFR_RNDN);
                MPFR_ASSERTN (inex1 == 0);
                inex1 = mpfr_set_ui (z1, 1 << k, MPFR_RNDN);
                MPFR_ASSERTN (inex1 == 0);
                mpfr_clear_flags ();
                /* Do not use mpfr_div_ui to avoid the optimization
                   by mpfr_div_2si. */
                inex1 = mpfr_div (z1, y, z1, (mpfr_rnd_t) rnd);
                flags1 = __gmpfr_flags;

              for (div = 0; div <= 2; div++)
                {
                  mpfr_clear_flags ();
                  inex2 = div == 0 ?
                    mpfr_mul_2si (z2, x, e - k, (mpfr_rnd_t) rnd) : div == 1 ?
                    mpfr_div_2si (z2, x, k - e, (mpfr_rnd_t) rnd) :
                    mpfr_div_2ui (z2, x, k - e, (mpfr_rnd_t) rnd);
                  flags2 = __gmpfr_flags;
                  if (flags1 == flags2 && SAME_SIGN (inex1, inex2) &&
                      mpfr_equal_p (z1, z2))
                    continue;
                  printf ("Error in underflow(");
                  if (e == MPFR_EMIN_MIN)
                    printf ("MPFR_EMIN_MIN");
                  else if (e == emin)
                    printf ("default emin");
                  else if (e >= LONG_MIN)
                    printf ("%ld", (long) e);
                  else
                    printf ("<LONG_MIN");
                  printf (") with mpfr_%s,\nx = %d/16, prec = %d, k = %d, "
                          "%s\n", div == 0 ? "mul_2si" : div == 1 ?
                          "div_2si" : "div_2ui", i, prec, k,
                          mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                  printf ("Expected ");
                  mpfr_out_str (stdout, 16, 0, z1, MPFR_RNDN);
                  printf (", inex = %d, flags = %u\n", SIGN (inex1), flags1);
                  printf ("Got      ");
                  mpfr_out_str (stdout, 16, 0, z2, MPFR_RNDN);
                  printf (", inex = %d, flags = %u\n", SIGN (inex2), flags2);
                  exit (1);
                }  /* div */
              }  /* k */
          mpfr_clears (z1, z2, (mpfr_ptr) 0);
        }  /* prec */
    }  /* i */
  mpfr_clears (x, y, (mpfr_ptr) 0);
  set_emin (emin);
}
Ejemplo n.º 7
0
static void
large (mpfr_exp_t e)
{
  mpfr_t x, y, z;
  mpfr_exp_t emax;
  int inex;
  unsigned int flags;

  emax = mpfr_get_emax ();
  set_emax (e);
  mpfr_init2 (x, 8);
  mpfr_init2 (y, 8);
  mpfr_init2 (z, 4);

  mpfr_set_inf (x, 1);
  mpfr_nextbelow (x);

  mpfr_mul_2si (y, x, -1, MPFR_RNDU);
  mpfr_prec_round (y, 4, MPFR_RNDU);

  mpfr_clear_flags ();
  inex = mpfr_mul_2si (z, x, -1, MPFR_RNDU);
  flags = __gmpfr_flags;

  if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
    {
      printf ("Error in large(");
      if (e == MPFR_EMAX_MAX)
        printf ("MPFR_EMAX_MAX");
      else if (e == emax)
        printf ("default emax");
      else if (e <= LONG_MAX)
        printf ("%ld", (long) e);
      else
        printf (">LONG_MAX");
      printf (") for mpfr_mul_2si\n");
      printf ("Expected inex > 0, flags = %u,\n         y = ",
              (unsigned int) MPFR_FLAGS_INEXACT);
      mpfr_dump (y);
      printf ("Got      inex = %d, flags = %u,\n         y = ",
              inex, flags);
      mpfr_dump (z);
      exit (1);
    }

  mpfr_clear_flags ();
  inex = mpfr_div_2si (z, x, 1, MPFR_RNDU);
  flags = __gmpfr_flags;

  if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
    {
      printf ("Error in large(");
      if (e == MPFR_EMAX_MAX)
        printf ("MPFR_EMAX_MAX");
      else if (e == emax)
        printf ("default emax");
      else if (e <= LONG_MAX)
        printf ("%ld", (long) e);
      else
        printf (">LONG_MAX");
      printf (") for mpfr_div_2si\n");
      printf ("Expected inex > 0, flags = %u,\n         y = ",
              (unsigned int) MPFR_FLAGS_INEXACT);
      mpfr_dump (y);
      printf ("Got      inex = %d, flags = %u,\n         y = ",
              inex, flags);
      mpfr_dump (z);
      exit (1);
    }

  mpfr_clear_flags ();
  inex = mpfr_div_2ui (z, x, 1, MPFR_RNDU);
  flags = __gmpfr_flags;

  if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
    {
      printf ("Error in large(");
      if (e == MPFR_EMAX_MAX)
        printf ("MPFR_EMAX_MAX");
      else if (e == emax)
        printf ("default emax");
      else if (e <= LONG_MAX)
        printf ("%ld", (long) e);
      else
        printf (">LONG_MAX");
      printf (") for mpfr_div_2ui\n");
      printf ("Expected inex > 0, flags = %u,\n         y = ",
              (unsigned int) MPFR_FLAGS_INEXACT);
      mpfr_dump (y);
      printf ("Got      inex = %d, flags = %u,\n         y = ",
              inex, flags);
      mpfr_dump (z);
      exit (1);
    }

  mpfr_clears (x, y, z, (mpfr_ptr) 0);
  set_emax (emax);
}
Ejemplo n.º 8
0
static void
underflow_up (int extended_emin)
{
  mpfr_t minpos, x, y, t, t2;
  int precx, precy;
  int inex;
  int rnd;
  int e3;
  int i, j;

  mpfr_init2 (minpos, 2);
  mpfr_set_ui (minpos, 0, MPFR_RNDN);
  mpfr_nextabove (minpos);

  /* Let's test values near the underflow boundary.
   *
   * Minimum representable positive number: minpos = 2^(emin - 1).
   * Let's choose an MPFR number x = log(minpos) + eps, with |eps| small
   * (note: eps cannot be 0, and cannot be a rational number either).
   * Then exp(x) = minpos * exp(eps) ~= minpos * (1 + eps + eps^2).
   * We will compute y = rnd(exp(x)) in some rounding mode, precision p.
   *   1. If eps > 0, then in any rounding mode:
   *        rnd(exp(x)) >= minpos and no underflow.
   *      So, let's take x1 = rndu(log(minpos)) in some precision.
   *   2. If eps < 0, then exp(x) < minpos and the result will be either 0
   *      or minpos. An underflow always occurs in MPFR_RNDZ and MPFR_RNDD,
   *      but not necessarily in MPFR_RNDN and MPFR_RNDU (this is underflow
   *      after rounding in an unbounded exponent range). If -a < eps < -b,
   *        minpos * (1 - a) < exp(x) < minpos * (1 - b + b^2).
   *      - If eps > -2^(-p), no underflow in MPFR_RNDU.
   *      - If eps > -2^(-p-1), no underflow in MPFR_RNDN.
   *      - If eps < - (2^(-p-1) + 2^(-2p-1)), underflow in MPFR_RNDN.
   *      - If eps < - (2^(-p) + 2^(-2p+1)), underflow in MPFR_RNDU.
   *      - In MPFR_RNDN, result is minpos iff exp(eps) > 1/2, i.e.
   *        - log(2) < eps < ...
   *
   * Moreover, since precy < MPFR_EXP_THRESHOLD (to avoid tests that take
   * too much time), mpfr_exp() always selects mpfr_exp_2(); so, we need
   * to test mpfr_exp_3() too. This will be done via the e3 variable:
   *   e3 = 0: mpfr_exp(), thus mpfr_exp_2().
   *   e3 = 1: mpfr_exp_3(), via the exp_3() wrapper.
   * i.e.: inex = e3 ? exp_3 (y, x, rnd) : mpfr_exp (y, x, rnd);
   */

  /* Case eps > 0. In revision 5461 (trunk) on a 64-bit Linux machine:
   *   Incorrect flags in underflow_up, eps > 0, MPFR_RNDN and extended emin
   *   for precx = 96, precy = 16, mpfr_exp_3
   *   Got 9 instead of 8.
   * Note: testing this case in several precisions for x and y introduces
   * some useful random. Indeed, the bug is not always triggered.
   * Fixed in r5469.
   */
  for (precx = 16; precx <= 128; precx += 16)
    {
      mpfr_init2 (x, precx);
      mpfr_log (x, minpos, MPFR_RNDU);
      for (precy = 16; precy <= 128; precy += 16)
        {
          mpfr_init2 (y, precy);

          for (e3 = 0; e3 <= 1; e3++)
            {
              RND_LOOP (rnd)
                {
                  int err = 0;

                  mpfr_clear_flags ();
                  inex = e3 ? exp_3 (y, x, (mpfr_rnd_t) rnd)
                    : mpfr_exp (y, x, (mpfr_rnd_t) rnd);
                  if (__gmpfr_flags != MPFR_FLAGS_INEXACT)
                    {
                      printf ("Incorrect flags in underflow_up, eps > 0, %s",
                              mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                      if (extended_emin)
                        printf (" and extended emin");
                      printf ("\nfor precx = %d, precy = %d, %s\n",
                              precx, precy, e3 ? "mpfr_exp_3" : "mpfr_exp");
                      printf ("Got %u instead of %u.\n", __gmpfr_flags,
                              (unsigned int) MPFR_FLAGS_INEXACT);
                      err = 1;
                    }
                  if (mpfr_cmp0 (y, minpos) < 0)
                    {
                      printf ("Incorrect result in underflow_up, eps > 0, %s",
                              mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                      if (extended_emin)
                        printf (" and extended emin");
                      printf ("\nfor precx = %d, precy = %d, %s\n",
                              precx, precy, e3 ? "mpfr_exp_3" : "mpfr_exp");
                      mpfr_dump (y);
                      err = 1;
                    }
                  MPFR_ASSERTN (inex != 0);
                  if (rnd == MPFR_RNDD || rnd == MPFR_RNDZ)
                    MPFR_ASSERTN (inex < 0);
                  if (rnd == MPFR_RNDU)
                    MPFR_ASSERTN (inex > 0);
                  if (err)
                    exit (1);
                }
            }

          mpfr_clear (y);
        }
      mpfr_clear (x);
    }

  /* Case - log(2) < eps < 0 in MPFR_RNDN, starting with small-precision x;
   * only check the result and the ternary value.
   * Previous to r5453 (trunk), on 32-bit and 64-bit machines, this fails
   * for precx = 65 and precy = 16, e.g.:
   *   exp_2.c:264:  assertion failed: ...
   * because mpfr_sub (r, x, r, MPFR_RNDU); yields a null value. This is
   * fixed in r5453 by going to next Ziv's iteration.
   */
  for (precx = sizeof(mpfr_exp_t) * CHAR_BIT + 1; precx <= 81; precx += 8)
    {
      mpfr_init2 (x, precx);
      mpfr_log (x, minpos, MPFR_RNDD);  /* |ulp| <= 1/2 */
      for (precy = 16; precy <= 128; precy += 16)
        {
          mpfr_init2 (y, precy);
          inex = mpfr_exp (y, x, MPFR_RNDN);
          if (inex <= 0 || mpfr_cmp0 (y, minpos) != 0)
            {
              printf ("Error in underflow_up, - log(2) < eps < 0");
              if (extended_emin)
                printf (" and extended emin");
              printf (" for prec = %d\nExpected ", precy);
              mpfr_out_str (stdout, 16, 0, minpos, MPFR_RNDN);
              printf (" (minimum positive MPFR number) and inex > 0\nGot ");
              mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
              printf ("\nwith inex = %d\n", inex);
              exit (1);
            }
          mpfr_clear (y);
        }
      mpfr_clear (x);
    }

  /* Cases eps ~ -2^(-p) and eps ~ -2^(-p-1). More precisely,
   *   _ for j = 0, eps > -2^(-(p+i)),
   *   _ for j = 1, eps < - (2^(-(p+i)) + 2^(1-2(p+i))),
   * where i = 0 or 1.
   */
  mpfr_inits2 (2, t, t2, (mpfr_ptr) 0);
  for (precy = 16; precy <= 128; precy += 16)
    {
      mpfr_set_ui_2exp (t, 1, - precy, MPFR_RNDN);         /* 2^(-p) */
      mpfr_set_ui_2exp (t2, 1, 1 - 2 * precy, MPFR_RNDN);  /* 2^(-2p+1) */
      precx = sizeof(mpfr_exp_t) * CHAR_BIT + 2 * precy + 8;
      mpfr_init2 (x, precx);
      mpfr_init2 (y, precy);
      for (i = 0; i <= 1; i++)
        {
          for (j = 0; j <= 1; j++)
            {
              if (j == 0)
                {
                  /* Case eps > -2^(-(p+i)). */
                  mpfr_log (x, minpos, MPFR_RNDU);
                }
              else  /* j == 1 */
                {
                  /* Case eps < - (2^(-(p+i)) + 2^(1-2(p+i))). */
                  mpfr_log (x, minpos, MPFR_RNDD);
                  inex = mpfr_sub (x, x, t2, MPFR_RNDN);
                  MPFR_ASSERTN (inex == 0);
                }
              inex = mpfr_sub (x, x, t, MPFR_RNDN);
              MPFR_ASSERTN (inex == 0);

              RND_LOOP (rnd)
                for (e3 = 0; e3 <= 1; e3++)
                  {
                    int err = 0;
                    unsigned int flags;

                    flags = MPFR_FLAGS_INEXACT |
                      (((rnd == MPFR_RNDU || rnd == MPFR_RNDA)
                             && (i == 1 || j == 0)) ||
                       (rnd == MPFR_RNDN && (i == 1 && j == 0)) ?
                       0 : MPFR_FLAGS_UNDERFLOW);
                    mpfr_clear_flags ();
                    inex = e3 ? exp_3 (y, x, (mpfr_rnd_t) rnd)
                      : mpfr_exp (y, x, (mpfr_rnd_t) rnd);
                    if (__gmpfr_flags != flags)
                      {
                        printf ("Incorrect flags in underflow_up, %s",
                                mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                        if (extended_emin)
                          printf (" and extended emin");
                        printf ("\nfor precx = %d, precy = %d, ",
                                precx, precy);
                        if (j == 0)
                          printf ("eps >~ -2^(-%d)", precy + i);
                        else
                          printf ("eps <~ - (2^(-%d) + 2^(%d))",
                                  precy + i, 1 - 2 * (precy + i));
                        printf (", %s\n", e3 ? "mpfr_exp_3" : "mpfr_exp");
                        printf ("Got %u instead of %u.\n",
                                __gmpfr_flags, flags);
                        err = 1;
                      }
                    if (rnd == MPFR_RNDU || rnd == MPFR_RNDA || rnd == MPFR_RNDN ?
                        mpfr_cmp0 (y, minpos) != 0 : MPFR_NOTZERO (y))
                      {
                        printf ("Incorrect result in underflow_up, %s",
                                mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                        if (extended_emin)
                          printf (" and extended emin");
                        printf ("\nfor precx = %d, precy = %d, ",
                                precx, precy);
                        if (j == 0)
                          printf ("eps >~ -2^(-%d)", precy + i);
                        else
                          printf ("eps <~ - (2^(-%d) + 2^(%d))",
                                  precy + i, 1 - 2 * (precy + i));
                        printf (", %s\n", e3 ? "mpfr_exp_3" : "mpfr_exp");
                        mpfr_dump (y);
                        err = 1;
                      }
                    if (err)
                      exit (1);
                  }  /* for (e3 ...) */
            }  /* for (j ...) */
          mpfr_div_2si (t, t, 1, MPFR_RNDN);
          mpfr_div_2si (t2, t2, 2, MPFR_RNDN);
        }  /* for (i ...) */
      mpfr_clears (x, y, (mpfr_ptr) 0);
    }  /* for (precy ...) */
  mpfr_clears (t, t2, (mpfr_ptr) 0);

  /* Case exp(eps) ~= 1/2, i.e. eps ~= - log(2).
   * We choose x0 and x1 with high enough precision such that:
   *   x0 = rndd(rndd(log(minpos)) - rndu(log(2)))
   *   x1 = rndu(rndu(log(minpos)) - rndd(log(2)))
   * In revision 5507 (trunk) on a 64-bit Linux machine, this fails:
   *   Error in underflow_up, eps >~ - log(2) and extended emin
   *   for precy = 16, mpfr_exp
   *   Expected 1.0@-1152921504606846976 (minimum positive MPFR number),
   *   inex > 0 and flags = 9
   *   Got 0
   *   with inex = -1 and flags = 9
   * due to a double-rounding problem in mpfr_mul_2si when rescaling
   * the result.
   */
  mpfr_inits2 (sizeof(mpfr_exp_t) * CHAR_BIT + 64, x, t, (mpfr_ptr) 0);
  for (i = 0; i <= 1; i++)
    {
      mpfr_log (x, minpos, i ? MPFR_RNDU : MPFR_RNDD);
      mpfr_const_log2 (t, i ? MPFR_RNDD : MPFR_RNDU);
      mpfr_sub (x, x, t, i ? MPFR_RNDU : MPFR_RNDD);
      for (precy = 16; precy <= 128; precy += 16)
        {
          mpfr_init2 (y, precy);
          for (e3 = 0; e3 <= 1; e3++)
            {
              unsigned int flags, uflags =
                MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;

              mpfr_clear_flags ();
              inex = e3 ? exp_3 (y, x, MPFR_RNDN) : mpfr_exp (y, x, MPFR_RNDN);
              flags = __gmpfr_flags;
              if (flags != uflags ||
                  (i ? (inex <= 0 || mpfr_cmp0 (y, minpos) != 0)
                     : (inex >= 0 || MPFR_NOTZERO (y))))
                {
                  printf ("Error in underflow_up, eps %c~ - log(2)",
                          i ? '>' : '<');
                  if (extended_emin)
                    printf (" and extended emin");
                  printf ("\nfor precy = %d, %s\nExpected ", precy,
                          e3 ? "mpfr_exp_3" : "mpfr_exp");
                  if (i)
                    {
                      mpfr_out_str (stdout, 16, 0, minpos, MPFR_RNDN);
                      printf (" (minimum positive MPFR number),\ninex >");
                    }
                  else
                    {
                      printf ("+0, inex <");
                    }
                  printf (" 0 and flags = %u\nGot ", uflags);
                  mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
                  printf ("\nwith inex = %d and flags = %u\n", inex, flags);
                  exit (1);
                }
            }
          mpfr_clear (y);
        }
    }
  mpfr_clears (x, t, (mpfr_ptr) 0);

  mpfr_clear (minpos);
}