int mpfr_si_sub (mpfr_ptr y, long int u, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { if (u >= 0) return mpfr_ui_sub (y, u, x, rnd_mode); else { int res = -mpfr_add_ui (y, x, -u, MPFR_INVERT_RND (rnd_mode)); MPFR_CHANGE_SIGN (y); return res; } }
int mpfr_mul_si (mpfr_ptr y, mpfr_srcptr x, long int u, mpfr_rnd_t rnd_mode) { int res; if (u >= 0) res = mpfr_mul_ui (y, x, u, rnd_mode); else { res = -mpfr_mul_ui (y, x, -u, MPFR_INVERT_RND (rnd_mode)); MPFR_CHANGE_SIGN (y); } return res; }
int mpfr_set_sj_2exp (mpfr_t x, intmax_t j, intmax_t e, mp_rnd_t rnd) { if (j>=0) return mpfr_set_uj_2exp (x, j, e, rnd); else { int inex; inex = mpfr_set_uj_2exp (x, - (uintmax_t) j, e, MPFR_INVERT_RND (rnd)); MPFR_CHANGE_SIGN (x); return -inex; } }
int mpfr_si_div (mpfr_ptr y, long int u, mpfr_srcptr x,mp_rnd_t rnd_mode) { int res; if (u >= 0) res = mpfr_ui_div (y, u, x, rnd_mode); else { res = -mpfr_ui_div (y, -u, x, MPFR_INVERT_RND(rnd_mode)); MPFR_CHANGE_SIGN (y); } return res; }
static int pi_div_2ui (mpfr_ptr dest, int i, int neg, mpfr_rnd_t rnd_mode) { int inexact; MPFR_SAVE_EXPO_DECL (expo); MPFR_SAVE_EXPO_MARK (expo); if (neg) /* -PI/2^i */ { inexact = - mpfr_const_pi (dest, MPFR_INVERT_RND (rnd_mode)); MPFR_CHANGE_SIGN (dest); } else /* PI/2^i */ { inexact = mpfr_const_pi (dest, rnd_mode); } mpfr_div_2ui (dest, dest, i, rnd_mode); /* exact */ MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (dest, inexact, rnd_mode); }
int mpfr_cbrt (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpz_t m; mpfr_exp_t e, r, sh; mpfr_prec_t n, size_m, tmp; int inexact, negative; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC ( ("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode), ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y, inexact)); /* special values */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x)) { MPFR_SET_NAN (y); MPFR_RET_NAN; } else if (MPFR_IS_INF (x)) { MPFR_SET_INF (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); } /* case 0: cbrt(+/- 0) = +/- 0 */ else /* x is necessarily 0 */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); } } /* General case */ MPFR_SAVE_EXPO_MARK (expo); mpz_init (m); e = mpfr_get_z_2exp (m, x); /* x = m * 2^e */ if ((negative = MPFR_IS_NEG(x))) mpz_neg (m, m); r = e % 3; if (r < 0) r += 3; /* x = (m*2^r) * 2^(e-r) = (m*2^r) * 2^(3*q) */ MPFR_MPZ_SIZEINBASE2 (size_m, m); n = MPFR_PREC (y) + (rnd_mode == MPFR_RNDN); /* we want 3*n-2 <= size_m + 3*sh + r <= 3*n i.e. 3*sh + size_m + r <= 3*n */ sh = (3 * (mpfr_exp_t) n - (mpfr_exp_t) size_m - r) / 3; sh = 3 * sh + r; if (sh >= 0) { mpz_mul_2exp (m, m, sh); e = e - sh; } else if (r > 0) { mpz_mul_2exp (m, m, r); e = e - r; } /* invariant: x = m*2^e, with e divisible by 3 */ /* we reuse the variable m to store the cube root, since it is not needed any more: we just need to know if the root is exact */ inexact = mpz_root (m, m, 3) == 0; MPFR_MPZ_SIZEINBASE2 (tmp, m); sh = tmp - n; if (sh > 0) /* we have to flush to 0 the last sh bits from m */ { inexact = inexact || ((mpfr_exp_t) mpz_scan1 (m, 0) < sh); mpz_fdiv_q_2exp (m, m, sh); e += 3 * sh; } if (inexact) { if (negative) rnd_mode = MPFR_INVERT_RND (rnd_mode); if (rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA || (rnd_mode == MPFR_RNDN && mpz_tstbit (m, 0))) inexact = 1, mpz_add_ui (m, m, 1); else inexact = -1; } /* either inexact is not zero, and the conversion is exact, i.e. inexact is not changed; or inexact=0, and inexact is set only when rnd_mode=MPFR_RNDN and bit (n+1) from m is 1 */ inexact += mpfr_set_z (y, m, MPFR_RNDN); MPFR_SET_EXP (y, MPFR_GET_EXP (y) + e / 3); if (negative) { MPFR_CHANGE_SIGN (y); inexact = -inexact; } mpz_clear (m); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); }
static void special (void) { mpfr_t x, y, z; int r; int i; mpfr_init2 (x, 53); mpfr_init2 (y, 53); mpfr_init2 (z, 53); mpfr_set_str_binary (x, "1.0000100110000001100111100011001110101110100111011101"); mpfr_set_str_binary (y, "1.1001101101110100101100110011011101101000011010111110e-1"); mpfr_atan (z, x, MPFR_RNDN); if (mpfr_cmp (y, z)) { printf ("Error in mpfr_atan for prec=53, rnd=MPFR_RNDN\n"); printf ("x="); mpfr_out_str (stdout, 2, 0, x, MPFR_RNDN); printf ("\nexpected "); mpfr_out_str (stdout, 2, 0, y, MPFR_RNDN); printf ("\ngot "); mpfr_out_str (stdout, 2, 0, z, MPFR_RNDN); printf ("\n"); exit (1); } /* atan(+Inf) = Pi/2 */ for (r = 0; r < MPFR_RND_MAX ; r++) { mpfr_set_inf (x, 1); mpfr_atan (y, x, (mpfr_rnd_t) r); mpfr_const_pi (x, (mpfr_rnd_t) r); mpfr_div_2exp (x, x, 1, (mpfr_rnd_t) r); if (mpfr_cmp (x, y)) { printf ("Error: mpfr_atan(+Inf), rnd=%s\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); exit (1); } } /* atan(-Inf) = - Pi/2 */ for (r = 0; r < MPFR_RND_MAX ; r++) { mpfr_set_inf (x, -1); mpfr_atan (y, x, (mpfr_rnd_t) r); mpfr_const_pi (x, MPFR_INVERT_RND((mpfr_rnd_t) r)); mpfr_neg (x, x, (mpfr_rnd_t) r); mpfr_div_2exp (x, x, 1, (mpfr_rnd_t) r); if (mpfr_cmp (x, y)) { printf ("Error: mpfr_atan(-Inf), rnd=%s\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); exit (1); } } /* atan(NaN) = NaN */ mpfr_set_nan (x); mpfr_atan (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_atan(NaN) <> NaN\n"); exit (1); } /* atan(+/-0) = +/-0 */ mpfr_set_ui (x, 0, MPFR_RNDN); MPFR_SET_NEG (y); mpfr_atan (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || MPFR_IS_NEG (y)) { printf ("Error: mpfr_atan (+0) <> +0\n"); exit (1); } mpfr_atan (x, x, MPFR_RNDN); if (mpfr_cmp_ui (x, 0) || MPFR_IS_NEG (x)) { printf ("Error: mpfr_atan (+0) <> +0 (in place)\n"); exit (1); } mpfr_neg (x, x, MPFR_RNDN); MPFR_SET_POS (y); mpfr_atan (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || MPFR_IS_POS (y)) { printf ("Error: mpfr_atan (-0) <> -0\n"); exit (1); } mpfr_atan (x, x, MPFR_RNDN); if (mpfr_cmp_ui (x, 0) || MPFR_IS_POS (x)) { printf ("Error: mpfr_atan (-0) <> -0 (in place)\n"); exit (1); } mpfr_set_prec (x, 32); mpfr_set_prec (y, 32); /* test one random positive argument */ mpfr_set_str_binary (x, "0.10000100001100101001001001011001"); mpfr_atan (x, x, MPFR_RNDN); mpfr_set_str_binary (y, "0.1111010000001111001111000000011E-1"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_atan (1)\n"); exit (1); } /* test one random negative argument */ mpfr_set_str_binary (x, "-0.1100001110110000010101011001011"); mpfr_atan (x, x, MPFR_RNDN); mpfr_set_str_binary (y, "-0.101001110001010010110001110001"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_atan (2)\n"); mpfr_print_binary (x); printf ("\n"); mpfr_print_binary (y); printf ("\n"); exit (1); } mpfr_set_prec (x, 3); mpfr_set_prec (y, 192); mpfr_set_prec (z, 192); mpfr_set_str_binary (x, "-0.100e1"); mpfr_atan (z, x, MPFR_RNDD); mpfr_set_str_binary (y, "-0.110010010000111111011010101000100010000101101000110000100011010011000100110001100110001010001011100000001101110000011100110100010010100100000010010011100000100010001010011001111100110001110101"); if (mpfr_cmp (z, y)) { printf ("Error in mpfr_atan (3)\n"); printf ("Expected "); mpfr_print_binary (y); printf ("\n"); printf ("Got "); mpfr_print_binary (z); printf ("\n"); exit (1); } /* Test regression */ mpfr_set_prec (x, 51); mpfr_set_prec (y, 51); mpfr_set_str_binary (x, "0.101100100000101111111010001111111000001000000000000E-11"); i = mpfr_atan (y, x, MPFR_RNDN); if (mpfr_cmp_str (y, "1.01100100000101111111001110011001010110100100000000e-12", 2, MPFR_RNDN) || i >= 0) { printf ("Wrong Regression test (%d)\n", i); mpfr_dump (y); exit (1); } mpfr_set_si (x, -1, MPFR_RNDN); mpfr_atan (x, x, MPFR_RNDN); MPFR_ASSERTN (MPFR_IS_NEG (x)); /* Test regression */ mpfr_set_prec (x, 48); mpfr_set_prec (y, 48); mpfr_set_str_binary (x, "1.11001110010000011111100000010000000000000000000e-19"); mpfr_atan (y, x, MPFR_RNDD); if (mpfr_cmp_str (y, "0.111001110010000011111100000001111111110000010011E-18", 2, MPFR_RNDN)) { printf ("Error in mpfr_atan (4)\n"); printf ("Input 1.11001110010000011111100000010000000000000000000e-19 [prec=48]\n"); printf ("Expected 0.111001110010000011111100000001111111110000010011E-18\n"); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); }
int mpfr_sub (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { MPFR_LOG_FUNC (("b[%#R]=%R c[%#R]=%R rnd=%d", b, b, c, c, rnd_mode), ("a[%#R]=%R", a, a)); if (MPFR_ARE_SINGULAR (b,c)) { if (MPFR_IS_NAN (b) || MPFR_IS_NAN (c)) { MPFR_SET_NAN (a); MPFR_RET_NAN; } else if (MPFR_IS_INF (b)) { if (!MPFR_IS_INF (c) || MPFR_SIGN (b) != MPFR_SIGN(c)) { MPFR_SET_INF (a); MPFR_SET_SAME_SIGN (a, b); MPFR_RET (0); /* exact */ } else { MPFR_SET_NAN (a); /* Inf - Inf */ MPFR_RET_NAN; } } else if (MPFR_IS_INF (c)) { MPFR_SET_INF (a); MPFR_SET_OPPOSITE_SIGN (a, c); MPFR_RET (0); /* exact */ } else if (MPFR_IS_ZERO (b)) { if (MPFR_IS_ZERO (c)) { int sign = rnd_mode != MPFR_RNDD ? ((MPFR_IS_NEG(b) && MPFR_IS_POS(c)) ? -1 : 1) : ((MPFR_IS_POS(b) && MPFR_IS_NEG(c)) ? 1 : -1); MPFR_SET_SIGN (a, sign); MPFR_SET_ZERO (a); MPFR_RET(0); /* 0 - 0 is exact */ } else return mpfr_neg (a, c, rnd_mode); } else { MPFR_ASSERTD (MPFR_IS_ZERO (c)); return mpfr_set (a, b, rnd_mode); } } MPFR_ASSERTD (MPFR_IS_PURE_FP (b) && MPFR_IS_PURE_FP (c)); if (MPFR_LIKELY (MPFR_SIGN (b) == MPFR_SIGN (c))) { /* signs are equal, it's a real subtraction */ if (MPFR_LIKELY (MPFR_PREC (a) == MPFR_PREC (b) && MPFR_PREC (b) == MPFR_PREC (c))) return mpfr_sub1sp (a, b, c, rnd_mode); else return mpfr_sub1 (a, b, c, rnd_mode); } else { /* signs differ, it's an addition */ if (MPFR_GET_EXP (b) < MPFR_GET_EXP (c)) { /* exchange rounding modes toward +/- infinity */ int inexact; rnd_mode = MPFR_INVERT_RND (rnd_mode); if (MPFR_LIKELY (MPFR_PREC (a) == MPFR_PREC (b) && MPFR_PREC (b) == MPFR_PREC (c))) inexact = mpfr_add1sp (a, c, b, rnd_mode); else inexact = mpfr_add1 (a, c, b, rnd_mode); MPFR_CHANGE_SIGN (a); return -inexact; } else { if (MPFR_LIKELY (MPFR_PREC (a) == MPFR_PREC (b) && MPFR_PREC (b) == MPFR_PREC (c))) return mpfr_add1sp (a, b, c, rnd_mode); else return mpfr_add1 (a, b, c, rnd_mode); } } }
/* Assumes that the exponent range has already been extended and if y is an integer, then the result is not exact in unbounded exponent range. */ int mpfr_pow_general (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd_mode, int y_is_integer, mpfr_save_expo_t *expo) { mpfr_t t, u, k, absx; int neg_result = 0; int k_non_zero = 0; int check_exact_case = 0; int inexact; /* Declaration of the size variable */ mpfr_prec_t Nz = MPFR_PREC(z); /* target precision */ mpfr_prec_t Nt; /* working precision */ mpfr_exp_t err; /* error */ MPFR_ZIV_DECL (ziv_loop); MPFR_LOG_FUNC (("x[%Pu]=%.*Rg y[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, mpfr_get_prec (y), mpfr_log_prec, y, rnd_mode), ("z[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (z), mpfr_log_prec, z, inexact)); /* We put the absolute value of x in absx, pointing to the significand of x to avoid allocating memory for the significand of absx. */ MPFR_ALIAS(absx, x, /*sign=*/ 1, /*EXP=*/ MPFR_EXP(x)); /* We will compute the absolute value of the result. So, let's invert the rounding mode if the result is negative. */ if (MPFR_IS_NEG (x) && is_odd (y)) { neg_result = 1; rnd_mode = MPFR_INVERT_RND (rnd_mode); } /* compute the precision of intermediary variable */ /* the optimal number of bits : see algorithms.tex */ Nt = Nz + 5 + MPFR_INT_CEIL_LOG2 (Nz); /* initialise of intermediary variable */ mpfr_init2 (t, Nt); MPFR_ZIV_INIT (ziv_loop, Nt); for (;;) { MPFR_BLOCK_DECL (flags1); /* compute exp(y*ln|x|), using MPFR_RNDU to get an upper bound, so that we can detect underflows. */ mpfr_log (t, absx, MPFR_IS_NEG (y) ? MPFR_RNDD : MPFR_RNDU); /* ln|x| */ mpfr_mul (t, y, t, MPFR_RNDU); /* y*ln|x| */ if (k_non_zero) { MPFR_LOG_MSG (("subtract k * ln(2)\n", 0)); mpfr_const_log2 (u, MPFR_RNDD); mpfr_mul (u, u, k, MPFR_RNDD); /* Error on u = k * log(2): < k * 2^(-Nt) < 1. */ mpfr_sub (t, t, u, MPFR_RNDU); MPFR_LOG_MSG (("t = y * ln|x| - k * ln(2)\n", 0)); MPFR_LOG_VAR (t); } /* estimate of the error -- see pow function in algorithms.tex. The error on t is at most 1/2 + 3*2^(EXP(t)+1) ulps, which is <= 2^(EXP(t)+3) for EXP(t) >= -1, and <= 2 ulps for EXP(t) <= -2. Additional error if k_no_zero: treal = t * errk, with 1 - |k| * 2^(-Nt) <= exp(-|k| * 2^(-Nt)) <= errk <= 1, i.e., additional absolute error <= 2^(EXP(k)+EXP(t)-Nt). Total error <= 2^err1 + 2^err2 <= 2^(max(err1,err2)+1). */ err = MPFR_NOTZERO (t) && MPFR_GET_EXP (t) >= -1 ? MPFR_GET_EXP (t) + 3 : 1; if (k_non_zero) { if (MPFR_GET_EXP (k) > err) err = MPFR_GET_EXP (k); err++; } MPFR_BLOCK (flags1, mpfr_exp (t, t, MPFR_RNDN)); /* exp(y*ln|x|)*/ /* We need to test */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (t) || MPFR_UNDERFLOW (flags1))) { mpfr_prec_t Ntmin; MPFR_BLOCK_DECL (flags2); MPFR_ASSERTN (!k_non_zero); MPFR_ASSERTN (!MPFR_IS_NAN (t)); /* Real underflow? */ if (MPFR_IS_ZERO (t)) { /* Underflow. We computed rndn(exp(t)), where t >= y*ln|x|. Therefore rndn(|x|^y) = 0, and we have a real underflow on |x|^y. */ inexact = mpfr_underflow (z, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, MPFR_SIGN_POS); if (expo != NULL) MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW); break; } /* Real overflow? */ if (MPFR_IS_INF (t)) { /* Note: we can probably use a low precision for this test. */ mpfr_log (t, absx, MPFR_IS_NEG (y) ? MPFR_RNDU : MPFR_RNDD); mpfr_mul (t, y, t, MPFR_RNDD); /* y * ln|x| */ MPFR_BLOCK (flags2, mpfr_exp (t, t, MPFR_RNDD)); /* t = lower bound on exp(y * ln|x|) */ if (MPFR_OVERFLOW (flags2)) { /* We have computed a lower bound on |x|^y, and it overflowed. Therefore we have a real overflow on |x|^y. */ inexact = mpfr_overflow (z, rnd_mode, MPFR_SIGN_POS); if (expo != NULL) MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW); break; } } k_non_zero = 1; Ntmin = sizeof(mpfr_exp_t) * CHAR_BIT; if (Ntmin > Nt) { Nt = Ntmin; mpfr_set_prec (t, Nt); } mpfr_init2 (u, Nt); mpfr_init2 (k, Ntmin); mpfr_log2 (k, absx, MPFR_RNDN); mpfr_mul (k, y, k, MPFR_RNDN); mpfr_round (k, k); MPFR_LOG_VAR (k); /* |y| < 2^Ntmin, therefore |k| < 2^Nt. */ continue; } if (MPFR_LIKELY (MPFR_CAN_ROUND (t, Nt - err, Nz, rnd_mode))) { inexact = mpfr_set (z, t, rnd_mode); break; } /* check exact power, except when y is an integer (since the exact cases for y integer have already been filtered out) */ if (check_exact_case == 0 && ! y_is_integer) { if (mpfr_pow_is_exact (z, absx, y, rnd_mode, &inexact)) break; check_exact_case = 1; } /* reactualisation of the precision */ MPFR_ZIV_NEXT (ziv_loop, Nt); mpfr_set_prec (t, Nt); if (k_non_zero) mpfr_set_prec (u, Nt); } MPFR_ZIV_FREE (ziv_loop); if (k_non_zero) { int inex2; long lk; /* The rounded result in an unbounded exponent range is z * 2^k. As * MPFR chooses underflow after rounding, the mpfr_mul_2si below will * correctly detect underflows and overflows. However, in rounding to * nearest, if z * 2^k = 2^(emin - 2), then the double rounding may * affect the result. We need to cope with that before overwriting z. * This can occur only if k < 0 (this test is necessary to avoid a * potential integer overflow). * If inexact >= 0, then the real result is <= 2^(emin - 2), so that * o(2^(emin - 2)) = +0 is correct. If inexact < 0, then the real * result is > 2^(emin - 2) and we need to round to 2^(emin - 1). */ MPFR_ASSERTN (MPFR_EXP_MAX <= LONG_MAX); lk = mpfr_get_si (k, MPFR_RNDN); /* Due to early overflow detection, |k| should not be much larger than * MPFR_EMAX_MAX, and as MPFR_EMAX_MAX <= MPFR_EXP_MAX/2 <= LONG_MAX/2, * an overflow should not be possible in mpfr_get_si (and lk is exact). * And one even has the following assertion. TODO: complete proof. */ MPFR_ASSERTD (lk > LONG_MIN && lk < LONG_MAX); /* Note: even in case of overflow (lk inexact), the code is correct. * Indeed, for the 3 occurrences of lk: * - The test lk < 0 is correct as sign(lk) = sign(k). * - In the test MPFR_GET_EXP (z) == __gmpfr_emin - 1 - lk, * if lk is inexact, then lk = LONG_MIN <= MPFR_EXP_MIN * (the minimum value of the mpfr_exp_t type), and * __gmpfr_emin - 1 - lk >= MPFR_EMIN_MIN - 1 - 2 * MPFR_EMIN_MIN * >= - MPFR_EMIN_MIN - 1 = MPFR_EMAX_MAX - 1. However, from the * choice of k, z has been chosen to be around 1, so that the * result of the test is false, as if lk were exact. * - In the mpfr_mul_2si (z, z, lk, rnd_mode), if lk is inexact, * then |lk| >= LONG_MAX >= MPFR_EXP_MAX, and as z is around 1, * mpfr_mul_2si underflows or overflows in the same way as if * lk were exact. * TODO: give a bound on |t|, then on |EXP(z)|. */ if (rnd_mode == MPFR_RNDN && inexact < 0 && lk < 0 && MPFR_GET_EXP (z) == __gmpfr_emin - 1 - lk && mpfr_powerof2_raw (z)) { /* Rounding to nearest, real result > z * 2^k = 2^(emin - 2), * underflow case: as the minimum precision is > 1, we will * obtain the correct result and exceptions by replacing z by * nextabove(z). */ MPFR_ASSERTN (MPFR_PREC_MIN > 1); mpfr_nextabove (z); } MPFR_CLEAR_FLAGS (); inex2 = mpfr_mul_2si (z, z, lk, rnd_mode); if (inex2) /* underflow or overflow */ { inexact = inex2; if (expo != NULL) MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, __gmpfr_flags); } mpfr_clears (u, k, (mpfr_ptr) 0); } mpfr_clear (t); /* update the sign of the result if x was negative */ if (neg_result) { MPFR_SET_NEG(z); inexact = -inexact; } return inexact; }
int mpfr_asin (mpfr_ptr asin, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_t xp; int compared, inexact; mpfr_prec_t prec; mpfr_exp_t xp_exp; MPFR_SAVE_EXPO_DECL (expo); MPFR_ZIV_DECL (loop); MPFR_LOG_FUNC ( ("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode), ("asin[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (asin), mpfr_log_prec, asin, inexact)); /* Special cases */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x) || MPFR_IS_INF (x)) { MPFR_SET_NAN (asin); MPFR_RET_NAN; } else /* x = 0 */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_ZERO (asin); MPFR_SET_SAME_SIGN (asin, x); MPFR_RET (0); /* exact result */ } } /* asin(x) = x + x^3/6 + ... so the error is < 2^(3*EXP(x)-2) */ MPFR_FAST_COMPUTE_IF_SMALL_INPUT (asin, x, -2 * MPFR_GET_EXP (x), 2, 1, rnd_mode, {}); /* Set x_p=|x| (x is a normal number) */ mpfr_init2 (xp, MPFR_PREC (x)); inexact = mpfr_abs (xp, x, MPFR_RNDN); MPFR_ASSERTD (inexact == 0); compared = mpfr_cmp_ui (xp, 1); MPFR_SAVE_EXPO_MARK (expo); if (MPFR_UNLIKELY (compared >= 0)) { mpfr_clear (xp); if (compared > 0) /* asin(x) = NaN for |x| > 1 */ { MPFR_SAVE_EXPO_FREE (expo); MPFR_SET_NAN (asin); MPFR_RET_NAN; } else /* x = 1 or x = -1 */ { if (MPFR_IS_POS (x)) /* asin(+1) = Pi/2 */ inexact = mpfr_const_pi (asin, rnd_mode); else /* asin(-1) = -Pi/2 */ { inexact = -mpfr_const_pi (asin, MPFR_INVERT_RND(rnd_mode)); MPFR_CHANGE_SIGN (asin); } mpfr_div_2ui (asin, asin, 1, rnd_mode); } } else { /* Compute exponent of 1 - ABS(x) */ mpfr_ui_sub (xp, 1, xp, MPFR_RNDD); MPFR_ASSERTD (MPFR_GET_EXP (xp) <= 0); MPFR_ASSERTD (MPFR_GET_EXP (x) <= 0); xp_exp = 2 - MPFR_GET_EXP (xp); /* Set up initial prec */ prec = MPFR_PREC (asin) + 10 + xp_exp; /* use asin(x) = atan(x/sqrt(1-x^2)) */ MPFR_ZIV_INIT (loop, prec); for (;;) { mpfr_set_prec (xp, prec); mpfr_sqr (xp, x, MPFR_RNDN); mpfr_ui_sub (xp, 1, xp, MPFR_RNDN); mpfr_sqrt (xp, xp, MPFR_RNDN); mpfr_div (xp, x, xp, MPFR_RNDN); mpfr_atan (xp, xp, MPFR_RNDN); if (MPFR_LIKELY (MPFR_CAN_ROUND (xp, prec - xp_exp, MPFR_PREC (asin), rnd_mode))) break; MPFR_ZIV_NEXT (loop, prec); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (asin, xp, rnd_mode); mpfr_clear (xp); } MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (asin, inexact, rnd_mode); }
int mpfr_atan2 (mpfr_ptr dest, mpfr_srcptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_t tmp, pi; int inexact; mpfr_prec_t prec; mpfr_exp_t e; MPFR_SAVE_EXPO_DECL (expo); MPFR_ZIV_DECL (loop); MPFR_LOG_FUNC (("y[%Pu]=%.*Rg x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (y), mpfr_log_prec, y, mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode), ("atan[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (dest), mpfr_log_prec, dest, inexact)); /* Special cases */ if (MPFR_ARE_SINGULAR (x, y)) { /* atan2(0, 0) does not raise the "invalid" floating-point exception, nor does atan2(y, 0) raise the "divide-by-zero" floating-point exception. -- atan2(±0, -0) returns ±pi.313) -- atan2(±0, +0) returns ±0. -- atan2(±0, x) returns ±pi, for x < 0. -- atan2(±0, x) returns ±0, for x > 0. -- atan2(y, ±0) returns -pi/2 for y < 0. -- atan2(y, ±0) returns pi/2 for y > 0. -- atan2(±oo, -oo) returns ±3pi/4. -- atan2(±oo, +oo) returns ±pi/4. -- atan2(±oo, x) returns ±pi/2, for finite x. -- atan2(±y, -oo) returns ±pi, for finite y > 0. -- atan2(±y, +oo) returns ±0, for finite y > 0. */ if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y)) { MPFR_SET_NAN (dest); MPFR_RET_NAN; } if (MPFR_IS_ZERO (y)) { if (MPFR_IS_NEG (x)) /* +/- PI */ { set_pi: if (MPFR_IS_NEG (y)) { inexact = mpfr_const_pi (dest, MPFR_INVERT_RND (rnd_mode)); MPFR_CHANGE_SIGN (dest); return -inexact; } else return mpfr_const_pi (dest, rnd_mode); } else /* +/- 0 */ { set_zero: MPFR_SET_ZERO (dest); MPFR_SET_SAME_SIGN (dest, y); return 0; } } if (MPFR_IS_ZERO (x)) { return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode); } if (MPFR_IS_INF (y)) { if (!MPFR_IS_INF (x)) /* +/- PI/2 */ return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode); else if (MPFR_IS_POS (x)) /* +/- PI/4 */ return pi_div_2ui (dest, 2, MPFR_IS_NEG (y), rnd_mode); else /* +/- 3*PI/4: Ugly since we have to round properly */ { mpfr_t tmp2; MPFR_ZIV_DECL (loop2); mpfr_prec_t prec2 = MPFR_PREC (dest) + 10; MPFR_SAVE_EXPO_MARK (expo); mpfr_init2 (tmp2, prec2); MPFR_ZIV_INIT (loop2, prec2); for (;;) { mpfr_const_pi (tmp2, MPFR_RNDN); mpfr_mul_ui (tmp2, tmp2, 3, MPFR_RNDN); /* Error <= 2 */ mpfr_div_2ui (tmp2, tmp2, 2, MPFR_RNDN); if (mpfr_round_p (MPFR_MANT (tmp2), MPFR_LIMB_SIZE (tmp2), MPFR_PREC (tmp2) - 2, MPFR_PREC (dest) + (rnd_mode == MPFR_RNDN))) break; MPFR_ZIV_NEXT (loop2, prec2); mpfr_set_prec (tmp2, prec2); } MPFR_ZIV_FREE (loop2); if (MPFR_IS_NEG (y)) MPFR_CHANGE_SIGN (tmp2); inexact = mpfr_set (dest, tmp2, rnd_mode); mpfr_clear (tmp2); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (dest, inexact, rnd_mode); } } MPFR_ASSERTD (MPFR_IS_INF (x)); if (MPFR_IS_NEG (x)) goto set_pi; else goto set_zero; } /* When x is a power of two, we call directly atan(y/x) since y/x is exact. */ if (MPFR_UNLIKELY (MPFR_IS_POWER_OF_2 (x))) { int r; mpfr_t yoverx; unsigned int saved_flags = __gmpfr_flags; mpfr_init2 (yoverx, MPFR_PREC (y)); if (MPFR_LIKELY (mpfr_div_2si (yoverx, y, MPFR_GET_EXP (x) - 1, MPFR_RNDN) == 0)) { /* Here the flags have not changed due to mpfr_div_2si. */ r = mpfr_atan (dest, yoverx, rnd_mode); mpfr_clear (yoverx); return r; } else { /* Division is inexact because of a small exponent range */ mpfr_clear (yoverx); __gmpfr_flags = saved_flags; } } MPFR_SAVE_EXPO_MARK (expo); /* Set up initial prec */ prec = MPFR_PREC (dest) + 3 + MPFR_INT_CEIL_LOG2 (MPFR_PREC (dest)); mpfr_init2 (tmp, prec); MPFR_ZIV_INIT (loop, prec); if (MPFR_IS_POS (x)) /* use atan2(y,x) = atan(y/x) */ for (;;) { int div_inex; MPFR_BLOCK_DECL (flags); MPFR_BLOCK (flags, div_inex = mpfr_div (tmp, y, x, MPFR_RNDN)); if (div_inex == 0) { /* Result is exact. */ inexact = mpfr_atan (dest, tmp, rnd_mode); goto end; } /* Error <= ulp (tmp) except in case of underflow or overflow. */ /* If the division underflowed, since |atan(z)/z| < 1, we have an underflow. */ if (MPFR_UNDERFLOW (flags)) { int sign; /* In the case MPFR_RNDN with 2^(emin-2) < |y/x| < 2^(emin-1): The smallest significand value S > 1 of |y/x| is: * 1 / (1 - 2^(-px)) if py <= px, * (1 - 2^(-px) + 2^(-py)) / (1 - 2^(-px)) if py >= px. Therefore S - 1 > 2^(-pz), where pz = max(px,py). We have: atan(|y/x|) > atan(z), where z = 2^(emin-2) * (1 + 2^(-pz)). > z - z^3 / 3. > 2^(emin-2) * (1 + 2^(-pz) - 2^(2 emin - 5)) Assuming pz <= -2 emin + 5, we can round away from zero (this is what mpfr_underflow always does on MPFR_RNDN). In the case MPFR_RNDN with |y/x| <= 2^(emin-2), we round toward zero, as |atan(z)/z| < 1. */ MPFR_ASSERTN (MPFR_PREC_MAX <= 2 * (mpfr_uexp_t) - MPFR_EMIN_MIN + 5); if (rnd_mode == MPFR_RNDN && MPFR_IS_ZERO (tmp)) rnd_mode = MPFR_RNDZ; sign = MPFR_SIGN (tmp); mpfr_clear (tmp); MPFR_SAVE_EXPO_FREE (expo); return mpfr_underflow (dest, rnd_mode, sign); } mpfr_atan (tmp, tmp, MPFR_RNDN); /* Error <= 2*ulp (tmp) since abs(D(arctan)) <= 1 */ /* TODO: check that the error bound is correct in case of overflow. */ /* FIXME: Error <= ulp(tmp) ? */ if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - 2, MPFR_PREC (dest), rnd_mode))) break; MPFR_ZIV_NEXT (loop, prec); mpfr_set_prec (tmp, prec); } else /* x < 0 */ /* Use sign(y)*(PI - atan (|y/x|)) */ { mpfr_init2 (pi, prec); for (;;) { mpfr_div (tmp, y, x, MPFR_RNDN); /* Error <= ulp (tmp) */ /* If tmp is 0, we have |y/x| <= 2^(-emin-2), thus atan|y/x| < 2^(-emin-2). */ MPFR_SET_POS (tmp); /* no error */ mpfr_atan (tmp, tmp, MPFR_RNDN); /* Error <= 2*ulp (tmp) since abs(D(arctan)) <= 1 */ mpfr_const_pi (pi, MPFR_RNDN); /* Error <= ulp(pi) /2 */ e = MPFR_NOTZERO(tmp) ? MPFR_GET_EXP (tmp) : __gmpfr_emin - 1; mpfr_sub (tmp, pi, tmp, MPFR_RNDN); /* see above */ if (MPFR_IS_NEG (y)) MPFR_CHANGE_SIGN (tmp); /* Error(tmp) <= (1/2+2^(EXP(pi)-EXP(tmp)-1)+2^(e-EXP(tmp)+1))*ulp <= 2^(MAX (MAX (EXP(PI)-EXP(tmp)-1, e-EXP(tmp)+1), -1)+2)*ulp(tmp) */ e = MAX (MAX (MPFR_GET_EXP (pi)-MPFR_GET_EXP (tmp) - 1, e - MPFR_GET_EXP (tmp) + 1), -1) + 2; if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - e, MPFR_PREC (dest), rnd_mode))) break; MPFR_ZIV_NEXT (loop, prec); mpfr_set_prec (tmp, prec); mpfr_set_prec (pi, prec); } mpfr_clear (pi); } inexact = mpfr_set (dest, tmp, rnd_mode); end: MPFR_ZIV_FREE (loop); mpfr_clear (tmp); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (dest, inexact, rnd_mode); }
static void special (void) { mpfr_t x, y; int r; mpfr_init (x); mpfr_init (y); /* asin(NaN) = NaN */ mpfr_set_nan (x); mpfr_asin (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_asin (NaN) <> NaN\n"); exit (1); } /* asin(+/-Inf) = NaN */ mpfr_set_inf (x, 1); mpfr_asin (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_asin (+Inf) <> NaN\n"); exit (1); } mpfr_set_inf (x, -1); mpfr_asin (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_asin (-Inf) <> NaN\n"); exit (1); } /* asin(+/-2) = NaN */ mpfr_set_ui (x, 2, MPFR_RNDN); mpfr_asin (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_asin (+2) <> NaN\n"); exit (1); } mpfr_set_si (x, -2, MPFR_RNDN); mpfr_asin (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error: mpfr_asin (-2) <> NaN\n"); exit (1); } /* asin(+/-0) = +/-0 */ mpfr_set_ui (x, 0, MPFR_RNDN); mpfr_asin (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) < 0) { printf ("Error: mpfr_asin (+0) <> +0\n"); exit (1); } mpfr_neg (x, x, MPFR_RNDN); mpfr_asin (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 0) || mpfr_sgn (y) > 0) { printf ("Error: mpfr_asin (-0) <> -0\n"); exit (1); } /* asin(1) = Pi/2 */ for (r = 0; r < MPFR_RND_MAX; r++) { mpfr_set_ui (x, 1, MPFR_RNDN); /* exact */ mpfr_asin (y, x, (mpfr_rnd_t) r); mpfr_const_pi (x, (mpfr_rnd_t) r); mpfr_div_2exp (x, x, 1, MPFR_RNDN); /* exact */ if (mpfr_cmp (x, y)) { printf ("Error: asin(1) != Pi/2 for rnd=%s\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); exit (1); } } /* asin(-1) = -Pi/2 */ for (r = 0; r < MPFR_RND_MAX; r++) { mpfr_set_si (x, -1, MPFR_RNDN); /* exact */ mpfr_asin (y, x, (mpfr_rnd_t) r); mpfr_const_pi (x, MPFR_INVERT_RND((mpfr_rnd_t) r)); mpfr_neg (x, x, MPFR_RNDN); /* exact */ mpfr_div_2exp (x, x, 1, MPFR_RNDN); /* exact */ if (mpfr_cmp (x, y)) { printf ("Error: asin(-1) != -Pi/2 for rnd=%s\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r)); exit (1); } } mpfr_set_prec (x, 32); mpfr_set_prec (y, 32); mpfr_set_str_binary (x, "0.1101110111111111001011101000101"); mpfr_asin (x, x, MPFR_RNDN); mpfr_set_str_binary (y, "1.00001100101011000001111100111"); if (mpfr_cmp (x, y)) { printf ("Error: mpfr_asin (1)\n"); exit (1); } mpfr_set_str_binary (x, "-0.01110111000011101010111100000101"); mpfr_asin (x, x, MPFR_RNDN); mpfr_set_str_binary (y, "-0.0111101111010100011111110101"); if (mpfr_cmp (x, y)) { printf ("Error: mpfr_asin (2)\n"); mpfr_print_binary (x); printf ("\n"); mpfr_print_binary (y); printf ("\n"); exit (1); } mpfr_set_prec (x, 9); mpfr_set_prec (y, 19); mpfr_set_str_binary (x, "0.110000000E-6"); mpfr_asin (y, x, MPFR_RNDD); mpfr_set_prec (x, 19); mpfr_set_str_binary (x, "0.1100000000000001001E-6"); if (mpfr_cmp (x, y)) { printf ("Error: mpfr_asin (3)\n"); mpfr_dump (x); mpfr_dump (y); exit (1); } mpfr_clear (x); mpfr_clear (y); }
int mpfr_erf (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { mpfr_t xf; mp_limb_t xf_limb[(53 - 1) / GMP_NUMB_BITS + 1]; int inex, large; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode), ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y, inex)); 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)) /* erf(+inf) = +1, erf(-inf) = -1 */ return mpfr_set_si (y, MPFR_INT_SIGN (x), MPFR_RNDN); else /* erf(+0) = +0, erf(-0) = -0 */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); return mpfr_set (y, x, MPFR_RNDN); /* should keep the sign of x */ } } /* now x is neither NaN, Inf nor 0 */ /* first try expansion at x=0 when x is small, or asymptotic expansion where x is large */ MPFR_SAVE_EXPO_MARK (expo); /* around x=0, we have erf(x) = 2x/sqrt(Pi) (1 - x^2/3 + ...), with 1 - x^2/3 <= sqrt(Pi)*erf(x)/2/x <= 1 for x >= 0. This means that if x^2/3 < 2^(-PREC(y)-1) we can decide of the correct rounding, unless we have a worst-case for 2x/sqrt(Pi). */ if (MPFR_EXP(x) < - (mpfr_exp_t) (MPFR_PREC(y) / 2)) { /* we use 2x/sqrt(Pi) (1 - x^2/3) <= erf(x) <= 2x/sqrt(Pi) for x > 0 and 2x/sqrt(Pi) <= erf(x) <= 2x/sqrt(Pi) (1 - x^2/3) for x < 0. In both cases |2x/sqrt(Pi) (1 - x^2/3)| <= |erf(x)| <= |2x/sqrt(Pi)|. We will compute l and h such that l <= |2x/sqrt(Pi) (1 - x^2/3)| and |2x/sqrt(Pi)| <= h. If l and h round to the same value to precision PREC(y) and rounding rnd_mode, then we are done. */ mpfr_t l, h; /* lower and upper bounds for erf(x) */ int ok, inex2; mpfr_init2 (l, MPFR_PREC(y) + 17); mpfr_init2 (h, MPFR_PREC(y) + 17); /* first compute l */ mpfr_mul (l, x, x, MPFR_RNDU); mpfr_div_ui (l, l, 3, MPFR_RNDU); /* upper bound on x^2/3 */ mpfr_ui_sub (l, 1, l, MPFR_RNDZ); /* lower bound on 1 - x^2/3 */ mpfr_const_pi (h, MPFR_RNDU); /* upper bound of Pi */ mpfr_sqrt (h, h, MPFR_RNDU); /* upper bound on sqrt(Pi) */ mpfr_div (l, l, h, MPFR_RNDZ); /* lower bound on 1/sqrt(Pi) (1 - x^2/3) */ mpfr_mul_2ui (l, l, 1, MPFR_RNDZ); /* 2/sqrt(Pi) (1 - x^2/3) */ mpfr_mul (l, l, x, MPFR_RNDZ); /* |l| is a lower bound on |2x/sqrt(Pi) (1 - x^2/3)| */ /* now compute h */ mpfr_const_pi (h, MPFR_RNDD); /* lower bound on Pi */ mpfr_sqrt (h, h, MPFR_RNDD); /* lower bound on sqrt(Pi) */ mpfr_div_2ui (h, h, 1, MPFR_RNDD); /* lower bound on sqrt(Pi)/2 */ /* since sqrt(Pi)/2 < 1, the following should not underflow */ mpfr_div (h, x, h, MPFR_IS_POS(x) ? MPFR_RNDU : MPFR_RNDD); /* round l and h to precision PREC(y) */ inex = mpfr_prec_round (l, MPFR_PREC(y), rnd_mode); inex2 = mpfr_prec_round (h, MPFR_PREC(y), rnd_mode); /* Caution: we also need inex=inex2 (inex might be 0). */ ok = SAME_SIGN (inex, inex2) && mpfr_cmp (l, h) == 0; if (ok) mpfr_set (y, h, rnd_mode); mpfr_clear (l); mpfr_clear (h); if (ok) goto end; /* this test can still fail for small precision, for example for x=-0.100E-2 with a target precision of 3 bits, since the error term x^2/3 is not that small. */ } MPFR_TMP_INIT1(xf_limb, xf, 53); mpfr_div (xf, x, __gmpfr_const_log2_RNDU, MPFR_RNDZ); /* round to zero ensures we get a lower bound of |x/log(2)| */ mpfr_mul (xf, xf, x, MPFR_RNDZ); large = mpfr_cmp_ui (xf, MPFR_PREC (y) + 1) > 0; /* when x goes to infinity, we have erf(x) = 1 - 1/sqrt(Pi)/exp(x^2)/x + ... and |erf(x) - 1| <= exp(-x^2) is true for any x >= 0, thus if exp(-x^2) < 2^(-PREC(y)-1) the result is 1 or 1-epsilon. This rewrites as x^2/log(2) > p+1. */ if (MPFR_UNLIKELY (large)) /* |erf x| = 1 or 1- */ { mpfr_rnd_t rnd2 = MPFR_IS_POS (x) ? rnd_mode : MPFR_INVERT_RND(rnd_mode); if (rnd2 == MPFR_RNDN || rnd2 == MPFR_RNDU || rnd2 == MPFR_RNDA) { inex = MPFR_INT_SIGN (x); mpfr_set_si (y, inex, rnd2); } else /* round to zero */ { inex = -MPFR_INT_SIGN (x); mpfr_setmax (y, 0); /* warning: setmax keeps the old sign of y */ MPFR_SET_SAME_SIGN (y, x); } } else /* use Taylor */ { double xf2; /* FIXME: get rid of doubles/mpfr_get_d here */ xf2 = mpfr_get_d (x, MPFR_RNDN); xf2 = xf2 * xf2; /* xf2 ~ x^2 */ inex = mpfr_erf_0 (y, x, xf2, rnd_mode); } end: MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inex, rnd_mode); }
/* return in z a lower bound (for rnd = RNDD) or upper bound (for rnd = RNDU) of |zeta(s)|/2, using: log(|zeta(s)|/2) = (s-1)*log(2*Pi) + lngamma(1-s) + log(|sin(Pi*s/2)| * zeta(1-s)). Assumes s < 1/2 and s1 = 1-s exactly, thus s1 > 1/2. y and p are temporary variables. At input, p is Pi rounded down. The comments in the code are for rnd = RNDD. */ static void mpfr_reflection_overflow (mpfr_t z, mpfr_t s1, const mpfr_t s, mpfr_t y, mpfr_t p, mpfr_rnd_t rnd) { mpz_t sint; MPFR_ASSERTD (rnd == MPFR_RNDD || rnd == MPFR_RNDU); /* Since log is increasing, we want lower bounds on |sin(Pi*s/2)| and zeta(1-s). */ mpz_init (sint); mpfr_get_z (sint, s, MPFR_RNDD); /* sint = floor(s) */ /* We first compute a lower bound of |sin(Pi*s/2)|, which is a periodic function of period 2. Thus: if 2k < s < 2k+1, then |sin(Pi*s/2)| is increasing; if 2k-1 < s < 2k, then |sin(Pi*s/2)| is decreasing. These cases are distinguished by testing bit 0 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 2): 0: sint = 0 mod 2, thus 2k < s < 2k+1 and |sin(Pi*s/2)| is increasing; 1: sint = 1 mod 2, thus 2k-1 < s < 2k and |sin(Pi*s/2)| is decreasing. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 0) == 0) /* |sin(Pi*s/2)| is increasing: round down Pi*s to get a lower bound. */ { mpfr_mul (y, p, s, rnd); if (rnd == MPFR_RNDD) mpfr_nextabove (p); /* we will need p rounded above afterwards */ } else /* |sin(Pi*s/2)| is decreasing: round up Pi*s to get a lower bound. */ { if (rnd == MPFR_RNDD) mpfr_nextabove (p); mpfr_mul (y, p, s, MPFR_INVERT_RND(rnd)); } mpfr_div_2ui (y, y, 1, MPFR_RNDN); /* exact, rounding mode doesn't matter */ /* The rounding direction of sin depends on its sign. We have: if -4k-2 < s < -4k, then -2k-1 < s/2 < -2k, thus sin(Pi*s/2) < 0; if -4k < s < -4k+2, then -2k < s/2 < -2k+1, thus sin(Pi*s/2) > 0. These cases are distinguished by testing bit 1 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 4): 0: sint = {0,1} mod 4, thus -2k < s/2 < -2k+1 and sin(Pi*s/2) > 0; 1: sint = {2,3} mod 4, thus -2k-1 < s/2 < -2k and sin(Pi*s/2) < 0. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 1) == 0) /* -2k < s/2 < -2k+1; sin(Pi*s/2) > 0 */ { /* Round sin down to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, rnd); } else /* -2k-1 < s/2 < -2k; sin(Pi*s/2) < 0 */ { /* Round sin up to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, MPFR_INVERT_RND(rnd)); mpfr_abs (y, y, MPFR_RNDN); /* exact, rounding mode doesn't matter */ } mpz_clear (sint); /* now y <= |sin(Pi*s/2)| when rnd=RNDD, y >= |sin(Pi*s/2)| when rnd=RNDU */ mpfr_zeta_pos (z, s1, rnd); /* zeta(1-s) */ mpfr_mul (z, z, y, rnd); /* now z <= |sin(Pi*s/2)|*zeta(1-s) */ mpfr_log (z, z, rnd); /* now z <= log(|sin(Pi*s/2)|*zeta(1-s)) */ mpfr_lngamma (y, s1, rnd); mpfr_add (z, z, y, rnd); /* z <= lngamma(1-s) + log(|sin(Pi*s/2)|*zeta(1-s)) */ /* since s-1 < 0, we want to round log(2*pi) upwards */ mpfr_mul_2ui (y, p, 1, MPFR_INVERT_RND(rnd)); mpfr_log (y, y, MPFR_INVERT_RND(rnd)); mpfr_mul (y, y, s1, MPFR_INVERT_RND(rnd)); mpfr_sub (z, z, y, rnd); mpfr_exp (z, z, rnd); if (rnd == MPFR_RNDD) mpfr_nextbelow (p); /* restore original p */ }