Esempio n. 1
0
/* bug found in nightly tests */
static void
test20071214 (void)
{
  mpfr_t a, b;
  int inex;

  mpfr_init2 (a, 4);
  mpfr_init2 (b, 4);

  mpfr_set_ui_2exp (a, 3, -4, MPFR_RNDN);
  inex = mpfr_sin_cos (a, b, a, MPFR_RNDD);
  MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 11, -6) == 0);
  MPFR_ASSERTN(mpfr_cmp_ui_2exp (b, 15, -4) == 0);
  MPFR_ASSERTN(inex == 10);

  mpfr_set_ui_2exp (a, 3, -4, MPFR_RNDN);
  inex = mpfr_sin_cos (a, b, a, MPFR_RNDU);
  MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 3, -4) == 0);
  MPFR_ASSERTN(mpfr_cmp_ui (b, 1) == 0);
  MPFR_ASSERTN(inex == 5);

  mpfr_set_ui_2exp (a, 3, -4, MPFR_RNDN);
  inex = mpfr_sin_cos (a, b, a, MPFR_RNDN);
  MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 3, -4) == 0);
  MPFR_ASSERTN(mpfr_cmp_ui (b, 1) == 0);
  MPFR_ASSERTN(inex == 5);

  mpfr_clear (a);
  mpfr_clear (b);
}
Esempio n. 2
0
static void
check53 (const char *xs, const char *sin_xs, const char *cos_xs,
         mpfr_rnd_t rnd_mode)
{
  mpfr_t xx, s, c;

  mpfr_inits2 (53, xx, s, c, (mpfr_ptr) 0);
  mpfr_set_str1 (xx, xs); /* should be exact */
  mpfr_sin_cos (s, c, xx, rnd_mode);
  if (mpfr_cmp_str1 (s, sin_xs))
    {
      printf ("mpfr_sin_cos failed for x=%s, rnd=%s\n",
              xs, mpfr_print_rnd_mode (rnd_mode));
      printf ("mpfr_sin_cos gives sin(x)=");
      mpfr_out_str(stdout, 10, 0, s, MPFR_RNDN);
      printf(", expected %s\n", sin_xs);
      exit (1);
    }
  if (mpfr_cmp_str1 (c, cos_xs))
    {
      printf ("mpfr_sin_cos failed for x=%s, rnd=%s\n",
              xs, mpfr_print_rnd_mode (rnd_mode));
      printf ("mpfr_sin_cos gives cos(x)=");
      mpfr_out_str(stdout, 10, 0, c, MPFR_RNDN);
      printf(", expected %s\n", cos_xs);
      exit (1);
    }
  mpfr_clears (xx, s, c, (mpfr_ptr) 0);
}
Esempio n. 3
0
static void
coverage_01032011 (void)
{
  mpfr_t val, cval, sval, svalf;
  int status_f, status;

  mpfr_init2 (val, MPFR_PREC_MIN);
  mpfr_init2 (cval, MPFR_PREC_MIN);
  mpfr_init2 (sval, MPFR_PREC_MIN);
  mpfr_init2 (svalf, MPFR_PREC_MIN);

  mpfr_set_str1 (val, "-0.7");

  status_f = mpfr_sincos_fast (svalf, NULL, val, MPFR_RNDN);
  status = mpfr_sin_cos (sval, cval, val, MPFR_RNDN);
  if (! mpfr_equal_p (svalf, sval) || SIGN (status_f) != SIGN (status))
    {
      printf ("mpfr_sincos_fast differ from mpfr_sin_cos result:\n"
              " sin fast is ");
      mpfr_dump (svalf);
      printf (" sin is ");
      mpfr_dump (sval);
      printf ("status_f = %d, status = %d\n", status_f, status);
      exit (1);
    }

  mpfr_clears(val, cval, sval, svalf, (mpfr_ptr) 0);
}
Esempio n. 4
0
/* check that mpfr_sin_cos and test_mpfr_sincos_fast agree */
static void
test_mpfr_sincos_fast (void)
{
  mpfr_t x, y, z, yref, zref, h;
  mpfr_prec_t p = 1000;
  int i, inex, inexref;
  mpfr_rnd_t r;

  mpfr_init2 (x, p);
  mpfr_init2 (y, p);
  mpfr_init2 (z, p);
  mpfr_init2 (yref, p);
  mpfr_init2 (zref, p);
  mpfr_init2 (h, p);
  mpfr_set_ui (x, 0, MPFR_RNDN);
  /* we generate a random value x, compute sin(x) and cos(x) with both
     mpfr_sin_cos and mpfr_sincos_fast, and check the values and the flags
     agree */
  for (i = 0; i < 100; i++)
    {
      mpfr_urandomb (h, RANDS);
      mpfr_add (x, x, h, MPFR_RNDN);
      r = RND_RAND ();
      inexref = mpfr_sin_cos (yref, zref, x, r);
      inex = mpfr_sincos_fast (y, z, x, r);
      if (mpfr_cmp (y, yref))
        {
          printf ("mpfr_sin_cos and mpfr_sincos_fast disagree\n");
          printf ("x="); mpfr_dump (x);
          printf ("rnd=%s\n", mpfr_print_rnd_mode (r));
          printf ("yref="); mpfr_dump (yref);
          printf ("y="); mpfr_dump (y);
          exit (1);
        }
      if (mpfr_cmp (z, zref))
        {
          printf ("mpfr_sin_cos and mpfr_sincos_fast disagree\n");
          printf ("x="); mpfr_dump (x);
          printf ("rnd=%s\n", mpfr_print_rnd_mode (r));
          printf ("zref="); mpfr_dump (zref);
          printf ("z="); mpfr_dump (z);
          exit (1);
        }
      if (inex != inexref)
        {
          printf ("mpfr_sin_cos and mpfr_sincos_fast disagree\n");
          printf ("x="); mpfr_dump (x);
          printf ("rnd=%s\n", mpfr_print_rnd_mode (r));
          printf ("inexref=%d inex=%d\n", inexref, inex);
          exit (1);
        }
    }
  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
  mpfr_clear (yref);
  mpfr_clear (zref);
  mpfr_clear (h);
}
Esempio n. 5
0
/* Note: with the sin_cos.c code before r6507, the disagreement occurs
   only on the return ("inexact") value, which is new in r6444. */
