static void copysign_variant (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd_mode, int k) { mpfr_clear_flags (); switch (k) { case 0: mpfr_copysign (z, x, y, MPFR_RNDN); return; case 1: (mpfr_copysign) (z, x, y, MPFR_RNDN); return; case 2: mpfr_setsign (z, x, mpfr_signbit (y), MPFR_RNDN); return; case 3: mpfr_setsign (z, x, (mpfr_signbit) (y), MPFR_RNDN); return; case 4: (mpfr_setsign) (z, x, mpfr_signbit (y), MPFR_RNDN); return; case 5: (mpfr_setsign) (z, x, (mpfr_signbit) (y), MPFR_RNDN); return; } }
static int mpc_div_real (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd) /* Assumes z finite and w finite and non-zero, with imaginary part of w a signed zero. */ { int inex_re, inex_im; /* save signs of operands in case there are overlaps */ int zrs = MPFR_SIGNBIT (mpc_realref (z)); int zis = MPFR_SIGNBIT (mpc_imagref (z)); int wrs = MPFR_SIGNBIT (mpc_realref (w)); int wis = MPFR_SIGNBIT (mpc_imagref (w)); /* warning: rop may overlap with z,w so treat the imaginary part first */ inex_im = mpfr_div (mpc_imagref(rop), mpc_imagref(z), mpc_realref(w), MPC_RND_IM(rnd)); inex_re = mpfr_div (mpc_realref(rop), mpc_realref(z), mpc_realref(w), MPC_RND_RE(rnd)); /* correct signs of zeroes if necessary, which does not affect the inexact flags */ if (mpfr_zero_p (mpc_realref (rop))) mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis), MPFR_RNDN); /* exact */ if (mpfr_zero_p (mpc_imagref (rop))) mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis), MPFR_RNDN); return MPC_INEX(inex_re, inex_im); }
void r_flipsign(real y, real x) { int new_sign; new_sign = (mpfr_signbit(x) == 0); mpfr_setsign(y, x, new_sign, MPFR_RNDN); }
SeedValue seed_mpfr_setsign (SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue args[], SeedException *exception) { mpfr_ptr rop, op; gint ret; gint s; mpfr_rnd_t rnd; CHECK_ARG_COUNT("mpfr.signbit", 3); rop = seed_object_get_private(this_object); s = seed_value_to_int(ctx, args[1], exception); rnd = seed_value_to_mpfr_rnd_t(ctx, args[2], exception); if ( seed_value_is_object_of_class(ctx, args[0], mpfr_class) ) { op = seed_object_get_private(args[0]); } else { TYPE_EXCEPTION("mpfr.setsign", "mpfr_t"); } ret = mpfr_setsign(rop, op, s, rnd); return seed_value_from_int(ctx, ret, exception); }
static int mpc_div_imag (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd) /* Assumes z finite and w finite and non-zero, with real part of w a signed zero. */ { int inex_re, inex_im; int overlap = (rop == z) || (rop == w); int imag_z = mpfr_zero_p (mpc_realref (z)); mpfr_t wloc; mpc_t tmprop; mpc_ptr dest = (overlap) ? tmprop : rop; /* save signs of operands in case there are overlaps */ int zrs = MPFR_SIGNBIT (mpc_realref (z)); int zis = MPFR_SIGNBIT (mpc_imagref (z)); int wrs = MPFR_SIGNBIT (mpc_realref (w)); int wis = MPFR_SIGNBIT (mpc_imagref (w)); if (overlap) mpc_init3 (tmprop, MPC_PREC_RE (rop), MPC_PREC_IM (rop)); wloc[0] = mpc_imagref(w)[0]; /* copies mpfr struct IM(w) into wloc */ inex_re = mpfr_div (mpc_realref(dest), mpc_imagref(z), wloc, MPC_RND_RE(rnd)); mpfr_neg (wloc, wloc, MPFR_RNDN); /* changes the sign only in wloc, not in w; no need to correct later */ inex_im = mpfr_div (mpc_imagref(dest), mpc_realref(z), wloc, MPC_RND_IM(rnd)); if (overlap) { /* Note: we could use mpc_swap here, but this might cause problems if rop and tmprop have been allocated using different methods, since it will swap the significands of rop and tmprop. See http://lists.gforge.inria.fr/pipermail/mpc-discuss/2009-August/000504.html */ mpc_set (rop, tmprop, MPC_RNDNN); /* exact */ mpc_clear (tmprop); } /* correct signs of zeroes if necessary, which does not affect the inexact flags */ if (mpfr_zero_p (mpc_realref (rop))) mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis), MPFR_RNDN); /* exact */ if (imag_z) mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis), MPFR_RNDN); return MPC_INEX(inex_re, inex_im); }
int mpfi_init_set_d (mpfi_ptr a, const double b) { int inexact_left, inexact_right, inexact = 0; inexact_left = mpfr_init_set_d (&(a->left), b, MPFI_RNDD); inexact_right = mpfr_init_set_d (&(a->right), b, MPFI_RNDU); if ( MPFI_NAN_P (a) ) MPFR_RET_NAN; if (b == 0.0) { /* fix signed zero so as to return [+0, -0] */ mpfr_setsign (&(a->left), &(a->left), 0, MPFI_RNDU); mpfr_setsign (&(a->right), &(a->right), 1, MPFI_RNDD); } if (inexact_left) inexact += 1; if (inexact_right) inexact += 2; return inexact; }
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; }
static PyObject * GMPy_Real_DivMod_1(PyObject *x, PyObject *y, CTXT_Object *context) { MPFR_Object *tempx = NULL, *tempy = NULL, *quo = NULL, *rem = NULL; PyObject *result = NULL; CHECK_CONTEXT(context); if (!(result = PyTuple_New(2)) || !(rem = GMPy_MPFR_New(0, context)) || !(quo = GMPy_MPFR_New(0, context))) { /* LCOV_EXCL_START */ goto error; /* LCOV_EXCL_STOP */ } if (IS_REAL(x) && IS_REAL(y)) { if (!(tempx = GMPy_MPFR_From_Real(x, 1, context)) || !(tempy = GMPy_MPFR_From_Real(y, 1, context))) { /* LCOV_EXCL_START */ goto error; /* LCOV_EXCL_STOP */ } if (mpfr_zero_p(tempy->f)) { context->ctx.divzero = 1; if (context->ctx.traps & TRAP_DIVZERO) { GMPY_DIVZERO("divmod() division by zero"); goto error; } } if (mpfr_nan_p(tempx->f) || mpfr_nan_p(tempy->f) || mpfr_inf_p(tempx->f)) { context->ctx.invalid = 1; if (context->ctx.traps & TRAP_INVALID) { GMPY_INVALID("divmod() invalid operation"); goto error; } else { mpfr_set_nan(quo->f); mpfr_set_nan(rem->f); } } else if (mpfr_inf_p(tempy->f)) { context->ctx.invalid = 1; if (context->ctx.traps & TRAP_INVALID) { GMPY_INVALID("divmod() invalid operation"); goto error; } if (mpfr_zero_p(tempx->f)) { mpfr_set_zero(quo->f, mpfr_sgn(tempy->f)); mpfr_set_zero(rem->f, mpfr_sgn(tempy->f)); } else if ((mpfr_signbit(tempx->f)) != (mpfr_signbit(tempy->f))) { mpfr_set_si(quo->f, -1, MPFR_RNDN); mpfr_set_inf(rem->f, mpfr_sgn(tempy->f)); } else { mpfr_set_si(quo->f, 0, MPFR_RNDN); rem->rc = mpfr_set(rem->f, tempx->f, MPFR_RNDN); } } else { MPFR_Object *temp; if (!(temp = GMPy_MPFR_New(0, context))) { /* LCOV_EXCL_START */ goto error; /* LCOV_EXCL_STOP */ } mpfr_fmod(rem->f, tempx->f, tempy->f, MPFR_RNDN); mpfr_sub(temp->f, tempx->f, rem->f, MPFR_RNDN); mpfr_div(quo->f, temp->f, tempy->f, MPFR_RNDN); if (!mpfr_zero_p(rem->f)) { if ((mpfr_sgn(tempy->f) < 0) != (mpfr_sgn(rem->f) < 0)) { mpfr_add(rem->f, rem->f, tempy->f, MPFR_RNDN); mpfr_sub_ui(quo->f, quo->f, 1, MPFR_RNDN); } } else { mpfr_copysign(rem->f, rem->f, tempy->f, MPFR_RNDN); } if (!mpfr_zero_p(quo->f)) { mpfr_round(quo->f, quo->f); } else { mpfr_setsign(quo->f, quo->f, mpfr_sgn(tempx->f) * mpfr_sgn(tempy->f) - 1, MPFR_RNDN); } Py_DECREF((PyObject*)temp); } GMPY_MPFR_CHECK_RANGE(quo, context); GMPY_MPFR_CHECK_RANGE(rem, context); GMPY_MPFR_SUBNORMALIZE(quo, context); GMPY_MPFR_SUBNORMALIZE(rem, context); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); PyTuple_SET_ITEM(result, 0, (PyObject*)quo); PyTuple_SET_ITEM(result, 1, (PyObject*)rem); return (PyObject*)result; } /* LCOV_EXCL_START */ SYSTEM_ERROR("Internal error in GMPy_Real_DivMod_1()."); error: Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)tempy); Py_XDECREF((PyObject*)rem); Py_XDECREF((PyObject*)quo); Py_XDECREF(result); return NULL; /* LCOV_EXCL_STOP */ }
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 */ }
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); }