Blame src/sin_cos.c

Packit Service 2e9770
/* mpc_sin_cos -- combined sine and cosine of a complex number.
Packit Service 2e9770
Packit Service 2e9770
Copyright (C) 2010, 2011, 2012 INRIA
Packit Service 2e9770
Packit Service 2e9770
This file is part of GNU MPC.
Packit Service 2e9770
Packit Service 2e9770
GNU MPC is free software; you can redistribute it and/or modify it under
Packit Service 2e9770
the terms of the GNU Lesser General Public License as published by the
Packit Service 2e9770
Free Software Foundation; either version 3 of the License, or (at your
Packit Service 2e9770
option) any later version.
Packit Service 2e9770
Packit Service 2e9770
GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
Packit Service 2e9770
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
Packit Service 2e9770
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
Packit Service 2e9770
more details.
Packit Service 2e9770
Packit Service 2e9770
You should have received a copy of the GNU Lesser General Public License
Packit Service 2e9770
along with this program. If not, see http://www.gnu.org/licenses/ .
Packit Service 2e9770
*/
Packit Service 2e9770
Packit Service 2e9770
#include <stdio.h>
Packit Service 2e9770
#include "mpc-impl.h"
Packit Service 2e9770
Packit Service 2e9770
static int
Packit Service 2e9770
mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
Packit Service 2e9770
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
Packit Service 2e9770
   /* assumes that op (that is, its real or imaginary part) is not finite */