static void
bug20091008 (void)
{
  mpfr_t x, y, z, yref, zref;
  mpfr_prec_t p = 1000;
  int inex, inexref;
  mpfr_rnd_t r = MPFR_RNDN;

  mpfr_init2 (x, p);
  mpfr_init2 (y, p);
  mpfr_init2 (z, p);
  mpfr_init2 (yref, p);
  mpfr_init2 (zref, p);

  mpfr_set_str (x, "c.91813724e28ef6a711d33e6505984699daef7fe93636c1ed5d0168bc96989cc6802f7f9e405c902ec62fb90cd39c9d21084c8ad8b5af4c4aa87bf402e2e4a78e6fe1ffeb6dbbbdbbc2983c196c518966ccc1e094ed39ee77984ef2428069d65de37928e75247edbe7007245e682616b5ebbf05f2fdefc74ad192024f10", 16, MPFR_RNDN);
  inexref = mpfr_sin_cos (yref, zref, x, r);
  inex = mpfr_sincos_fast (y, z, x, r);

  if (mpfr_cmp (y, yref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091008)\n");
      printf ("yref="); mpfr_dump (yref);
      printf ("y="); mpfr_dump (y);
      exit (1);
    }
  if (mpfr_cmp (z, zref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091008)\n");
      printf ("zref="); mpfr_dump (zref);
      printf ("z="); mpfr_dump (z);
      exit (1);
    }
  /* sin(x) is rounded up, cos(x) is rounded up too, thus we should get 5
     for the return value */
  if (inex != inexref)
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091008)\n");
      printf ("inexref=%d inex=%d (5 expected)\n", inexref, inex);
      exit (1);
    }

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
  mpfr_clear (yref);
  mpfr_clear (zref);
}
Esempio n. 6
0
static void
bug20091013 (void)
{
  mpfr_t x, y, z, yref, zref;
  mpfr_prec_t p = 1000;
  int inex, inexref;
  mpfr_rnd_t r = MPFR_RNDN;

  mpfr_init2 (x, p);
  mpfr_init2 (y, p);
  mpfr_init2 (z, p);
  mpfr_init2 (yref, p);
  mpfr_init2 (zref, p);

  mpfr_set_str (x, "3.240ff3fdcb1ee7cd667b96287593ae24e20fb63ed7c2d5bf4bd0f2cc5509283b04e7628e66382605f14ed5967cef15296041539a1bdaa626c777c7fbb6f2068414759b78cee14f37848689b3a170f583656be4e0837f464d8210556a3a822d4ecfdd59f4e0d5fdb76bf7e15b8a57234e2160b98e14c17bbdf27c4643b8@1", 16, MPFR_RNDN);
  inexref = mpfr_sin_cos (yref, zref, x, r);
  inex = mpfr_sincos_fast (y, z, x, r);

  if (mpfr_cmp (y, yref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091013)\n");
      printf ("yref="); mpfr_dump (yref);
      printf ("y="); mpfr_dump (y);
      exit (1);
    }
  if (mpfr_cmp (z, zref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091013)\n");
      printf ("zref="); mpfr_dump (zref);
      printf ("z="); mpfr_dump (z);
      exit (1);
    }
  /* sin(x) is rounded down and cos(x) is rounded down, thus we should get
     2+4*2 = 10 as return value */
  if (inex != inexref)
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091013)\n");
      printf ("inexref=%d inex=%d (10 expected)\n", inexref, inex);
      exit (1);
    }

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
  mpfr_clear (yref);
  mpfr_clear (zref);
}
Esempio n. 7
0
static void
bug20091007 (void)
{
  mpfr_t x, y, z, yref, zref;
  mpfr_prec_t p = 1000;
  int inex, inexref;
  mpfr_rnd_t r = MPFR_RNDZ;

  mpfr_init2 (x, p);
  mpfr_init2 (y, p);
  mpfr_init2 (z, p);
  mpfr_init2 (yref, p);
  mpfr_init2 (zref, p);

  mpfr_set_str (x, "1.9ecdc22ba77a5ab2560f7e84289e2a328906f47377ea3fd4c82d1bb2f13ee05c032cffc1933eadab7b0a5498e03e3bd0508968e59c25829d97a0b54f20cd4662c8dfffa54e714de41fc8ee3e0e0b244d110a194db05b70022b7d77f88955d415b09f17dd404576098dc51a583a3e49c35839551646e880c7eb790a01a4@1", 16, MPFR_RNDN);
  inexref = mpfr_sin_cos (yref, zref, x, r);
  inex = mpfr_sincos_fast (y, z, x, r);

  if (mpfr_cmp (y, yref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091007)\n");
      printf ("yref="); mpfr_dump (yref);
      printf ("y="); mpfr_dump (y);
      exit (1);
    }
  if (mpfr_cmp (z, zref))
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091007)\n");
      printf ("zref="); mpfr_dump (zref);
      printf ("z="); mpfr_dump (z);
      exit (1);
    }
  if (inex != inexref)
    {
      printf ("mpfr_sin_cos and mpfr_sincos_fast disagree (bug20091007)\n");
      printf ("inexref=%d inex=%d\n", inexref, inex);
      exit (1);
    }

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
  mpfr_clear (yref);
  mpfr_clear (zref);
}
Esempio n. 8
0
static void
large_test (char *X, int prec, int N)
{
  int i;
  mpfr_t x, s, c;

  mpfr_init2 (x, prec);
  mpfr_init2 (s, prec);
  mpfr_init2 (c, prec);
  mpfr_set_str (x, X, 10, MPFR_RNDN);

  for (i = 0; i < N; i++)
    mpfr_sin_cos (s, c, x, MPFR_RNDN);

  mpfr_clear (x);
  mpfr_clear (s);
  mpfr_clear (c);
}
Esempio n. 9
0
static void
check_nans (void)
{
  mpfr_t  x, s, c;

  mpfr_init2 (x, 123L);
  mpfr_init2 (s, 123L);
  mpfr_init2 (c, 123L);

  /* sin(NaN)==NaN, cos(NaN)==NaN */
  mpfr_set_nan (x);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (s));
  MPFR_ASSERTN (mpfr_nan_p (c));

  /* sin(+Inf)==NaN, cos(+Inf)==NaN */
  mpfr_set_inf (x, 1);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (s));
  MPFR_ASSERTN (mpfr_nan_p (c));

  /* sin(-Inf)==NaN, cos(-Inf)==NaN */
  mpfr_set_inf (x, -1);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_nan_p (s));
  MPFR_ASSERTN (mpfr_nan_p (c));

  /* check zero */
  mpfr_set_ui  (x, 0, MPFR_RNDN);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (s, 0) == 0 && MPFR_IS_POS (s));
  MPFR_ASSERTN (mpfr_cmp_ui (c, 1) == 0);
  mpfr_neg (x, x, MPFR_RNDN);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_ui (s, 0) == 0 && MPFR_IS_NEG (s));
  MPFR_ASSERTN (mpfr_cmp_ui (c, 1) == 0);

  /* coverage test */
  mpfr_set_prec (x, 2);
  mpfr_set_ui (x, 4, MPFR_RNDN);
  mpfr_set_prec (s, 2);
  mpfr_set_prec (c, 2);
  mpfr_sin_cos (s, c, x, MPFR_RNDN);
  MPFR_ASSERTN (mpfr_cmp_si_2exp (s, -3, -2) == 0);
  MPFR_ASSERTN (mpfr_cmp_si_2exp (c, -3, -2) == 0);

  mpfr_clear (x);
  mpfr_clear (s);
  mpfr_clear (c);
}
Esempio n. 10
0
static void
tiny (void)
{
  mpfr_t x, s, c;
  int i, inex;

  mpfr_inits2 (64, x, s, c, (mpfr_ptr) 0);

  for (i = -1; i <= 1; i += 2)
    {
      mpfr_set_si (x, i, MPFR_RNDN);
      mpfr_set_exp (x, mpfr_get_emin ());
      inex = mpfr_sin_cos (s, c, x, MPFR_RNDN);
      MPFR_ASSERTN (inex != 0);
      MPFR_ASSERTN (mpfr_equal_p (s, x));
      MPFR_ASSERTN (!mpfr_nan_p (c) && mpfr_cmp_ui (c, 1) == 0);
    }

  mpfr_clears (x, s, c, (mpfr_ptr) 0);
}
Esempio n. 11
0
static PyObject *
_GMPy_MPFR_Sin_Cos(PyObject *x, CTXT_Object *context)
{
    MPFR_Object *s, *c;
    PyObject *result;
    int code;

    CHECK_CONTEXT(context);

    s = GMPy_MPFR_New(0, context);
    c = GMPy_MPFR_New(0, context);
    result = PyTuple_New(2);
    if (!s || !c || !result) {
        Py_XDECREF((PyObject*)s);
        Py_XDECREF((PyObject*)c);
        Py_XDECREF(result);
        return NULL;
    }

    mpfr_clear_flags();
    code = mpfr_sin_cos(s->f, c->f, MPFR(x), GET_MPFR_ROUND(context));

    s->rc = code & 0x03;
    c->rc = code >> 2;
    if (s->rc == 2) s->rc = -1;
    if (c->rc == 2) c->rc = -1;

    _GMPy_MPFR_Cleanup(&s, context);
    _GMPy_MPFR_Cleanup(&c, context);

    if (!s || !c) {
        Py_XDECREF((PyObject*)s);
        Py_XDECREF((PyObject*)c);
        Py_DECREF(result);
        return NULL;
    }

    PyTuple_SET_ITEM(result, 0, (PyObject*)s);
    PyTuple_SET_ITEM(result, 1, (PyObject*)c);
    return result;
}
Esempio n. 12
0
/* Bug reported by Laurent Fousse for the 2.4 branch.
   No problem in the trunk.
   https://sympa.inria.fr/sympa/arc/mpfr/2009-11/msg00044.html */
