int mpfr_exp (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_exp_t expx; mpfr_prec_t precy; int inexact; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode), ("y[%#R]=%R inexact=%d", y, y, inexact)); if (MPFR_UNLIKELY( MPFR_IS_SINGULAR(x) )) { if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); MPFR_RET_NAN; } else if (MPFR_IS_INF(x)) { if (MPFR_IS_POS(x)) MPFR_SET_INF(y); else MPFR_SET_ZERO(y); MPFR_SET_POS(y); MPFR_RET(0); } else { MPFR_ASSERTD(MPFR_IS_ZERO(x)); return mpfr_set_ui (y, 1, rnd_mode); } } /* First, let's detect most overflow and underflow cases. */ { mpfr_t e, bound; /* We must extended the exponent range and save the flags now. */ MPFR_SAVE_EXPO_MARK (expo); mpfr_init2 (e, sizeof (mpfr_exp_t) * CHAR_BIT); mpfr_init2 (bound, 32); inexact = mpfr_set_exp_t (e, expo.saved_emax, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); mpfr_const_log2 (bound, expo.saved_emax < 0 ? MPFR_RNDD : MPFR_RNDU); mpfr_mul (bound, bound, e, MPFR_RNDU); if (MPFR_UNLIKELY (mpfr_cmp (x, bound) >= 0)) { /* x > log(2^emax), thus exp(x) > 2^emax */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_overflow (y, rnd_mode, 1); } inexact = mpfr_set_exp_t (e, expo.saved_emin, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); inexact = mpfr_sub_ui (e, e, 2, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); mpfr_const_log2 (bound, expo.saved_emin < 0 ? MPFR_RNDU : MPFR_RNDD); mpfr_mul (bound, bound, e, MPFR_RNDD); if (MPFR_UNLIKELY (mpfr_cmp (x, bound) <= 0)) { /* x < log(2^(emin - 2)), thus exp(x) < 2^(emin - 2) */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_underflow (y, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, 1); } /* Other overflow/underflow cases must be detected by the generic routines. */ mpfr_clears (e, bound, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); } expx = MPFR_GET_EXP (x); precy = MPFR_PREC (y); /* if x < 2^(-precy), then exp(x) i.e. gives 1 +/- 1 ulp(1) */ if (MPFR_UNLIKELY (expx < 0 && (mpfr_uexp_t) (-expx) > precy)) { mpfr_exp_t emin = __gmpfr_emin; mpfr_exp_t emax = __gmpfr_emax; int signx = MPFR_SIGN (x); MPFR_SET_POS (y); if (MPFR_IS_NEG_SIGN (signx) && (rnd_mode == MPFR_RNDD || rnd_mode == MPFR_RNDZ)) { __gmpfr_emin = 0; __gmpfr_emax = 0; mpfr_setmax (y, 0); /* y = 1 - epsilon */ inexact = -1; } else { __gmpfr_emin = 1; __gmpfr_emax = 1; mpfr_setmin (y, 1); /* y = 1 */ if (MPFR_IS_POS_SIGN (signx) && (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA)) { mp_size_t yn; int sh; yn = 1 + (MPFR_PREC(y) - 1) / GMP_NUMB_BITS; sh = (mpfr_prec_t) yn * GMP_NUMB_BITS - MPFR_PREC(y); MPFR_MANT(y)[0] += MPFR_LIMB_ONE << sh; inexact = 1; } else inexact = -MPFR_FROM_SIGN_TO_INT(signx); } __gmpfr_emin = emin; __gmpfr_emax = emax; } else /* General case */ { if (MPFR_UNLIKELY (precy >= MPFR_EXP_THRESHOLD)) /* mpfr_exp_3 saves the exponent range and flags itself, otherwise the flag changes in mpfr_exp_3 are lost */ inexact = mpfr_exp_3 (y, x, rnd_mode); /* O(M(n) log(n)^2) */ else { MPFR_SAVE_EXPO_MARK (expo); inexact = mpfr_exp_2 (y, x, rnd_mode); /* O(n^(1/3) M(n)) */ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags); MPFR_SAVE_EXPO_FREE (expo); } } return mpfr_check_range (y, inexact, rnd_mode); }
static int mpfr_mul3 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { /* Old implementation */ int sign_product, cc, inexact; mpfr_exp_t ax; mp_limb_t *tmp; mp_limb_t b1; mpfr_prec_t bq, cq; mp_size_t bn, cn, tn, k; MPFR_TMP_DECL(marker); /* deal with special cases */ if (MPFR_ARE_SINGULAR(b,c)) { if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) { MPFR_SET_NAN(a); MPFR_RET_NAN; } sign_product = MPFR_MULT_SIGN( MPFR_SIGN(b) , MPFR_SIGN(c) ); if (MPFR_IS_INF(b)) { if (MPFR_IS_INF(c) || MPFR_NOTZERO(c)) { MPFR_SET_SIGN(a,sign_product); MPFR_SET_INF(a); MPFR_RET(0); /* exact */ } else { MPFR_SET_NAN(a); MPFR_RET_NAN; } } else if (MPFR_IS_INF(c)) { if (MPFR_NOTZERO(b)) { MPFR_SET_SIGN(a, sign_product); MPFR_SET_INF(a); MPFR_RET(0); /* exact */ } else { MPFR_SET_NAN(a); MPFR_RET_NAN; } } else { MPFR_ASSERTD(MPFR_IS_ZERO(b) || MPFR_IS_ZERO(c)); MPFR_SET_SIGN(a, sign_product); MPFR_SET_ZERO(a); MPFR_RET(0); /* 0 * 0 is exact */ } } sign_product = MPFR_MULT_SIGN( MPFR_SIGN(b) , MPFR_SIGN(c) ); ax = MPFR_GET_EXP (b) + MPFR_GET_EXP (c); bq = MPFR_PREC(b); cq = MPFR_PREC(c); MPFR_ASSERTD(bq+cq > bq); /* PREC_MAX is /2 so no integer overflow */ bn = (bq+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; /* number of limbs of b */ cn = (cq+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; /* number of limbs of c */ k = bn + cn; /* effective nb of limbs used by b*c (= tn or tn+1) below */ tn = (bq + cq + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; /* <= k, thus no int overflow */ MPFR_ASSERTD(tn <= k); /* Check for no size_t overflow*/ MPFR_ASSERTD((size_t) k <= ((size_t) -1) / BYTES_PER_MP_LIMB); MPFR_TMP_MARK(marker); tmp = (mp_limb_t *) MPFR_TMP_ALLOC((size_t) k * BYTES_PER_MP_LIMB); /* multiplies two mantissa in temporary allocated space */ b1 = (MPFR_LIKELY(bn >= cn)) ? mpn_mul (tmp, MPFR_MANT(b), bn, MPFR_MANT(c), cn) : mpn_mul (tmp, MPFR_MANT(c), cn, MPFR_MANT(b), bn); /* now tmp[0]..tmp[k-1] contains the product of both mantissa, with tmp[k-1]>=2^(GMP_NUMB_BITS-2) */ b1 >>= GMP_NUMB_BITS - 1; /* msb from the product */ /* if the mantissas of b and c are uniformly distributed in ]1/2, 1], then their product is in ]1/4, 1/2] with probability 2*ln(2)-1 ~ 0.386 and in [1/2, 1] with probability 2-2*ln(2) ~ 0.614 */ tmp += k - tn; if (MPFR_UNLIKELY(b1 == 0)) mpn_lshift (tmp, tmp, tn, 1); /* tn <= k, so no stack corruption */ cc = mpfr_round_raw (MPFR_MANT (a), tmp, bq + cq, MPFR_IS_NEG_SIGN(sign_product), MPFR_PREC (a), rnd_mode, &inexact); /* cc = 1 ==> result is a power of two */ if (MPFR_UNLIKELY(cc)) MPFR_MANT(a)[MPFR_LIMB_SIZE(a)-1] = MPFR_LIMB_HIGHBIT; MPFR_TMP_FREE(marker); { mpfr_exp_t ax2 = ax + (mpfr_exp_t) (b1 - 1 + cc); if (MPFR_UNLIKELY( ax2 > __gmpfr_emax)) return mpfr_overflow (a, rnd_mode, sign_product); if (MPFR_UNLIKELY( ax2 < __gmpfr_emin)) { /* In the rounding to the nearest mode, if the exponent of the exact result (i.e. before rounding, i.e. without taking cc into account) is < __gmpfr_emin - 1 or the exact result is a power of 2 (i.e. if both arguments are powers of 2), then round to zero. */ if (rnd_mode == MPFR_RNDN && (ax + (mpfr_exp_t) b1 < __gmpfr_emin || (mpfr_powerof2_raw (b) && mpfr_powerof2_raw (c)))) rnd_mode = MPFR_RNDZ; return mpfr_underflow (a, rnd_mode, sign_product); } MPFR_SET_EXP (a, ax2); MPFR_SET_SIGN(a, sign_product); } MPFR_RET (inexact); }
int mpfr_tanh (mpfr_ptr y, mpfr_srcptr xt , mpfr_rnd_t rnd_mode) { /****** Declaration ******/ mpfr_t x; int inexact; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (xt), mpfr_log_prec, xt, rnd_mode), ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y, inexact)); /* Special value checking */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (xt))) { if (MPFR_IS_NAN (xt)) { MPFR_SET_NAN (y); MPFR_RET_NAN; } else if (MPFR_IS_INF (xt)) { /* tanh(inf) = 1 && tanh(-inf) = -1 */ return mpfr_set_si (y, MPFR_INT_SIGN (xt), rnd_mode); } else /* tanh (0) = 0 and xt is zero */ { MPFR_ASSERTD (MPFR_IS_ZERO(xt)); MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, xt); MPFR_RET (0); } } /* tanh(x) = x - x^3/3 + ... so the error is < 2^(3*EXP(x)-1) */ MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, xt, -2 * MPFR_GET_EXP (xt), 1, 0, rnd_mode, {}); MPFR_TMP_INIT_ABS (x, xt); MPFR_SAVE_EXPO_MARK (expo); /* General case */ { /* Declaration of the intermediary variable */ mpfr_t t, te; mpfr_exp_t d; /* Declaration of the size variable */ mpfr_prec_t Ny = MPFR_PREC(y); /* target precision */ mpfr_prec_t Nt; /* working precision */ long int err; /* error */ int sign = MPFR_SIGN (xt); MPFR_ZIV_DECL (loop); MPFR_GROUP_DECL (group); /* First check for BIG overflow of exp(2*x): For x > 0, exp(2*x) > 2^(2*x) If 2 ^(2*x) > 2^emax or x>emax/2, there is an overflow */ if (MPFR_UNLIKELY (mpfr_cmp_si (x, __gmpfr_emax/2) >= 0)) { /* initialise of intermediary variables since 'set_one' label assumes the variables have been initialize */ MPFR_GROUP_INIT_2 (group, MPFR_PREC_MIN, t, te); goto set_one; } /* Compute the precision of intermediary variable */ /* The optimal number of bits: see algorithms.tex */ Nt = Ny + MPFR_INT_CEIL_LOG2 (Ny) + 4; /* if x is small, there will be a cancellation in exp(2x)-1 */ if (MPFR_GET_EXP (x) < 0) Nt += -MPFR_GET_EXP (x); /* initialise of intermediary variable */ MPFR_GROUP_INIT_2 (group, Nt, t, te); MPFR_ZIV_INIT (loop, Nt); for (;;) { /* tanh = (exp(2x)-1)/(exp(2x)+1) */ mpfr_mul_2ui (te, x, 1, MPFR_RNDN); /* 2x */ /* since x > 0, we can only have an overflow */ mpfr_exp (te, te, MPFR_RNDN); /* exp(2x) */ if (MPFR_UNLIKELY (MPFR_IS_INF (te))) { set_one: inexact = MPFR_FROM_SIGN_TO_INT (sign); mpfr_set4 (y, __gmpfr_one, MPFR_RNDN, sign); if (MPFR_IS_LIKE_RNDZ (rnd_mode, MPFR_IS_NEG_SIGN (sign))) { inexact = -inexact; mpfr_nexttozero (y); } break; } d = MPFR_GET_EXP (te); /* For Error calculation */ mpfr_add_ui (t, te, 1, MPFR_RNDD); /* exp(2x) + 1*/ mpfr_sub_ui (te, te, 1, MPFR_RNDU); /* exp(2x) - 1*/ d = d - MPFR_GET_EXP (te); mpfr_div (t, te, t, MPFR_RNDN); /* (exp(2x)-1)/(exp(2x)+1)*/ /* Calculation of the error */ d = MAX(3, d + 1); err = Nt - (d + 1); if (MPFR_LIKELY ((d <= Nt / 2) && MPFR_CAN_ROUND (t, err, Ny, rnd_mode))) { inexact = mpfr_set4 (y, t, rnd_mode, sign); break; } /* if t=1, we still can round since |sinh(x)| < 1 */ if (MPFR_GET_EXP (t) == 1) goto set_one; /* Actualisation of the precision */ MPFR_ZIV_NEXT (loop, Nt); MPFR_GROUP_REPREC_2 (group, Nt, t, te); } MPFR_ZIV_FREE (loop); MPFR_GROUP_CLEAR (group); } MPFR_SAVE_EXPO_FREE (expo); inexact = mpfr_check_range (y, inexact, rnd_mode); return inexact; }
int mpfr_sin (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_t c, xr; mpfr_srcptr xx; mpfr_exp_t expx, err; mpfr_prec_t precy, m; int inexact, sign, reduce; MPFR_ZIV_DECL (loop); MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode), ("y[%#R]=%R inexact=%d", y, y, inexact)); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x) || MPFR_IS_INF (x)) { MPFR_SET_NAN (y); MPFR_RET_NAN; } else /* x is zero */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); } } /* sin(x) = x - x^3/6 + ... so the error is < 2^(3*EXP(x)-2) */ MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -2 * MPFR_GET_EXP (x), 2, 0, rnd_mode, {}); MPFR_SAVE_EXPO_MARK (expo); /* Compute initial precision */ precy = MPFR_PREC (y); if (precy >= MPFR_SINCOS_THRESHOLD) return mpfr_sin_fast (y, x, rnd_mode); m = precy + MPFR_INT_CEIL_LOG2 (precy) + 13; expx = MPFR_GET_EXP (x); mpfr_init (c); mpfr_init (xr); MPFR_ZIV_INIT (loop, m); for (;;) { /* first perform argument reduction modulo 2*Pi (if needed), also helps to determine the sign of sin(x) */ if (expx >= 2) /* If Pi < x < 4, we need to reduce too, to determine the sign of sin(x). For 2 <= |x| < Pi, we could avoid the reduction. */ { reduce = 1; /* As expx + m - 1 will silently be converted into mpfr_prec_t in the mpfr_set_prec call, the assert below may be useful to avoid undefined behavior. */ MPFR_ASSERTN (expx + m - 1 <= MPFR_PREC_MAX); mpfr_set_prec (c, expx + m - 1); mpfr_set_prec (xr, m); mpfr_const_pi (c, MPFR_RNDN); mpfr_mul_2ui (c, c, 1, MPFR_RNDN); mpfr_remainder (xr, x, c, MPFR_RNDN); /* The analysis is similar to that of cos.c: |xr - x - 2kPi| <= 2^(2-m). Thus we can decide the sign of sin(x) if xr is at distance at least 2^(2-m) of both 0 and +/-Pi. */ mpfr_div_2ui (c, c, 1, MPFR_RNDN); /* Since c approximates Pi with an error <= 2^(2-expx-m) <= 2^(-m), it suffices to check that c - |xr| >= 2^(2-m). */ if (MPFR_SIGN (xr) > 0) mpfr_sub (c, c, xr, MPFR_RNDZ); else mpfr_add (c, c, xr, MPFR_RNDZ); if (MPFR_IS_ZERO(xr) || MPFR_EXP(xr) < (mpfr_exp_t) 3 - (mpfr_exp_t) m || MPFR_EXP(c) < (mpfr_exp_t) 3 - (mpfr_exp_t) m) goto ziv_next; /* |xr - x - 2kPi| <= 2^(2-m), thus |sin(xr) - sin(x)| <= 2^(2-m) */ xx = xr; } else /* the input argument is already reduced */ { reduce = 0; xx = x; } sign = MPFR_SIGN(xx); /* now that the argument is reduced, precision m is enough */ mpfr_set_prec (c, m); mpfr_cos (c, xx, MPFR_RNDZ); /* can't be exact */ mpfr_nexttoinf (c); /* now c = cos(x) rounded away */ mpfr_mul (c, c, c, MPFR_RNDU); /* away */ mpfr_ui_sub (c, 1, c, MPFR_RNDZ); mpfr_sqrt (c, c, MPFR_RNDZ); if (MPFR_IS_NEG_SIGN(sign)) MPFR_CHANGE_SIGN(c); /* Warning: c may be 0! */ if (MPFR_UNLIKELY (MPFR_IS_ZERO (c))) { /* Huge cancellation: increase prec a lot! */ m = MAX (m, MPFR_PREC (x)); m = 2 * m; } else { /* the absolute error on c is at most 2^(3-m-EXP(c)), plus 2^(2-m) if there was an argument reduction. Since EXP(c) <= 1, 3-m-EXP(c) >= 2-m, thus the error is at most 2^(3-m-EXP(c)) in case of argument reduction. */ err = 2 * MPFR_GET_EXP (c) + (mpfr_exp_t) m - 3 - (reduce != 0); if (MPFR_CAN_ROUND (c, err, precy, rnd_mode)) break; /* check for huge cancellation (Near 0) */ if (err < (mpfr_exp_t) MPFR_PREC (y)) m += MPFR_PREC (y) - err; /* Check if near 1 */ if (MPFR_GET_EXP (c) == 1) m += m; } ziv_next: /* Else generic increase */ MPFR_ZIV_NEXT (loop, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, c, rnd_mode); /* inexact cannot be 0, since this would mean that c was representable within the target precision, but in that case mpfr_can_round will fail */ mpfr_clear (c); mpfr_clear (xr); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); }