Packit Service 2e9770
{
Packit Service 2e9770
   int overlap;
Packit Service 2e9770
   mpc_t op_loc;
Packit Service 2e9770
Packit Service 2e9770
   overlap = (rop_sin == op || rop_cos == op);
Packit Service 2e9770
   if (overlap) {
Packit Service 2e9770
      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
Packit Service 2e9770
      mpc_set (op_loc, op, MPC_RNDNN);
Packit Service 2e9770
   }
Packit Service 2e9770
   else
Packit Service 2e9770
      op_loc [0] = op [0];
Packit Service 2e9770
Packit Service 2e9770
   if (rop_sin != NULL) {
Packit Service 2e9770
      if (mpfr_nan_p (mpc_realref (op_loc)) || mpfr_nan_p (mpc_imagref (op_loc))) {
Packit Service 2e9770
         mpc_set (rop_sin, op_loc, rnd_sin);
Packit Service 2e9770
         if (mpfr_nan_p (mpc_imagref (op_loc))) {
Packit Service 2e9770
            /* sin(x +i*NaN) = NaN +i*NaN, except for x=0 */
Packit Service 2e9770
            /* sin(-0 +i*NaN) = -0 +i*NaN */
Packit Service 2e9770
            /* sin(+0 +i*NaN) = +0 +i*NaN */
Packit Service 2e9770
            if (!mpfr_zero_p (mpc_realref (op_loc)))
Packit Service 2e9770
               mpfr_set_nan (mpc_realref (rop_sin));
Packit Service 2e9770
         }
Packit Service 2e9770
         else /* op = NaN + i*y */
Packit Service 2e9770
            if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            /* sin(NaN -i*Inf) = NaN -i*Inf */
Packit Service 2e9770
            /* sin(NaN -i*0) = NaN -i*0 */
Packit Service 2e9770
            /* sin(NaN +i*0) = NaN +i*0 */
Packit Service 2e9770
            /* sin(NaN +i*Inf) = NaN +i*Inf */
Packit Service 2e9770
            /* sin(NaN +i*y) = NaN +i*NaN, when 0<|y|
Packit Service 2e9770
            mpfr_set_nan (mpc_imagref (rop_sin));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mpfr_inf_p (mpc_realref (op_loc))) {
Packit Service 2e9770
         mpfr_set_nan (mpc_realref (rop_sin));
Packit Service 2e9770
Packit Service 2e9770
         if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            /* sin(+/-Inf +i*y) = NaN +i*NaN, when 0<|y|
Packit Service 2e9770
            mpfr_set_nan (mpc_imagref (rop_sin));
Packit Service 2e9770
         else
Packit Service 2e9770
            /* sin(+/-Inf -i*Inf) = NaN -i*Inf */
Packit Service 2e9770
            /* sin(+/-Inf +i*Inf) = NaN +i*Inf */
Packit Service 2e9770
            /* sin(+/-Inf -i*0) = NaN -i*0 */
Packit Service 2e9770
            /* sin(+/-Inf +i*0) = NaN +i*0 */
Packit Service 2e9770
            mpfr_set (mpc_imagref (rop_sin), mpc_imagref (op_loc), MPC_RND_IM (rnd_sin));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mpfr_zero_p (mpc_realref (op_loc))) {
Packit Service 2e9770
         /* sin(-0 -i*Inf) = -0 -i*Inf */
Packit Service 2e9770
         /* sin(+0 -i*Inf) = +0 -i*Inf */
Packit Service 2e9770
         /* sin(-0 +i*Inf) = -0 +i*Inf */
Packit Service 2e9770
         /* sin(+0 +i*Inf) = +0 +i*Inf */
Packit Service 2e9770
         mpc_set (rop_sin, op_loc, rnd_sin);
Packit Service 2e9770
      }
Packit Service 2e9770
      else {
Packit Service 2e9770
         /* sin(x -i*Inf) = +Inf*(sin(x) -i*cos(x)) */
Packit Service 2e9770
         /* sin(x +i*Inf) = +Inf*(sin(x) +i*cos(x)) */
Packit Service 2e9770
         mpfr_t s, c;
Packit Service 2e9770
         mpfr_init2 (s, 2);
Packit Service 2e9770
         mpfr_init2 (c, 2);
Packit Service 2e9770
         mpfr_sin_cos (s, c, mpc_realref (op_loc), MPFR_RNDZ);
Packit Service 2e9770
         mpfr_set_inf (mpc_realref (rop_sin), MPFR_SIGN (s));
Packit Service 2e9770
         mpfr_set_inf (mpc_imagref (rop_sin), MPFR_SIGN (c)*MPFR_SIGN (mpc_imagref (op_loc)));
Packit Service 2e9770
         mpfr_clear (s);
Packit Service 2e9770
         mpfr_clear (c);
Packit Service 2e9770
      }
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (rop_cos != NULL) {
Packit Service 2e9770
      if (mpfr_nan_p (mpc_realref (op_loc))) {
Packit Service 2e9770
         /* cos(NaN + i * NaN) = NaN + i * NaN */
Packit Service 2e9770
         /* cos(NaN - i * Inf) = +Inf + i * NaN */
Packit Service 2e9770
         /* cos(NaN + i * Inf) = +Inf + i * NaN */
Packit Service 2e9770
         /* cos(NaN - i * 0) = NaN - i * 0 */
Packit Service 2e9770
         /* cos(NaN + i * 0) = NaN + i * 0 */
Packit Service 2e9770
         /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
Packit Service 2e9770
         if (mpfr_inf_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            mpfr_set_inf (mpc_realref (rop_cos), +1);
Packit Service 2e9770
         else
Packit Service 2e9770
            mpfr_set_nan (mpc_realref (rop_cos));
Packit Service 2e9770
Packit Service 2e9770
         if (mpfr_zero_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            mpfr_set (mpc_imagref (rop_cos), mpc_imagref (op_loc), MPC_RND_IM (rnd_cos));
Packit Service 2e9770
         else
Packit Service 2e9770
            mpfr_set_nan (mpc_imagref (rop_cos));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mpfr_nan_p (mpc_imagref (op_loc))) {
Packit Service 2e9770
          /* cos(-Inf + i * NaN) = NaN + i * NaN */
Packit Service 2e9770
          /* cos(+Inf + i * NaN) = NaN + i * NaN */
Packit Service 2e9770
          /* cos(-0 + i * NaN) = NaN - i * 0 */
Packit Service 2e9770
          /* cos(+0 + i * NaN) = NaN + i * 0 */
Packit Service 2e9770
          /* cos(x + i * NaN) = NaN + i * NaN, when x != 0 */
Packit Service 2e9770
         if (mpfr_zero_p (mpc_realref (op_loc)))
Packit Service 2e9770
            mpfr_set (mpc_imagref (rop_cos), mpc_realref (op_loc), MPC_RND_IM (rnd_cos));
Packit Service 2e9770
         else
Packit Service 2e9770
            mpfr_set_nan (mpc_imagref (rop_cos));
Packit Service 2e9770
Packit Service 2e9770
         mpfr_set_nan (mpc_realref (rop_cos));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mpfr_inf_p (mpc_realref (op_loc))) {
Packit Service 2e9770
         /* cos(-Inf -i*Inf) = cos(+Inf +i*Inf) = -Inf +i*NaN */
Packit Service 2e9770
         /* cos(-Inf +i*Inf) = cos(+Inf -i*Inf) = +Inf +i*NaN */
Packit Service 2e9770
         /* cos(-Inf -i*0) = cos(+Inf +i*0) = NaN -i*0 */
Packit Service 2e9770
         /* cos(-Inf +i*0) = cos(+Inf -i*0) = NaN +i*0 */
Packit Service 2e9770
         /* cos(-Inf +i*y) = cos(+Inf +i*y) = NaN +i*NaN, when y != 0 */
Packit Service 2e9770
Packit Service 2e9770
         const int same_sign =
Packit Service 2e9770
            mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
Packit Service 2e9770
Packit Service 2e9770
         if (mpfr_inf_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            mpfr_set_inf (mpc_realref (rop_cos), (same_sign ? -1 : +1));
Packit Service 2e9770
         else
Packit Service 2e9770
            mpfr_set_nan (mpc_realref (rop_cos));
Packit Service 2e9770
Packit Service 2e9770
         if (mpfr_zero_p (mpc_imagref (op_loc)))
Packit Service 2e9770
            mpfr_setsign (mpc_imagref (rop_cos), mpc_imagref (op_loc), same_sign,
Packit Service 2e9770
                          MPC_RND_IM(rnd_cos));
Packit Service 2e9770
         else
Packit Service 2e9770
            mpfr_set_nan (mpc_imagref (rop_cos));
Packit Service 2e9770
      }
Packit Service 2e9770
      else if (mpfr_zero_p (mpc_realref (op_loc))) {
Packit Service 2e9770
         /* cos(-0 -i*Inf) = cos(+0 +i*Inf) = +Inf -i*0 */
Packit Service 2e9770
         /* cos(-0 +i*Inf) = cos(+0 -i*Inf) = +Inf +i*0 */
Packit Service 2e9770
         const int same_sign =
Packit Service 2e9770
            mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
Packit Service 2e9770
Packit Service 2e9770
         mpfr_setsign (mpc_imagref (rop_cos), mpc_realref (op_loc), same_sign,
Packit Service 2e9770
                       MPC_RND_IM (rnd_cos));
Packit Service 2e9770
         mpfr_set_inf (mpc_realref (rop_cos), +1);
Packit Service 2e9770
      }
Packit Service 2e9770
      else {
Packit Service 2e9770
         /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
Packit Service 2e9770
         /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
Packit Service 2e9770
         mpfr_t s, c;
Packit Service 2e9770
         mpfr_init2 (c, 2);
Packit Service 2e9770
         mpfr_init2 (s, 2);
Packit Service 2e9770
         mpfr_sin_cos (s, c, mpc_realref (op_loc), MPFR_RNDN);
Packit Service 2e9770
         mpfr_set_inf (mpc_realref (rop_cos), mpfr_sgn (c));
Packit Service 2e9770
         mpfr_set_inf (mpc_imagref (rop_cos),
Packit Service 2e9770
            (mpfr_sgn (mpc_imagref (op_loc)) == mpfr_sgn (s) ? -1 : +1));
Packit Service 2e9770
         mpfr_clear (s);
Packit Service 2e9770
         mpfr_clear (c);
Packit Service 2e9770
      }
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_clear (op_loc);
Packit Service 2e9770
Packit Service 2e9770
   return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
Packit Service 2e9770
      /* everything is exact */
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
static int
Packit Service 2e9770
mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
Packit Service 2e9770
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
Packit Service 2e9770
   /* assumes that op is real */
Packit Service 2e9770
{
Packit Service 2e9770
   int inex_sin_re = 0, inex_cos_re = 0;
Packit Service 2e9770
      /* Until further notice, assume computations exact; in particular,
Packit Service 2e9770
         by definition, for not computed values.                         */
Packit Service 2e9770
   mpfr_t s, c;
Packit Service 2e9770
   int inex_s, inex_c;
Packit Service 2e9770
   int sign_im = mpfr_signbit (mpc_imagref (op));
Packit Service 2e9770
Packit Service 2e9770
   /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */
Packit Service 2e9770
   /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */
Packit Service 2e9770
   if (rop_sin != 0)
Packit Service 2e9770
      mpfr_init2 (s, MPC_PREC_RE (rop_sin));
Packit Service 2e9770
   else
Packit Service 2e9770
      mpfr_init2 (s, 2); /* We need only the sign. */
Packit Service 2e9770
   if (rop_cos != NULL)
Packit Service 2e9770
      mpfr_init2 (c, MPC_PREC_RE (rop_cos));
Packit Service 2e9770
   else
Packit Service 2e9770
      mpfr_init2 (c, 2);
Packit Service 2e9770
   inex_s = mpfr_sin (s, mpc_realref (op), MPC_RND_RE (rnd_sin));
Packit Service 2e9770
   inex_c = mpfr_cos (c, mpc_realref (op), MPC_RND_RE (rnd_cos));
Packit Service 2e9770
      /* We cannot use mpfr_sin_cos since we may need two distinct rounding
Packit Service 2e9770
         modes and the exact return values. If we need only the sign, an
Packit Service 2e9770
         arbitrary rounding mode will work.                                 */
Packit Service 2e9770
Packit Service 2e9770
   if (rop_sin != NULL) {
Packit Service 2e9770
      mpfr_set (mpc_realref (rop_sin), s, MPFR_RNDN); /* exact */
Packit Service 2e9770
      inex_sin_re = inex_s;
Packit Service 2e9770
      mpfr_set_zero (mpc_imagref (rop_sin),
Packit Service 2e9770
         (     ( sign_im && !mpfr_signbit(c))
Packit Service 2e9770
            || (!sign_im &&  mpfr_signbit(c)) ? -1 : 1));
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (rop_cos != NULL) {
Packit Service 2e9770
      mpfr_set (mpc_realref (rop_cos), c, MPFR_RNDN); /* exact */
Packit Service 2e9770
      inex_cos_re = inex_c;
Packit Service 2e9770
      mpfr_set_zero (mpc_imagref (rop_cos),
Packit Service 2e9770
         (     ( sign_im &&  mpfr_signbit(s))
Packit Service 2e9770
            || (!sign_im && !mpfr_signbit(s)) ? -1 : 1));
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   mpfr_clear (s);
Packit Service 2e9770
   mpfr_clear (c);
Packit Service 2e9770
Packit Service 2e9770
   return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
Packit Service 2e9770
static int
Packit Service 2e9770
mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
Packit Service 2e9770
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
Packit Service 2e9770
   /* assumes that op is purely imaginary, but not zero */
Packit Service 2e9770
{
Packit Service 2e9770
   int inex_sin_im = 0, inex_cos_re = 0;
Packit Service 2e9770
      /* assume exact if not computed */
Packit Service 2e9770
   int overlap;
Packit Service 2e9770
   mpc_t op_loc;
Packit Service 2e9770
Packit Service 2e9770
   overlap = (rop_sin == op || rop_cos == op);
Packit Service 2e9770
   if (overlap) {
Packit Service 2e9770
      mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
Packit Service 2e9770
      mpc_set (op_loc, op, MPC_RNDNN);
Packit Service 2e9770
   }
Packit Service 2e9770
   else
Packit Service 2e9770
      op_loc [0] = op [0];
Packit Service 2e9770
Packit Service 2e9770
   if (rop_sin != NULL) {
Packit Service 2e9770
      /* sin(+-O +i*y) = +-0 +i*sinh(y) */
Packit Service 2e9770
      mpfr_set (mpc_realref(rop_sin), mpc_realref(op_loc), MPFR_RNDN);
Packit Service 2e9770
      inex_sin_im = mpfr_sinh (mpc_imagref(rop_sin), mpc_imagref(op_loc), MPC_RND_IM(rnd_sin));
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (rop_cos != NULL) {
Packit Service 2e9770
      /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0,
Packit Service 2e9770
         cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
Packit Service 2e9770
         where y > 0 */
Packit Service 2e9770
      inex_cos_re = mpfr_cosh (mpc_realref (rop_cos), mpc_imagref (op_loc), MPC_RND_RE (rnd_cos));
Packit Service 2e9770
Packit Service 2e9770
      mpfr_set_ui (mpc_imagref (rop_cos), 0ul, MPC_RND_IM (rnd_cos));
Packit Service 2e9770
      if (mpfr_signbit (mpc_realref (op_loc)) ==  mpfr_signbit (mpc_imagref (op_loc)))
Packit Service 2e9770
         MPFR_CHANGE_SIGN (mpc_imagref (rop_cos));
Packit Service 2e9770
   }
Packit Service 2e9770
Packit Service 2e9770
   if (overlap)
Packit Service 2e9770
      mpc_clear (op_loc);
Packit Service 2e9770
Packit Service 2e9770
   return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0));
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
/* Fix an inexact overflow, when x is +Inf or -Inf:
Packit Service 2e9770
   When rnd is towards zero, change x into the largest (in absolute value)
Packit Service 2e9770
   floating-point number.
Packit Service 2e9770
   Return the inexact flag. */
Packit Service 2e9770
int
Packit Service 2e9770
mpc_fix_inf (mpfr_t x, mpfr_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
  MPC_ASSERT (mpfr_inf_p (x));
Packit Service 2e9770
  if (!MPC_IS_LIKE_RNDZ(rnd, MPFR_SIGNBIT(x)))
Packit Service 2e9770
    return mpfr_sgn (x);
Packit Service 2e9770
  else
Packit Service 2e9770
    {
Packit Service 2e9770
      if (mpfr_sgn (x) < 0)
Packit Service 2e9770
        mpfr_nextabove (x);
Packit Service 2e9770
      else
Packit Service 2e9770
        mpfr_nextbelow (x);
Packit Service 2e9770
      return -mpfr_sgn (x);
Packit Service 2e9770
    }
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
/* Fix an inexact underflow, when x is +0 or -0:
Packit Service 2e9770
   When rnd is away from zero, change x into the closest floating-point number.
Packit Service 2e9770
   Return the inexact flag. */
Packit Service 2e9770
int
Packit Service 2e9770
mpc_fix_zero (mpfr_t x, mpfr_rnd_t rnd)
Packit Service 2e9770
{
Packit Service 2e9770
  if (!MPC_IS_LIKE_RNDA(rnd, MPFR_SIGNBIT(x)))
Packit Service 2e9770
    return mpfr_signbit (x) == 0 ? -1 : 1;
Packit Service 2e9770
  else
Packit Service 2e9770
    {
Packit Service 2e9770
      if (mpfr_signbit (x) == 0)
Packit Service 2e9770
        {
Packit Service 2e9770
          mpfr_nextabove (x);
Packit Service 2e9770
          return 1;
Packit Service 2e9770
        }
Packit Service 2e9770
      else
Packit Service 2e9770
        {
Packit Service 2e9770
          mpfr_nextbelow (x);
Packit Service 2e9770
          return -1;
Packit Service 2e9770
        }
Packit Service 2e9770
    }
Packit Service 2e9770
}
Packit Service 2e9770
Packit Service 2e9770
int
Packit Service 2e9770
mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
Packit Service 2e9770
   mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
Packit Service 2e9770
   /* Feature not documented in the texinfo file: One of rop_sin or
Packit Service 2e9770
      rop_cos may be NULL, in which case it is not computed, and the
Packit Service 2e9770
      corresponding ternary inexact value is set to 0 (exact).       */
Packit Service 2e9770
{
Packit Service 2e9770
   if (!mpc_fin_p (op))
Packit Service 2e9770
      return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
Packit Service 2e9770
   else if (mpfr_zero_p (mpc_imagref (op)))
Packit Service 2e9770
      return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
Packit Service 2e9770
   else if (mpfr_zero_p (mpc_realref (op)))
Packit Service 2e9770
      return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
Packit Service 2e9770
   else {
Packit Service 2e9770
      /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
Packit Service 2e9770
                           and  cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).
Packit Service 2e9770
Packit Service 2e9770
         For Re(sin(op)) (and analogously, the other parts), we use the
Packit Service 2e9770
         following algorithm, with rounding to nearest for all operations
Packit Service 2e9770
         and working precision w:
Packit Service 2e9770
Packit Service 2e9770
         (1) x = o(sin(a))
Packit Service 2e9770
         (2) y = o(cosh(b))
Packit Service 2e9770
         (3) r = o(x*y)
Packit Service 2e9770
         then the error on r is at most 4 ulps, since we can write
Packit Service 2e9770
         r = sin(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
Packit Service 2e9770
         thus for w >= 2, r = sin(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
Packit Service 2e9770
         thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
Packit Service 2e9770
      */
Packit Service 2e9770
      mpfr_t s, c, sh, ch, sch, csh;
Packit Service 2e9770
      mpfr_prec_t prec;
Packit Service 2e9770
      int ok;
Packit Service 2e9770
      int inex_re, inex_im, inex_sin, inex_cos, loop = 0;
Packit Service 2e9770
Packit Service 2e9770
      prec = 2;
Packit Service 2e9770
      if (rop_sin != NULL)
Packit Service 2e9770
        {
Packit Service 2e9770
          mp_prec_t er, ei;
Packit Service 2e9770
          prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
Packit Service 2e9770
          /* since the Taylor expansion of sin(x) at x=0 is x - x^3/6 + O(x^5),
Packit Service 2e9770
             if x <= 2^(-p), then the second term/x is about 2^(-2p)/6, thus we
Packit Service 2e9770
             need at least 2p+3 bits of precision. This is true only when x is
Packit Service 2e9770
             exactly representable in the target precision. */
Packit Service 2e9770
          if (MPC_MAX_PREC (op) <= prec)
Packit Service 2e9770
            {
Packit Service 2e9770
              er = mpfr_get_exp (mpc_realref (op));
Packit Service 2e9770
              ei = mpfr_get_exp (mpc_imagref (op));
Packit Service 2e9770
              /* consider the maximal exponent only */
Packit Service 2e9770
              er = (er < ei) ? ei : er;
Packit Service 2e9770
              if (er < 0)
Packit Service 2e9770
                if (prec < 2 * (mp_prec_t) (-er) + 3)
Packit Service 2e9770
                  prec = 2 * (mp_prec_t) (-er) + 3;
Packit Service 2e9770
            }
Packit Service 2e9770
        }
Packit Service 2e9770
      if (rop_cos != NULL)
Packit Service 2e9770
         prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));
Packit Service 2e9770
Packit Service 2e9770
      mpfr_init2 (s, 2);
Packit Service 2e9770
      mpfr_init2 (c, 2);
Packit Service 2e9770
      mpfr_init2 (sh, 2);
Packit Service 2e9770
      mpfr_init2 (ch, 2);
Packit Service 2e9770
      mpfr_init2 (sch, 2);
Packit Service 2e9770
      mpfr_init2 (csh, 2);
Packit Service 2e9770
Packit Service 2e9770
      do {
Packit Service 2e9770
         loop ++;
Packit Service 2e9770
         ok = 1;
Packit Service 2e9770
         prec += (loop <= 2) ? mpc_ceil_log2 (prec) + 5 : prec / 2;
Packit Service 2e9770
Packit Service 2e9770
         mpfr_set_prec (s, prec);
Packit Service 2e9770
         mpfr_set_prec (c, prec);
Packit Service 2e9770
         mpfr_set_prec (sh, prec);
Packit Service 2e9770
         mpfr_set_prec (ch, prec);
Packit Service 2e9770
         mpfr_set_prec (sch, prec);
Packit Service 2e9770
         mpfr_set_prec (csh, prec);
Packit Service 2e9770
Packit Service 2e9770
         mpfr_sin_cos (s, c, mpc_realref(op), MPFR_RNDN);
Packit Service 2e9770
         mpfr_sinh_cosh (sh, ch, mpc_imagref(op), MPFR_RNDN);
Packit Service 2e9770
Packit Service 2e9770
         if (rop_sin != NULL) {
Packit Service 2e9770
            /* real part of sine */
Packit Service 2e9770
            mpfr_mul (sch, s, ch, MPFR_RNDN);
Packit Service 2e9770
            ok = (!mpfr_number_p (sch))
Packit Service 2e9770
                  || mpfr_can_round (sch, prec - 2, MPFR_RNDN, MPFR_RNDZ,
Packit Service 2e9770
                        MPC_PREC_RE (rop_sin)
Packit Service 2e9770
                        + (MPC_RND_RE (rnd_sin) == MPFR_RNDN));
Packit Service 2e9770
Packit Service 2e9770
            if (ok) {
Packit Service 2e9770
               /* imaginary part of sine */
Packit Service 2e9770
               mpfr_mul (csh, c, sh, MPFR_RNDN);
Packit Service 2e9770
               ok = (!mpfr_number_p (csh))
Packit Service 2e9770
                     || mpfr_can_round (csh, prec - 2, MPFR_RNDN, MPFR_RNDZ,
Packit Service 2e9770
                           MPC_PREC_IM (rop_sin)
Packit Service 2e9770
                           + (MPC_RND_IM (rnd_sin) == MPFR_RNDN));
Packit Service 2e9770
            }
Packit Service 2e9770
         }
Packit Service 2e9770
Packit Service 2e9770
         if (rop_cos != NULL && ok) {
Packit Service 2e9770
            /* real part of cosine */
Packit Service 2e9770
            mpfr_mul (c, c, ch, MPFR_RNDN);
Packit Service 2e9770
            ok = (!mpfr_number_p (c))
Packit Service 2e9770
                  || mpfr_can_round (c, prec - 2, MPFR_RNDN, MPFR_RNDZ,
Packit Service 2e9770
                        MPC_PREC_RE (rop_cos)
Packit Service 2e9770
                        + (MPC_RND_RE (rnd_cos) == MPFR_RNDN));
Packit Service 2e9770
Packit Service 2e9770
            if (ok) {
Packit Service 2e9770
               /* imaginary part of cosine */
Packit Service 2e9770
               mpfr_mul (s, s, sh, MPFR_RNDN);
Packit Service 2e9770
               mpfr_neg (s, s, MPFR_RNDN);
Packit Service 2e9770
               ok = (!mpfr_number_p (s))
Packit Service 2e9770
                     || mpfr_can_round (s, prec - 2, MPFR_RNDN, MPFR_RNDZ,
Packit Service 2e9770
                           MPC_PREC_IM (rop_cos)
Packit Service 2e9770
                           + (MPC_RND_IM (rnd_cos) == MPFR_RNDN));
Packit Service 2e9770
            }
Packit Service 2e9770
         }
Packit Service 2e9770
      } while (ok == 0);
Packit Service 2e9770
Packit Service 2e9770
      if (rop_sin != NULL) {
Packit Service 2e9770
         inex_re = mpfr_set (mpc_realref (rop_sin), sch, MPC_RND_RE (rnd_sin));
Packit Service 2e9770
         if (mpfr_inf_p (sch))
Packit Service 2e9770
           inex_re = mpc_fix_inf (mpc_realref (rop_sin), MPC_RND_RE (rnd_sin));
Packit Service 2e9770
         inex_im = mpfr_set (mpc_imagref (rop_sin), csh, MPC_RND_IM (rnd_sin));
Packit Service 2e9770
         if (mpfr_inf_p (csh))
Packit Service 2e9770
           inex_im = mpc_fix_inf (mpc_imagref (rop_sin), MPC_RND_IM (rnd_sin));
Packit Service 2e9770
         inex_sin = MPC_INEX (inex_re, inex_im);
Packit Service 2e9770
      }
Packit Service 2e9770
      else
Packit Service 2e9770
         inex_sin = MPC_INEX (0,0); /* return exact if not computed */
Packit Service 2e9770
Packit Service 2e9770
      if (rop_cos != NULL) {
Packit Service 2e9770
         inex_re = mpfr_set (mpc_realref (rop_cos), c, MPC_RND_RE (rnd_cos));
Packit Service 2e9770
         if (mpfr_inf_p (c))
Packit Service 2e9770
           inex_re = mpc_fix_inf (mpc_realref (rop_cos), MPC_RND_RE (rnd_cos));
Packit Service 2e9770
         inex_im = mpfr_set (mpc_imagref (rop_cos), s, MPC_RND_IM (rnd_cos));
Packit Service 2e9770
         if (mpfr_inf_p (s))
Packit Service 2e9770
           inex_im = mpc_fix_inf (mpc_imagref (rop_cos), MPC_RND_IM (rnd_cos));
Packit Service 2e9770
         inex_cos = MPC_INEX (inex_re, inex_im);
Packit Service 2e9770
      }
Packit Service 2e9770
      else
Packit Service 2e9770
         inex_cos = MPC_INEX (0,0); /* return exact if not computed */
Packit Service 2e9770
Packit Service 2e9770
      mpfr_clear (s);
Packit Service 2e9770
      mpfr_clear (c);
Packit Service 2e9770
      mpfr_clear (sh);
Packit Service 2e9770
      mpfr_clear (ch);
Packit Service 2e9770
      mpfr_clear (sch);
Packit Service 2e9770
      mpfr_clear (csh);
Packit Service 2e9770
Packit Service 2e9770
      return (MPC_INEX12 (inex_sin, inex_cos));
Packit Service 2e9770
   }
Packit Service 2e9770
}