static void
bug20091122 (void)
{
  mpfr_t x, y, z, yref, zref;
  mpfr_prec_t p = 3;
  mpfr_rnd_t r = MPFR_RNDN;

  mpfr_init2 (x, 5);
  mpfr_init2 (y, p);
  mpfr_init2 (z, p);
  mpfr_init2 (yref, p);
  mpfr_init2 (zref, p);

  mpfr_set_str (x, "0.11111E49", 2, MPFR_RNDN);
  mpfr_sin_cos (yref, zref, x, r);

  mpfr_sin (y, x, r);
  mpfr_cos (z, x, r);

  if (! mpfr_equal_p (y, yref))
    {
      printf ("mpfr_sin_cos and mpfr_sin disagree (bug20091122)\n");
      printf ("yref = "); mpfr_dump (yref);
      printf ("y    = "); mpfr_dump (y);
      exit (1);
    }
  if (! mpfr_equal_p (z, zref))
    {
      printf ("mpfr_sin_cos and mpfr_cos disagree (bug20091122)\n");
      printf ("zref = "); mpfr_dump (zref);
      printf ("z    = "); mpfr_dump (z);
      exit (1);
    }

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
  mpfr_clear (yref);
  mpfr_clear (zref);
}
Esempio n. 13
0
static bool
do_mpfr_sincos (real_value *result_sin, real_value *result_cos,
		const real_value *arg, const real_format *format)
{
  /* To proceed, MPFR must exactly represent the target floating point
     format, which only happens when the target base equals two.  */
  if (format->b != 2 || !real_isfinite (arg))
    return false;

  int prec = format->p;
  mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
  mpfr_t m, ms, mc;

  mpfr_inits2 (prec, m, ms, mc, NULL);
  mpfr_from_real (m, arg, GMP_RNDN);
  mpfr_clear_flags ();
  bool inexact = mpfr_sin_cos (ms, mc, m, rnd);
  bool ok = (do_mpfr_ckconv (result_sin, ms, inexact, format)
	     && do_mpfr_ckconv (result_cos, mc, inexact, format));
  mpfr_clears (m, ms, mc, NULL);

  return ok;
}
Esempio n. 14
0
/* Implements asymptotic expansion for jn or yn (formulae 9.2.5 and 9.2.6
   from Abramowitz & Stegun).
   Assumes |z| > p log(2)/2, where p is the target precision
   (z can be negative only for jn).
   Return 0 if the expansion does not converge enough (the value 0 as inexact
   flag should not happen for normal input).
*/
static int
FUNCTION (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r)
{
  mpfr_t s, c, P, Q, t, iz, err_t, err_s, err_u;
  mpfr_prec_t w;
  long k;
  int inex, stop, diverge = 0;
  mpfr_exp_t err2, err;
  MPFR_ZIV_DECL (loop);

  mpfr_init (c);

  w = MPFR_PREC(res) + MPFR_INT_CEIL_LOG2(MPFR_PREC(res)) + 4;

  MPFR_ZIV_INIT (loop, w);
  for (;;)
    {
      mpfr_set_prec (c, w);
      mpfr_init2 (s, w);
      mpfr_init2 (P, w);
      mpfr_init2 (Q, w);
      mpfr_init2 (t, w);
      mpfr_init2 (iz, w);
      mpfr_init2 (err_t, 31);
      mpfr_init2 (err_s, 31);
      mpfr_init2 (err_u, 31);

      /* Approximate sin(z) and cos(z). In the following, err <= k means that
         the approximate value y and the true value x are related by
         y = x * (1 + u)^k with |u| <= 2^(-w), following Higham's method. */
      mpfr_sin_cos (s, c, z, MPFR_RNDN);
      if (MPFR_IS_NEG(z))
        mpfr_neg (s, s, MPFR_RNDN); /* compute jn/yn(|z|), fix sign later */
      /* The absolute error on s/c is bounded by 1/2 ulp(1/2) <= 2^(-w-1). */
      mpfr_add (t, s, c, MPFR_RNDN);
      mpfr_sub (c, s, c, MPFR_RNDN);
      mpfr_swap (s, t);
      /* now s approximates sin(z)+cos(z), and c approximates sin(z)-cos(z),
         with total absolute error bounded by 2^(1-w). */

      /* precompute 1/(8|z|) */
      mpfr_si_div (iz, MPFR_IS_POS(z) ? 1 : -1, z, MPFR_RNDN);   /* err <= 1 */
      mpfr_div_2ui (iz, iz, 3, MPFR_RNDN);

      /* compute P and Q */
      mpfr_set_ui (P, 1, MPFR_RNDN);
      mpfr_set_ui (Q, 0, MPFR_RNDN);
      mpfr_set_ui (t, 1, MPFR_RNDN); /* current term */
      mpfr_set_ui (err_t, 0, MPFR_RNDN); /* error on t */
      mpfr_set_ui (err_s, 0, MPFR_RNDN); /* error on P and Q (sum of errors) */
      for (k = 1, stop = 0; stop < 4; k++)
        {
          /* compute next term: t(k)/t(k-1) = (2n+2k-1)(2n-2k+1)/(8kz) */
          mpfr_mul_si (t, t, 2 * (n + k) - 1, MPFR_RNDN); /* err <= err_k + 1 */
          mpfr_mul_si (t, t, 2 * (n - k) + 1, MPFR_RNDN); /* err <= err_k + 2 */
          mpfr_div_ui (t, t, k, MPFR_RNDN);               /* err <= err_k + 3 */
          mpfr_mul (t, t, iz, MPFR_RNDN);                 /* err <= err_k + 5 */
          /* the relative error on t is bounded by (1+u)^(5k)-1, which is
             bounded by 6ku for 6ku <= 0.02: first |5 log(1+u)| <= |5.5u|
             for |u| <= 0.15, then |exp(5.5u)-1| <= 6u for |u| <= 0.02. */
          mpfr_mul_ui (err_t, t, 6 * k, MPFR_IS_POS(t) ? MPFR_RNDU : MPFR_RNDD);
          mpfr_abs (err_t, err_t, MPFR_RNDN); /* exact */
          /* the absolute error on t is bounded by err_t * 2^(-w) */
          mpfr_abs (err_u, t, MPFR_RNDU);
          mpfr_mul_2ui (err_u, err_u, w, MPFR_RNDU); /* t * 2^w */
          mpfr_add (err_u, err_u, err_t, MPFR_RNDU); /* max|t| * 2^w */
          if (stop >= 2)
            {
              /* take into account the neglected terms: t * 2^w */
              mpfr_div_2ui (err_s, err_s, w, MPFR_RNDU);
              if (MPFR_IS_POS(t))
                mpfr_add (err_s, err_s, t, MPFR_RNDU);
              else
                mpfr_sub (err_s, err_s, t, MPFR_RNDU);
              mpfr_mul_2ui (err_s, err_s, w, MPFR_RNDU);
              stop ++;
            }
          /* if k is odd, add to Q, otherwise to P */
          else if (k & 1)
            {
              /* if k = 1 mod 4, add, otherwise subtract */
              if ((k & 2) == 0)
                mpfr_add (Q, Q, t, MPFR_RNDN);
              else
                mpfr_sub (Q, Q, t, MPFR_RNDN);
              /* check if the next term is smaller than ulp(Q): if EXP(err_u)
                 <= EXP(Q), since the current term is bounded by
                 err_u * 2^(-w), it is bounded by ulp(Q) */
              if (MPFR_EXP(err_u) <= MPFR_EXP(Q))
                stop ++;
              else
                stop = 0;
            }
          else
            {
              /* if k = 0 mod 4, add, otherwise subtract */
              if ((k & 2) == 0)
                mpfr_add (P, P, t, MPFR_RNDN);
              else
                mpfr_sub (P, P, t, MPFR_RNDN);
              /* check if the next term is smaller than ulp(P) */
              if (MPFR_EXP(err_u) <= MPFR_EXP(P))
                stop ++;
              else
                stop = 0;
            }
          mpfr_add (err_s, err_s, err_t, MPFR_RNDU);
          /* the sum of the rounding errors on P and Q is bounded by
             err_s * 2^(-w) */

          /* stop when start to diverge */
          if (stop < 2 &&
              ((MPFR_IS_POS(z) && mpfr_cmp_ui (z, (k + 1) / 2) < 0) ||
               (MPFR_IS_NEG(z) && mpfr_cmp_si (z, - ((k + 1) / 2)) > 0)))
            {
              /* if we have to stop the series because it diverges, then
                 increasing the precision will most probably fail, since
                 we will stop to the same point, and thus compute a very
                 similar approximation */
              diverge = 1;
              stop = 2; /* force stop */
            }
        }
      /* the sum of the total errors on P and Q is bounded by err_s * 2^(-w) */

      /* Now combine: the sum of the rounding errors on P and Q is bounded by
         err_s * 2^(-w), and the absolute error on s/c is bounded by 2^(1-w) */
      if ((n & 1) == 0) /* n even: P * (sin + cos) + Q (cos - sin) for jn
                                   Q * (sin + cos) + P (sin - cos) for yn */
        {
#ifdef MPFR_JN
          mpfr_mul (c, c, Q, MPFR_RNDN); /* Q * (sin - cos) */
          mpfr_mul (s, s, P, MPFR_RNDN); /* P * (sin + cos) */
#else
          mpfr_mul (c, c, P, MPFR_RNDN); /* P * (sin - cos) */
          mpfr_mul (s, s, Q, MPFR_RNDN); /* Q * (sin + cos) */
#endif
          err = MPFR_EXP(c);
          if (MPFR_EXP(s) > err)
            err = MPFR_EXP(s);
#ifdef MPFR_JN
          mpfr_sub (s, s, c, MPFR_RNDN);
#else
          mpfr_add (s, s, c, MPFR_RNDN);
#endif
        }
      else /* n odd: P * (sin - cos) + Q (cos + sin) for jn,
                     Q * (sin - cos) - P (cos + sin) for yn */
        {
#ifdef MPFR_JN
          mpfr_mul (c, c, P, MPFR_RNDN); /* P * (sin - cos) */
          mpfr_mul (s, s, Q, MPFR_RNDN); /* Q * (sin + cos) */
#else
          mpfr_mul (c, c, Q, MPFR_RNDN); /* Q * (sin - cos) */
          mpfr_mul (s, s, P, MPFR_RNDN); /* P * (sin + cos) */
#endif
          err = MPFR_EXP(c);
          if (MPFR_EXP(s) > err)
            err = MPFR_EXP(s);
#ifdef MPFR_JN
          mpfr_add (s, s, c, MPFR_RNDN);
#else
          mpfr_sub (s, c, s, MPFR_RNDN);
#endif
        }
      if ((n & 2) != 0)
        mpfr_neg (s, s, MPFR_RNDN);
      if (MPFR_EXP(s) > err)
        err = MPFR_EXP(s);
      /* the absolute error on s is bounded by P*err(s/c) + Q*err(s/c)
         + err(P)*(s/c) + err(Q)*(s/c) + 3 * 2^(err - w - 1)
         <= (|P|+|Q|) * 2^(1-w) + err_s * 2^(1-w) + 2^err * 2^(1-w),
         since |c|, |old_s| <= 2. */
      err2 = (MPFR_EXP(P) >= MPFR_EXP(Q)) ? MPFR_EXP(P) + 2 : MPFR_EXP(Q) + 2;
      /* (|P| + |Q|) * 2^(1 - w) <= 2^(err2 - w) */
      err = MPFR_EXP(err_s) >= err ? MPFR_EXP(err_s) + 2 : err + 2;
      /* err_s * 2^(1-w) + 2^old_err * 2^(1-w) <= 2^err * 2^(-w) */
      err2 = (err >= err2) ? err + 1 : err2 + 1;
      /* now the absolute error on s is bounded by 2^(err2 - w) */

      /* multiply by sqrt(1/(Pi*z)) */
      mpfr_const_pi (c, MPFR_RNDN);     /* Pi, err <= 1 */
      mpfr_mul (c, c, z, MPFR_RNDN);    /* err <= 2 */
      mpfr_si_div (c, MPFR_IS_POS(z) ? 1 : -1, c, MPFR_RNDN); /* err <= 3 */
      mpfr_sqrt (c, c, MPFR_RNDN);      /* err<=5/2, thus the absolute error is
                                          bounded by 3*u*|c| for |u| <= 0.25 */
      mpfr_mul (err_t, c, s, MPFR_SIGN(c)==MPFR_SIGN(s) ? MPFR_RNDU : MPFR_RNDD);
      mpfr_abs (err_t, err_t, MPFR_RNDU);
      mpfr_mul_ui (err_t, err_t, 3, MPFR_RNDU);
      /* 3*2^(-w)*|old_c|*|s| [see below] is bounded by err_t * 2^(-w) */
      err2 += MPFR_EXP(c);
      /* |old_c| * 2^(err2 - w) [see below] is bounded by 2^(err2-w) */
      mpfr_mul (c, c, s, MPFR_RNDN);    /* the absolute error on c is bounded by
                                          1/2 ulp(c) + 3*2^(-w)*|old_c|*|s|
                                          + |old_c| * 2^(err2 - w) */
      /* compute err_t * 2^(-w) + 1/2 ulp(c) = (err_t + 2^EXP(c)) * 2^(-w) */
      err = (MPFR_EXP(err_t) > MPFR_EXP(c)) ? MPFR_EXP(err_t) + 1 : MPFR_EXP(c) + 1;
      /* err_t * 2^(-w) + 1/2 ulp(c) <= 2^(err - w) */
      /* now err_t * 2^(-w) bounds 1/2 ulp(c) + 3*2^(-w)*|old_c|*|s| */
      err = (err >= err2) ? err + 1 : err2 + 1;
      /* the absolute error on c is bounded by 2^(err - w) */

      mpfr_clear (s);
      mpfr_clear (P);
      mpfr_clear (Q);
      mpfr_clear (t);
      mpfr_clear (iz);
      mpfr_clear (err_t);
      mpfr_clear (err_s);
      mpfr_clear (err_u);

      err -= MPFR_EXP(c);
      if (MPFR_LIKELY (MPFR_CAN_ROUND (c, w - err, MPFR_PREC(res), r)))
        break;
      if (diverge != 0)
        {
          mpfr_set (c, z, r); /* will force inex=0 below, which means the
                               asymptotic expansion failed */
          break;
        }
      MPFR_ZIV_NEXT (loop, w);
    }
  MPFR_ZIV_FREE (loop);

  inex = (MPFR_IS_POS(z) || ((n & 1) == 0)) ? mpfr_set (res, c, r)
    : mpfr_neg (res, c, r);
  mpfr_clear (c);

  return inex;
}
static int
mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* assumes that op (that is, its real or imaginary part) is not finite */
{
   int overlap;
   mpc_t op_loc;

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

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

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

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

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

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

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

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

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

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

   if (overlap)
      mpc_clear (op_loc);

   return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
      /* everything is exact */
}
Esempio n. 16
0
static void
consistency (void)
{
  mpfr_t x, s1, s2, c1, c2;
  mpfr_exp_t emin, emax;
  mpfr_rnd_t rnd;
  unsigned int flags_sin, flags_cos, flags, flags_before, flags_ref;
  int inex_sin, is, inex_cos, ic, inex, inex_ref;
  int i;

  emin = mpfr_get_emin ();
  emax = mpfr_get_emax ();

  for (i = 0; i <= 10000; i++)
    {
      mpfr_init2 (x, MPFR_PREC_MIN + (randlimb () % 8));
      mpfr_inits2 (MPFR_PREC_MIN + (randlimb () % 8), s1, s2, c1, c2,
                   (mpfr_ptr) 0);
      if (i < 8 * MPFR_RND_MAX)
        {
          int j = i / MPFR_RND_MAX;
          if (j & 1)
            mpfr_set_emin (MPFR_EMIN_MIN);
          mpfr_set_si (x, (j & 2) ? 1 : -1, MPFR_RNDN);
          mpfr_set_exp (x, mpfr_get_emin ());
          rnd = (mpfr_rnd_t) (i % MPFR_RND_MAX);
          flags_before = 0;
          if (j & 4)
            mpfr_set_emax (-17);
        }
      else
        {
          tests_default_random (x, 256, -5, 50, 0);
          rnd = RND_RAND ();
          flags_before = (randlimb () & 1) ?
            (unsigned int) (MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE) :
            (unsigned int) 0;
        }
      __gmpfr_flags = flags_before;
      inex_sin = mpfr_sin (s1, x, rnd);
      is = inex_sin < 0 ? 2 : inex_sin > 0 ? 1 : 0;
      flags_sin = __gmpfr_flags;
      __gmpfr_flags = flags_before;
      inex_cos = mpfr_cos (c1, x, rnd);
      ic = inex_cos < 0 ? 2 : inex_cos > 0 ? 1 : 0;
      flags_cos = __gmpfr_flags;
      __gmpfr_flags = flags_before;
      inex = mpfr_sin_cos (s2, c2, x, rnd);
      flags = __gmpfr_flags;
      inex_ref = is + 4 * ic;
      flags_ref = flags_sin | flags_cos;
      if (!(mpfr_equal_p (s1, s2) && mpfr_equal_p (c1, c2)) ||
          inex != inex_ref || flags != flags_ref)
        {
          printf ("mpfr_sin_cos and mpfr_sin/mpfr_cos disagree on %s,"
                  " i = %d\nx = ", mpfr_print_rnd_mode (rnd), i);
          mpfr_dump (x);
          printf ("s1 = ");
          mpfr_dump (s1);
          printf ("s2 = ");
          mpfr_dump (s2);
          printf ("c1 = ");
          mpfr_dump (c1);
          printf ("c2 = ");
          mpfr_dump (c2);
          printf ("inex_sin = %d (s = %d), inex_cos = %d (c = %d), "
                  "inex = %d (expected %d)\n",
                  inex_sin, is, inex_cos, ic, inex, inex_ref);
          printf ("flags_sin = 0x%x, flags_cos = 0x%x, "
                  "flags = 0x%x (expected 0x%x)\n",
                  flags_sin, flags_cos, flags, flags_ref);
          exit (1);
        }
      mpfr_clears (x, s1, s2, c1, c2, (mpfr_ptr) 0);
      mpfr_set_emin (emin);
      mpfr_set_emax (emax);
    }
}
int
mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
   /* Feature not documented in the texinfo file: One of rop_sin or
      rop_cos may be NULL, in which case it is not computed, and the
      corresponding ternary inexact value is set to 0 (exact).       */
{
   if (!mpc_fin_p (op))
      return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else if (mpfr_zero_p (MPC_IM (op)))
      return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else if (mpfr_zero_p (MPC_RE (op)))
      return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
   else {
      /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
                           and  cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      return (MPC_INEX12 (inex_sin, inex_cos));
   }
}
Esempio n. 18
0
int
mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  mpfr_t x, y, z;
  mpfr_prec_t prec;
  int ok = 0;
  int inex_re, inex_im;
  int saved_underflow, saved_overflow;

  /* special values */
  if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
    /* NaNs
       exp(nan +i*y) = nan -i*0   if y = -0,
                       nan +i*0   if y = +0,
                       nan +i*nan otherwise
       exp(x+i*nan) =   +/-0 +/-i*0 if x=-inf,
                      +/-inf +i*nan if x=+inf,
                         nan +i*nan otherwise */
    {
      if (mpfr_zero_p (mpc_imagref (op)))
        return mpc_set (rop, op, MPC_RNDNN);

      if (mpfr_inf_p (mpc_realref (op)))
        {
          if (mpfr_signbit (mpc_realref (op)))
            return mpc_set_ui_ui (rop, 0, 0, MPC_RNDNN);
          else
            {
              mpfr_set_inf (mpc_realref (rop), +1);
              mpfr_set_nan (mpc_imagref (rop));
              return MPC_INEX(0, 0); /* Inf/NaN are exact */
            }
        }
      mpfr_set_nan (mpc_realref (rop));
      mpfr_set_nan (mpc_imagref (rop));
      return MPC_INEX(0, 0); /* NaN is exact */
    }


  if (mpfr_zero_p (mpc_imagref(op)))
    /* special case when the input is real
       exp(x-i*0) = exp(x) -i*0, even if x is NaN
       exp(x+i*0) = exp(x) +i*0, even if x is NaN */
    {
      inex_re = mpfr_exp (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd));
      inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref(op), MPC_RND_IM(rnd));
      return MPC_INEX(inex_re, inex_im);
    }

  if (mpfr_zero_p (mpc_realref (op)))
    /* special case when the input is imaginary  */
    {
      inex_re = mpfr_cos (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE(rnd));
      inex_im = mpfr_sin (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM(rnd));
      return MPC_INEX(inex_re, inex_im);
    }


  if (mpfr_inf_p (mpc_realref (op)))
    /* real part is an infinity,
       exp(-inf +i*y) = 0*(cos y +i*sin y)
       exp(+inf +i*y) = +/-inf +i*nan         if y = +/-inf
                        +inf*(cos y +i*sin y) if 0 < |y| < inf */
    {
      mpfr_t n;

      mpfr_init2 (n, 2);
      if (mpfr_signbit (mpc_realref (op)))
        mpfr_set_ui (n, 0, GMP_RNDN);
      else
        mpfr_set_inf (n, +1);

      if (mpfr_inf_p (mpc_imagref (op)))
        {
          inex_re = mpfr_set (mpc_realref (rop), n, GMP_RNDN);
          if (mpfr_signbit (mpc_realref (op)))
            inex_im = mpfr_set (mpc_imagref (rop), n, GMP_RNDN);
          else
            {
              mpfr_set_nan (mpc_imagref (rop));
              inex_im = 0; /* NaN is exact */
            }
        }
      else
        {
          mpfr_t c, s;
          mpfr_init2 (c, 2);
          mpfr_init2 (s, 2);

          mpfr_sin_cos (s, c, mpc_imagref (op), GMP_RNDN);
          inex_re = mpfr_copysign (mpc_realref (rop), n, c, GMP_RNDN);
          inex_im = mpfr_copysign (mpc_imagref (rop), n, s, GMP_RNDN);

          mpfr_clear (s);
          mpfr_clear (c);
        }

      mpfr_clear (n);
      return MPC_INEX(inex_re, inex_im);
    }

  if (mpfr_inf_p (mpc_imagref (op)))
    /* real part is finite non-zero number, imaginary part is an infinity */
    {
      mpfr_set_nan (mpc_realref (rop));
      mpfr_set_nan (mpc_imagref (rop));
      return MPC_INEX(0, 0); /* NaN is exact */
    }


  /* from now on, both parts of op are regular numbers */

  prec = MPC_MAX_PREC(rop)
         + MPC_MAX (MPC_MAX (-mpfr_get_exp (mpc_realref (op)), 0),
                   -mpfr_get_exp (mpc_imagref (op)));
    /* When op is close to 0, then exp is close to 1+Re(op), while
       cos is close to 1-Im(op); to decide on the ternary value of exp*cos,
       we need a high enough precision so that none of exp or cos is
       computed as 1. */
  mpfr_init2 (x, 2);
  mpfr_init2 (y, 2);
  mpfr_init2 (z, 2);

  /* save the underflow or overflow flags from MPFR */
  saved_underflow = mpfr_underflow_p ();
  saved_overflow = mpfr_overflow_p ();

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

      mpfr_set_prec (x, prec);
      mpfr_set_prec (y, prec);
      mpfr_set_prec (z, prec);

      /* FIXME: x may overflow so x.y does overflow too, while Re(exp(op))
         could be represented in the precision of rop. */
      mpfr_clear_overflow ();
      mpfr_clear_underflow ();
      mpfr_exp (x, mpc_realref(op), GMP_RNDN); /* error <= 0.5ulp */
      mpfr_sin_cos (z, y, mpc_imagref(op), GMP_RNDN); /* errors <= 0.5ulp */
      mpfr_mul (y, y, x, GMP_RNDN); /* error <= 2ulp */
      ok = mpfr_overflow_p () || mpfr_zero_p (x)
        || mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ,
                       MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == GMP_RNDN));
      if (ok) /* compute imaginary part */
        {
          mpfr_mul (z, z, x, GMP_RNDN);
          ok = mpfr_overflow_p () || mpfr_zero_p (x)
            || mpfr_can_round (z, prec - 2, GMP_RNDN, GMP_RNDZ,
                       MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == GMP_RNDN));
        }
    }
  while (ok == 0);

  inex_re = mpfr_set (mpc_realref(rop), y, MPC_RND_RE(rnd));
  inex_im = mpfr_set (mpc_imagref(rop), z, MPC_RND_IM(rnd));
  if (mpfr_overflow_p ()) {
    /* overflow in real exponential, inex is sign of infinite result */
    inex_re = mpfr_sgn (y);
    inex_im = mpfr_sgn (z);
  }
  else if (mpfr_underflow_p ()) {
    /* underflow in real exponential, inex is opposite of sign of 0 result */
    inex_re = (mpfr_signbit (y) ? +1 : -1);
    inex_im = (mpfr_signbit (z) ? +1 : -1);
  }

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);

  /* restore underflow and overflow flags from MPFR */
  if (saved_underflow)
    mpfr_set_underflow ();
  if (saved_overflow)
    mpfr_set_overflow ();

  return MPC_INEX(inex_re, inex_im);
}
Esempio n. 19
0
/* computes tan(x) = sign(x)*sqrt(1/cos(x)^2-1) */
int
mpfr_tan (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode)
{
  mp_prec_t precy, m;
  int inexact;
  mpfr_t s, c;
  MPFR_ZIV_DECL (loop);
  MPFR_SAVE_EXPO_DECL (expo);
  MPFR_GROUP_DECL (group);

  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);
        }
    }

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

  MPFR_SAVE_EXPO_MARK (expo);

  /* Compute initial precision */
  precy = MPFR_PREC (y);
  m = precy + MPFR_INT_CEIL_LOG2 (precy) + 13;
  MPFR_ASSERTD (m >= 2); /* needed for the error analysis in algorithms.tex */

  MPFR_GROUP_INIT_2 (group, m, s, c);
  MPFR_ZIV_INIT (loop, m);
  for (;;)
    {
      /* The only way to get an overflow is to get ~ Pi/2
         But the result will be ~ 2^Prec(y). */
      mpfr_sin_cos (s, c, x, GMP_RNDN); /* err <= 1/2 ulp on s and c */
      mpfr_div (c, s, c, GMP_RNDN);     /* err <= 4 ulps */
      MPFR_ASSERTD (!MPFR_IS_SINGULAR (c));
      if (MPFR_LIKELY (MPFR_CAN_ROUND (c, m - 2, precy, rnd_mode)))
        break;
      MPFR_ZIV_NEXT (loop, m);
      MPFR_GROUP_REPREC_2 (group, m, s, c);
    }
  MPFR_ZIV_FREE (loop);
  inexact = mpfr_set (y, c, rnd_mode);
  MPFR_GROUP_CLEAR (group);

  MPFR_SAVE_EXPO_FREE (expo);
  return mpfr_check_range (y, inexact, rnd_mode);
}
Esempio n. 20
0
File: tan.c Progetto: Distrotech/mpc
int
mpc_tan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  mpc_t x, y;
  mpfr_prec_t prec;
  mpfr_exp_t err;
  int ok = 0;
  int inex;

  /* special values */
  if (!mpc_fin_p (op))
    {
      if (mpfr_nan_p (mpc_realref (op)))
        {
          if (mpfr_inf_p (mpc_imagref (op)))
            /* tan(NaN -i*Inf) = +/-0 -i */
            /* tan(NaN +i*Inf) = +/-0 +i */
            {
              /* exact unless 1 is not in exponent range */
              inex = mpc_set_si_si (rop, 0,
                                    (MPFR_SIGN (mpc_imagref (op)) < 0) ? -1 : +1,
                                    rnd);
            }
          else
            /* tan(NaN +i*y) = NaN +i*NaN, when y is finite */
            /* tan(NaN +i*NaN) = NaN +i*NaN */
            {
              mpfr_set_nan (mpc_realref (rop));
              mpfr_set_nan (mpc_imagref (rop));
              inex = MPC_INEX (0, 0); /* always exact */
            }
        }
      else if (mpfr_nan_p (mpc_imagref (op)))
        {
          if (mpfr_cmp_ui (mpc_realref (op), 0) == 0)
            /* tan(-0 +i*NaN) = -0 +i*NaN */
            /* tan(+0 +i*NaN) = +0 +i*NaN */
            {
              mpc_set (rop, op, rnd);
              inex = MPC_INEX (0, 0); /* always exact */
            }
          else
            /* tan(x +i*NaN) = NaN +i*NaN, when x != 0 */
            {
              mpfr_set_nan (mpc_realref (rop));
              mpfr_set_nan (mpc_imagref (rop));
              inex = MPC_INEX (0, 0); /* always exact */
            }
        }
      else if (mpfr_inf_p (mpc_realref (op)))
        {
          if (mpfr_inf_p (mpc_imagref (op)))
            /* tan(-Inf -i*Inf) = -/+0 -i */
            /* tan(-Inf +i*Inf) = -/+0 +i */
            /* tan(+Inf -i*Inf) = +/-0 -i */
            /* tan(+Inf +i*Inf) = +/-0 +i */
            {
              const int sign_re = mpfr_signbit (mpc_realref (op));
              int inex_im;

              mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
              mpfr_setsign (mpc_realref (rop), mpc_realref (rop), sign_re, MPFR_RNDN);

              /* exact, unless 1 is not in exponent range */
              inex_im = mpfr_set_si (mpc_imagref (rop),
                                     mpfr_signbit (mpc_imagref (op)) ? -1 : +1,
                                     MPC_RND_IM (rnd));
              inex = MPC_INEX (0, inex_im);
            }
          else
            /* tan(-Inf +i*y) = tan(+Inf +i*y) = NaN +i*NaN, when y is
               finite */
            {
              mpfr_set_nan (mpc_realref (rop));
              mpfr_set_nan (mpc_imagref (rop));
              inex = MPC_INEX (0, 0); /* always exact */
            }
        }
      else
        /* tan(x -i*Inf) = +0*sin(x)*cos(x) -i, when x is finite */
        /* tan(x +i*Inf) = +0*sin(x)*cos(x) +i, when x is finite */
        {
          mpfr_t c;
          mpfr_t s;
          int inex_im;

          mpfr_init (c);
          mpfr_init (s);

          mpfr_sin_cos (s, c, mpc_realref (op), MPFR_RNDN);
          mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
          mpfr_setsign (mpc_realref (rop), mpc_realref (rop),
                        mpfr_signbit (c) != mpfr_signbit (s), MPFR_RNDN);
          /* exact, unless 1 is not in exponent range */
          inex_im = mpfr_set_si (mpc_imagref (rop),
                                 (mpfr_signbit (mpc_imagref (op)) ? -1 : +1),
                                 MPC_RND_IM (rnd));
          inex = MPC_INEX (0, inex_im);

          mpfr_clear (s);
          mpfr_clear (c);
        }

      return inex;
    }

  if (mpfr_zero_p (mpc_realref (op)))
    /* tan(-0 -i*y) = -0 +i*tanh(y), when y is finite. */
    /* tan(+0 +i*y) = +0 +i*tanh(y), when y is finite. */
    {
      int inex_im;

      mpfr_set (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
      inex_im = mpfr_tanh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));

      return MPC_INEX (0, inex_im);
    }

  if (mpfr_zero_p (mpc_imagref (op)))
    /* tan(x -i*0) = tan(x) -i*0, when x is finite. */
    /* tan(x +i*0) = tan(x) +i*0, when x is finite. */
    {
      int inex_re;

      inex_re = mpfr_tan (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
      mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));

      return MPC_INEX (inex_re, 0);
    }

  /* ordinary (non-zero) numbers */

  /* tan(op) = sin(op) / cos(op).

     We use the following algorithm with rounding away from 0 for all
     operations, and working precision w:

     (1) x = A(sin(op))
     (2) y = A(cos(op))
     (3) z = A(x/y)

     the error on Im(z) is at most 81 ulp,
     the error on Re(z) is at most
     7 ulp if k < 2,
     8 ulp if k = 2,
     else 5+k ulp, where
     k = Exp(Re(x))+Exp(Re(y))-2min{Exp(Re(y)), Exp(Im(y))}-Exp(Re(x/y))
     see proof in algorithms.tex.
  */

  prec = MPC_MAX_PREC(rop);

  mpc_init2 (x, 2);
  mpc_init2 (y, 2);

  err = 7;

  do
    {
      mpfr_exp_t k, exr, eyr, eyi, ezr;

      ok = 0;

      /* FIXME: prevent addition overflow */
      prec += mpc_ceil_log2 (prec) + err;
      mpc_set_prec (x, prec);
      mpc_set_prec (y, prec);

      /* rounding away from zero: except in the cases x=0 or y=0 (processed
         above), sin x and cos y are never exact, so rounding away from 0 is
         rounding towards 0 and adding one ulp to the absolute value */
      mpc_sin_cos (x, y, op, MPC_RNDZZ, MPC_RNDZZ);
      MPFR_ADD_ONE_ULP (mpc_realref (x));
      MPFR_ADD_ONE_ULP (mpc_imagref (x));
      MPFR_ADD_ONE_ULP (mpc_realref (y));
      MPFR_ADD_ONE_ULP (mpc_imagref (y));
      MPC_ASSERT (mpfr_zero_p (mpc_realref (x)) == 0);

      if (   mpfr_inf_p (mpc_realref (x)) || mpfr_inf_p (mpc_imagref (x))
          || mpfr_inf_p (mpc_realref (y)) || mpfr_inf_p (mpc_imagref (y))) {
         /* If the real or imaginary part of x is infinite, it means that
            Im(op) was large, in which case the result is
            sign(tan(Re(op)))*0 + sign(Im(op))*I,
            where sign(tan(Re(op))) = sign(Re(x))*sign(Re(y)). */
          int inex_re, inex_im;
          mpfr_set_ui (mpc_realref (rop), 0, MPFR_RNDN);
          if (mpfr_sgn (mpc_realref (x)) * mpfr_sgn (mpc_realref (y)) < 0)
            {
              mpfr_neg (mpc_realref (rop), mpc_realref (rop), MPFR_RNDN);
              inex_re = 1;
            }
          else
            inex_re = -1; /* +0 is rounded down */
          if (mpfr_sgn (mpc_imagref (op)) > 0)
            {
              mpfr_set_ui (mpc_imagref (rop), 1, MPFR_RNDN);
              inex_im = 1;
            }
          else
            {
              mpfr_set_si (mpc_imagref (rop), -1, MPFR_RNDN);
              inex_im = -1;
            }
          inex = MPC_INEX(inex_re, inex_im);
          goto end;
        }

      exr = mpfr_get_exp (mpc_realref (x));
      eyr = mpfr_get_exp (mpc_realref (y));
      eyi = mpfr_get_exp (mpc_imagref (y));

      /* some parts of the quotient may be exact */
      inex = mpc_div (x, x, y, MPC_RNDZZ);
      /* OP is no pure real nor pure imaginary, so in theory the real and
         imaginary parts of its tangent cannot be null. However due to
         rouding errors this might happen. Consider for example
         tan(1+14*I) = 1.26e-10 + 1.00*I. For small precision sin(op) and
         cos(op) differ only by a factor I, thus after mpc_div x = I and
         its real part is zero. */
      if (mpfr_zero_p (mpc_realref (x)) || mpfr_zero_p (mpc_imagref (x)))
        {
          err = prec; /* double precision */
          continue;
        }
      if (MPC_INEX_RE (inex))
         MPFR_ADD_ONE_ULP (mpc_realref (x));
      if (MPC_INEX_IM (inex))
         MPFR_ADD_ONE_ULP (mpc_imagref (x));
      MPC_ASSERT (mpfr_zero_p (mpc_realref (x)) == 0);
      ezr = mpfr_get_exp (mpc_realref (x));

      /* FIXME: compute
         k = Exp(Re(x))+Exp(Re(y))-2min{Exp(Re(y)), Exp(Im(y))}-Exp(Re(x/y))
         avoiding overflow */
      k = exr - ezr + MPC_MAX(-eyr, eyr - 2 * eyi);
      err = k < 2 ? 7 : (k == 2 ? 8 : (5 + k));

      /* Can the real part be rounded? */
      ok = (!mpfr_number_p (mpc_realref (x)))
           || mpfr_can_round (mpc_realref(x), prec - err, MPFR_RNDN, MPFR_RNDZ,
                      MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == MPFR_RNDN));

      if (ok)
        {
          /* Can the imaginary part be rounded? */
          ok = (!mpfr_number_p (mpc_imagref (x)))
               || mpfr_can_round (mpc_imagref(x), prec - 6, MPFR_RNDN, MPFR_RNDZ,
                      MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == MPFR_RNDN));
        }
    }
  while (ok == 0);

  inex = mpc_set (rop, x, rnd);

 end:
  mpc_clear (x);
  mpc_clear (y);

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

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

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

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

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

   prec = MPC_MAX_PREC(rop);

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

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

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

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

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

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

   return MPC_INEX(inex_re, inex_im);
}
Esempio n. 22
0
static void
_assympt_mpfr (gulong l, mpq_t q, mpfr_ptr res, mp_rnd_t rnd)
{
  NcmBinSplit **bs_ptr = _ncm_mpsf_sbessel_get_bs ();
  NcmBinSplit *bs = *bs_ptr;
  _binsplit_spherical_bessel *data = (_binsplit_spherical_bessel *) bs->userdata;
  gulong prec = mpfr_get_prec (res);
#define sin_x data->sin
#define cos_x data->cos
  mpfr_set_prec (sin_x, prec);
  mpfr_set_prec (cos_x, prec);

  mpfr_set_q (res, q, rnd);
  mpfr_sin_cos (sin_x, cos_x, res, rnd);

  switch (l % 4)
  {
    case 0:
      break;
    case 1:
      mpfr_swap (sin_x, cos_x);
      mpfr_neg (sin_x, sin_x, rnd);
      break;
    case 2:
      mpfr_neg (sin_x, sin_x, rnd);
      mpfr_neg (cos_x, cos_x, rnd);
      break;
    case 3:
      mpfr_swap (sin_x, cos_x);
      mpfr_neg (cos_x, cos_x, rnd);
      break;
  }

  if (l > 0)
  {
    mpfr_mul_ui (cos_x, cos_x, l * (l + 1), rnd);
    mpfr_div (cos_x, cos_x, res, rnd);
    mpfr_div (cos_x, cos_x, res, rnd);
    mpfr_div_2ui (cos_x, cos_x, 1, rnd);
  }

  mpfr_div (sin_x, sin_x, res, rnd);

  data->l = l;
  mpq_inv (data->mq2_2, q);
  mpq_mul (data->mq2_2, data->mq2_2, data->mq2_2);
  mpq_neg (data->mq2_2, data->mq2_2);
  mpq_div_2exp (data->mq2_2, data->mq2_2, 2);

  data->sincos = 0;
  binsplit_spherical_bessel_assympt (bs, 0, (l + 1) / 2 + (l + 1) % 2);
  mpfr_mul_z (sin_x, sin_x, bs->T, rnd);
  mpfr_div_z (sin_x, sin_x, bs->Q, rnd);

  data->sincos = 1;
  if (l > 0)
  {
    binsplit_spherical_bessel_assympt (bs, 0, l / 2 + l % 2);
    mpfr_mul_z (cos_x, cos_x, bs->T, rnd);
    mpfr_div_z (cos_x, cos_x, bs->Q, rnd);
    mpfr_add (res, sin_x, cos_x, rnd);
  }
  else
    mpfr_set (res, sin_x, rnd);

  ncm_memory_pool_return (bs_ptr);
  return;
}
Esempio n. 23
0
static void
overflowed_sin_cos0 (void)
{
  mpfr_t x, y, z;
  int emax, inex, rnd, err = 0;
  mpfr_exp_t old_emax;

  old_emax = mpfr_get_emax ();

  mpfr_init2 (x, 8);
  mpfr_init2 (y, 8);
  mpfr_init2 (z, 8);

  for (emax = -1; emax <= 0; emax++)
    {
      mpfr_set_ui_2exp (z, 1, emax, MPFR_RNDN);
      mpfr_nextbelow (z);
      set_emax (emax);  /* 1 is not representable. */
      /* and if emax < 0, 1 - eps is not representable either. */
      RND_LOOP (rnd)
        {
          mpfr_set_si (x, 0, MPFR_RNDN);
          mpfr_neg (x, x, MPFR_RNDN);
          mpfr_clear_flags ();
          inex = mpfr_sin_cos (x, y, x, (mpfr_rnd_t) rnd);
          if (! mpfr_overflow_p ())
            {
              printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                      "  The overflow flag is not set.\n",
                      mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
              err = 1;
            }
          if (! (mpfr_zero_p (x) && MPFR_IS_NEG (x)))
            {
              printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                      "  Got sin = ", mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
              mpfr_print_binary (x);
              printf (" instead of -0.\n");
              err = 1;
            }
          if (rnd == MPFR_RNDZ || rnd == MPFR_RNDD)
            {
              if (inex == 0)
                {
                  printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                          "  The inexact value must be non-zero.\n",
                          mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                  err = 1;
                }
              if (! mpfr_equal_p (y, z))
                {
                  printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                          "  Got cos = ",
                          mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                  mpfr_print_binary (y);
                  printf (" instead of 0.11111111E%d.\n", emax);
                  err = 1;
                }
            }
          else
            {
              if (inex == 0)
                {
                  printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                          "  The inexact value must be non-zero.\n",
                          mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                  err = 1;
                }
              if (! (mpfr_inf_p (y) && MPFR_IS_POS (y)))
                {
                  printf ("Error in overflowed_sin_cos0 (rnd = %s):\n"
                          "  Got cos = ",
                          mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
                  mpfr_print_binary (y);
                  printf (" instead of +Inf.\n");
                  err = 1;
                }
            }
        }
      set_emax (old_emax);
    }

  if (err)
    exit (1);
  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);
}
Esempio n. 24
0
int
main (int argc, char *argv[])
{
  mpfr_t x, c, s, c2, s2;

  tests_start_mpfr ();

  check_regression ();
  check_nans ();

  /* worst case from PhD thesis of Vincent Lefe`vre: x=8980155785351021/2^54 */
  check53 ("4.984987858808754279e-1", "4.781075595393330379e-1", MPFR_RNDN);
  check53 ("4.984987858808754279e-1", "4.781075595393329824e-1", MPFR_RNDD);
  check53 ("4.984987858808754279e-1", "4.781075595393329824e-1", MPFR_RNDZ);
  check53 ("4.984987858808754279e-1", "4.781075595393330379e-1", MPFR_RNDU);
  check53 ("1.00031274099908640274",  "8.416399183372403892e-1", MPFR_RNDN);
  check53 ("1.00229256850978698523",  "8.427074524447979442e-1", MPFR_RNDZ);
  check53 ("1.00288304857059840103",  "8.430252033025980029e-1", MPFR_RNDZ);
  check53 ("1.00591265847407274059",  "8.446508805292128885e-1", MPFR_RNDN);

  /* Other worst cases showing a bug introduced on 2005-01-29 in rev 3248 */
  check53b ("1.0111001111010111010111111000010011010001110001111011e-21",
            "1.0111001111010111010111111000010011010001101001110001e-21",
            MPFR_RNDU);
  check53b ("1.1011101111111010000001010111000010000111100100101101",
            "1.1111100100101100001111100000110011110011010001010101e-1",
            MPFR_RNDU);

  mpfr_init2 (x, 2);

  mpfr_set_str (x, "0.5", 10, MPFR_RNDN);
  test_sin (x, x, MPFR_RNDD);
  if (mpfr_cmp_ui_2exp (x, 3, -3)) /* x != 0.375 = 3/8 */
    {
      printf ("mpfr_sin(0.5, MPFR_RNDD) failed with precision=2\n");
      exit (1);
    }

  /* bug found by Kevin Ryde */
  mpfr_const_pi (x, MPFR_RNDN);
  mpfr_mul_ui (x, x, 3L, MPFR_RNDN);
  mpfr_div_ui (x, x, 2L, MPFR_RNDN);
  test_sin (x, x, MPFR_RNDN);
  if (mpfr_cmp_ui (x, 0) >= 0)
    {
      printf ("Error: wrong sign for sin(3*Pi/2)\n");
      exit (1);
    }

  /* Can fail on an assert */
  mpfr_set_prec (x, 53);
  mpfr_set_str (x, "77291789194529019661184401408", 10, MPFR_RNDN);
  mpfr_init2 (c, 4); mpfr_init2 (s, 42);
  mpfr_init2 (c2, 4); mpfr_init2 (s2, 42);

  test_sin (s, x, MPFR_RNDN);
  mpfr_cos (c, x, MPFR_RNDN);
  mpfr_sin_cos (s2, c2, x, MPFR_RNDN);
  if (mpfr_cmp (c2, c))
    {
      printf("cos differs for x=77291789194529019661184401408");
      exit (1);
    }
  if (mpfr_cmp (s2, s))
    {
      printf("sin differs for x=77291789194529019661184401408");
      exit (1);
    }

  mpfr_set_str_binary (x, "1.1001001000011111101101010100010001000010110100010011");
  test_sin (x, x, MPFR_RNDZ);
  if (mpfr_cmp_str (x, "1.1111111111111111111111111111111111111111111111111111e-1", 2, MPFR_RNDN))
    {
      printf ("Error for x= 1.1001001000011111101101010100010001000010110100010011\nGot ");
      mpfr_dump (x);
      exit (1);
    }

  mpfr_set_prec (s, 9);
  mpfr_set_prec (x, 190);
  mpfr_const_pi (x, MPFR_RNDN);
  mpfr_sin (s, x, MPFR_RNDZ);
  if (mpfr_cmp_str (s, "0.100000101e-196", 2, MPFR_RNDN))
    {
      printf ("Error for x ~= pi\n");
      mpfr_dump (s);
      exit (1);
    }

  mpfr_clear (s2);
  mpfr_clear (c2);
  mpfr_clear (s);
  mpfr_clear (c);
  mpfr_clear (x);

  test_generic (2, 100, 15);
  test_generic (MPFR_SINCOS_THRESHOLD-1, MPFR_SINCOS_THRESHOLD+1, 2);
  test_sign ();
  check_tiny ();

  data_check ("data/sin", mpfr_sin, "mpfr_sin");
  bad_cases (mpfr_sin, mpfr_asin, "mpfr_sin", 256, -40, 0, 4, 128, 800, 50);

  tests_end_mpfr ();
  return 0;
}
Esempio n. 25
0
int
mpc_cos (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
{
  mpfr_t x, y, z;
  mp_prec_t prec;
  int ok = 0;
  int inex_re, inex_im;

  /* special values */
  if (!mpfr_number_p (MPC_RE (op)) || !mpfr_number_p (MPC_IM (op)))
    {
      if (mpfr_nan_p (MPC_RE (op)))
        {
          /* cos(NaN + i * NaN) = NaN + i * NaN */
          /* cos(NaN - i * Inf) = +Inf + i * NaN */
          /* cos(NaN + i * Inf) = +Inf + i * NaN */
          /* cos(NaN - i * 0) = NaN - i * 0 */
          /* cos(NaN + i * 0) = NaN + i * 0 */
          /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
          if (mpfr_inf_p (MPC_IM (op)))
            mpfr_set_inf (MPC_RE (rop), +1);
          else
            mpfr_set_nan (MPC_RE (rop));

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

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

          /* SAME_SIGN is useful only if op == (+/-)Inf + i * (+/-)0, but, as
             MPC_RE(OP) might be erased (when ROP == OP), we compute it now */
          const int same_sign =
            mpfr_signbit (MPC_RE (op)) == mpfr_signbit (MPC_IM (op));

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

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

          mpfr_setsign (MPC_IM (rop), MPC_RE (op), same_sign,
                        MPC_RND_IM (rnd));
          mpfr_set_inf (MPC_RE (rop), +1);
        }
      else
        {
          /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
          /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
          mpfr_t c;
          mpfr_t s;

          mpfr_init (c);
          mpfr_init (s);

          mpfr_sin_cos (s, c, MPC_RE (op), GMP_RNDN);
          mpfr_set_inf (MPC_RE (rop), mpfr_sgn (c));
          mpfr_set_inf (MPC_IM (rop),
                        (mpfr_sgn (MPC_IM (op)) == mpfr_sgn (s) ? -1 : +1));

          mpfr_clear (s);
          mpfr_clear (c);
        }

      return MPC_INEX (0, 0); /* always exact */
    }

  if (mpfr_zero_p (MPC_RE (op)))
    {
      /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0
         cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
         when y >= 0 */

      /* When ROP == OP, the sign of 0 will be erased, so use it now */
      const int imag_sign =
        mpfr_signbit (MPC_RE (op)) ==  mpfr_signbit (MPC_IM (op));

      if (mpfr_zero_p (MPC_IM (op)))
        inex_re = mpfr_set_ui (MPC_RE (rop), 1, MPC_RND_RE (rnd));
      else
        inex_re = mpfr_cosh (MPC_RE (rop), MPC_IM (op), MPC_RND_RE (rnd));

      mpfr_set_ui (MPC_IM (rop), 0, MPC_RND_IM (rnd));
      mpfr_setsign (MPC_IM (rop), MPC_IM (rop), imag_sign, MPC_RND_IM (rnd));

      return MPC_INEX (inex_re, 0);
    }

  if (mpfr_zero_p (MPC_IM (op)))
    {
      /* cos(x +i*0) = cos(x) -i*0*sign(sin(x)) */
      /* cos(x -i*0) = cos(x) +i*0*sign(sin(x)) */
      mpfr_t sign;
      mpfr_init2 (sign, 2);
      mpfr_sin (sign, MPC_RE (op), GMP_RNDN);
      if (!mpfr_signbit (MPC_IM (op)))
         MPFR_CHANGE_SIGN (sign);

      inex_re = mpfr_cos (MPC_RE (rop), MPC_RE (op), MPC_RND_RE (rnd));

      mpfr_set_ui (MPC_IM (rop), 0ul, GMP_RNDN);
      if (mpfr_signbit (sign))
         MPFR_CHANGE_SIGN (MPC_IM (rop));

      mpfr_clear (sign);

      return MPC_INEX (inex_re, 0);
    }

  /* ordinary (non-zero) numbers */

  /* let op = a + i*b, then cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).

     We use the following algorithm (same for the imaginary part),
     with rounding to nearest for all operations, and working precision w:

     (1) x = o(cos(a))
     (2) y = o(cosh(b))
     (3) r = o(x*y)
     then the error on r is at most 4 ulps, since we can write
     r = cos(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
     thus for w >= 2, r = cos(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
     thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
  */

  prec = MPC_MAX_PREC(rop);

  mpfr_init2 (x, 2);
  mpfr_init2 (y, 2);
  mpfr_init2 (z, 2);

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

      mpfr_set_prec (x, prec);
      mpfr_set_prec (y, prec);
      mpfr_set_prec (z, prec);

      mpfr_sin_cos (y, x, MPC_RE(op), GMP_RNDN);
      mpfr_cosh (z, MPC_IM(op), GMP_RNDN);
      mpfr_mul (x, x, z, GMP_RNDN);
      ok = mpfr_can_round (x, prec - 2, GMP_RNDN, GMP_RNDZ,
                      MPFR_PREC(MPC_RE(rop)) + (MPC_RND_RE(rnd) == GMP_RNDN));
      if (ok) /* compute imaginary part */
        {
          mpfr_sinh (z, MPC_IM(op), GMP_RNDN);
          mpfr_mul (y, y, z, GMP_RNDN);
          mpfr_neg (y, y, GMP_RNDN);
          ok = mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ,
                      MPFR_PREC(MPC_IM(rop)) + (MPC_RND_IM(rnd) == GMP_RNDN));
        }
    }
  while (ok == 0);

  inex_re = mpfr_set (MPC_RE(rop), x, MPC_RND_RE(rnd));
  inex_im = mpfr_set (MPC_IM(rop), y, MPC_RND_IM(rnd));

  mpfr_clear (x);
  mpfr_clear (y);
  mpfr_clear (z);

  return MPC_INEX (inex_re, inex_im);
}