static void other (void) { mpfr_t x, y; /* Bug reported by Guillaume Melquiond on 2006-08-14. */ mpfr_init2 (x, 53); mpfr_set_str (x, "-1.5e4f72873ed9a@-100", 16, MPFR_RNDN); mpfr_init2 (y, 57); mpfr_log1p (y, x, MPFR_RNDU); if (mpfr_cmp (x, y) != 0) { printf ("Error in tlog1p for x = "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); printf (", rnd = MPFR_RNDU\nExpected "); mpfr_out_str (stdout, 16, 15, x, MPFR_RNDN); printf ("\nGot "); mpfr_out_str (stdout, 16, 15, y, MPFR_RNDN); printf ("\n"); exit (1); } mpfr_clear (y); mpfr_clear (x); return; }
static int test_log1p (mpfr_ptr a, mpfr_srcptr b, mpfr_rnd_t rnd_mode) { int res; int ok = rnd_mode == MPFR_RNDN && mpfr_number_p (b) && mpfr_get_prec (a)>=53; if (ok) { mpfr_print_raw (b); } res = mpfr_log1p (a, b, rnd_mode); if (ok) { printf (" "); mpfr_print_raw (a); printf ("\n"); } return res; }
int main() { long iter; flint_rand_t state; printf("log1p...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100000; iter++) { long bits; fmpr_t x, z, w; mpfr_t X, Z; bits = 2 + n_randint(state, 200); fmpr_init(x); fmpr_init(z); fmpr_init(w); mpfr_init2(X, bits + 100); mpfr_init2(Z, bits); fmpr_randtest_special(x, state, bits + n_randint(state, 100), 10); fmpr_randtest_special(z, state, bits + n_randint(state, 100), 10); fmpr_get_mpfr(X, x, MPFR_RNDN); switch (n_randint(state, 4)) { case 0: mpfr_log1p(Z, X, MPFR_RNDZ); fmpr_log1p(z, x, bits, FMPR_RND_DOWN); break; case 1: mpfr_log1p(Z, X, MPFR_RNDA); fmpr_log1p(z, x, bits, FMPR_RND_UP); break; case 2: mpfr_log1p(Z, X, MPFR_RNDD); fmpr_log1p(z, x, bits, FMPR_RND_FLOOR); break; case 3: mpfr_log1p(Z, X, MPFR_RNDU); fmpr_log1p(z, x, bits, FMPR_RND_CEIL); break; } fmpr_set_mpfr(w, Z); if (!fmpr_equal(z, w)) { printf("FAIL\n\n"); printf("bits = %ld\n", bits); printf("x = "); fmpr_print(x); printf("\n\n"); printf("z = "); fmpr_print(z); printf("\n\n"); printf("w = "); fmpr_print(w); printf("\n\n"); abort(); } fmpr_clear(x); fmpr_clear(z); fmpr_clear(w); mpfr_clear(X); mpfr_clear(Z); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
int mpc_log (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd){ int ok, underflow = 0; mpfr_srcptr x, y; mpfr_t v, w; mpfr_prec_t prec; int loops; int re_cmp, im_cmp; int inex_re, inex_im; int err; mpfr_exp_t expw; int sgnw; /* special values: NaN and infinities */ if (!mpc_fin_p (op)) { if (mpfr_nan_p (mpc_realref (op))) { if (mpfr_inf_p (mpc_imagref (op))) mpfr_set_inf (mpc_realref (rop), +1); else mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); inex_im = 0; /* Inf/NaN is exact */ } else if (mpfr_nan_p (mpc_imagref (op))) { if (mpfr_inf_p (mpc_realref (op))) mpfr_set_inf (mpc_realref (rop), +1); else mpfr_set_nan (mpc_realref (rop)); mpfr_set_nan (mpc_imagref (rop)); inex_im = 0; /* Inf/NaN is exact */ } else /* We have an infinity in at least one part. */ { inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); mpfr_set_inf (mpc_realref (rop), +1); } return MPC_INEX(0, inex_im); } /* special cases: real and purely imaginary numbers */ re_cmp = mpfr_cmp_ui (mpc_realref (op), 0); im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0); if (im_cmp == 0) { if (re_cmp == 0) { inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); mpfr_set_inf (mpc_realref (rop), -1); inex_re = 0; /* -Inf is exact */ } else if (re_cmp > 0) { inex_re = mpfr_log (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd)); inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd)); } else { /* op = x + 0*y; let w = -x = |x| */ int negative_zero; mpfr_rnd_t rnd_im; negative_zero = mpfr_signbit (mpc_imagref (op)); if (negative_zero) rnd_im = INV_RND (MPC_RND_IM (rnd)); else rnd_im = MPC_RND_IM (rnd); w [0] = *mpc_realref (op); MPFR_CHANGE_SIGN (w); inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), rnd_im); if (negative_zero) { mpc_conj (rop, rop, MPC_RNDNN); inex_im = -inex_im; } } return MPC_INEX(inex_re, inex_im); } else if (re_cmp == 0) { if (im_cmp > 0) { inex_re = mpfr_log (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), MPC_RND_IM (rnd)); /* division by 2 does not change the ternary flag */ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); } else { w [0] = *mpc_imagref (op); MPFR_CHANGE_SIGN (w); inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd)); inex_im = mpfr_const_pi (mpc_imagref (rop), INV_RND (MPC_RND_IM (rnd))); /* division by 2 does not change the ternary flag */ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN); mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN); inex_im = -inex_im; /* negate the ternary flag */ } return MPC_INEX(inex_re, inex_im); } prec = MPC_PREC_RE(rop); mpfr_init2 (w, 2); /* let op = x + iy; log = 1/2 log (x^2 + y^2) + i atan2 (y, x) */ /* loop for the real part: 1/2 log (x^2 + y^2), fast, but unsafe */ /* implementation */ ok = 0; for (loops = 1; !ok && loops <= 2; loops++) { prec += mpc_ceil_log2 (prec) + 4; mpfr_set_prec (w, prec); mpc_abs (w, op, GMP_RNDN); /* error 0.5 ulp */ if (mpfr_inf_p (w)) /* intermediate overflow; the logarithm may be representable. Intermediate underflow is impossible. */ break; mpfr_log (w, w, GMP_RNDN); /* generic error of log: (2^(- exp(w)) + 0.5) ulp */ if (mpfr_zero_p (w)) /* impossible to round, switch to second algorithm */ break; err = MPC_MAX (-mpfr_get_exp (w), 0) + 1; /* number of lost digits */ ok = mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ, mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN)); } if (!ok) { prec = MPC_PREC_RE(rop); mpfr_init2 (v, 2); /* compute 1/2 log (x^2 + y^2) = log |x| + 1/2 * log (1 + (y/x)^2) if |x| >= |y|; otherwise, exchange x and y */ if (mpfr_cmpabs (mpc_realref (op), mpc_imagref (op)) >= 0) { x = mpc_realref (op); y = mpc_imagref (op); } else { x = mpc_imagref (op); y = mpc_realref (op); } do { prec += mpc_ceil_log2 (prec) + 4; mpfr_set_prec (v, prec); mpfr_set_prec (w, prec); mpfr_div (v, y, x, GMP_RNDD); /* error 1 ulp */ mpfr_sqr (v, v, GMP_RNDD); /* generic error of multiplication: 1 + 2*1*(2+1*2^(1-prec)) <= 5.0625 since prec >= 6 */ mpfr_log1p (v, v, GMP_RNDD); /* error 1 + 4*5.0625 = 21.25 , see algorithms.tex */ mpfr_div_2ui (v, v, 1, GMP_RNDD); /* If the result is 0, then there has been an underflow somewhere. */ mpfr_abs (w, x, GMP_RNDN); /* exact */ mpfr_log (w, w, GMP_RNDN); /* error 0.5 ulp */ expw = mpfr_get_exp (w); sgnw = mpfr_signbit (w); mpfr_add (w, w, v, GMP_RNDN); if (!sgnw) /* v is positive, so no cancellation; error 22.25 ulp; error counts lost bits */ err = 5; else err = MPC_MAX (5 + mpfr_get_exp (v), /* 21.25 ulp (v) rewritten in ulp (result, now in w) */ -1 + expw - mpfr_get_exp (w) /* 0.5 ulp (previous w), rewritten in ulp (result) */ ) + 2; /* handle one special case: |x|=1, and (y/x)^2 underflows; then 1/2*log(x^2+y^2) \approx 1/2*y^2 also underflows. */ if ( (mpfr_cmp_si (x, -1) == 0 || mpfr_cmp_ui (x, 1) == 0) && mpfr_zero_p (w)) underflow = 1; } while (!underflow && !mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ, mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN))); mpfr_clear (v); } /* imaginary part */ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op), MPC_RND_IM (rnd)); /* set the real part; cannot be done before if rop==op */ if (underflow) /* create underflow in result */ inex_re = mpfr_set_ui_2exp (mpc_realref (rop), 1, mpfr_get_emin_min () - 2, MPC_RND_RE (rnd)); else inex_re = mpfr_set (mpc_realref (rop), w, MPC_RND_RE (rnd)); mpfr_clear (w); return MPC_INEX(inex_re, inex_im); }
/* Compute the real part of the dilogarithm defined by Li2(x) = -\Int_{t=0}^x log(1-t)/t dt */ int mpfr_li2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) { int inexact; mp_exp_t err; mpfr_prec_t yp, m; MPFR_ZIV_DECL (loop); MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", x, x, rnd_mode), ("y[%#R]=%R", y)); 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_NEG (y); MPFR_SET_INF (y); MPFR_RET (0); } else /* x is zero */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_SAME_SIGN (y, x); MPFR_SET_ZERO (y); MPFR_RET (0); } } /* Li2(x) = x + x^2/4 + x^3/9 + ..., more precisely for 0 < x <= 1/2 we have |Li2(x) - x| < x^2/2 <= 2^(2EXP(x)-1) and for -1/2 <= x < 0 we have |Li2(x) - x| < x^2/4 <= 2^(2EXP(x)-2) */ if (MPFR_IS_POS (x)) MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -MPFR_GET_EXP (x), 1, 1, rnd_mode, {}); else MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -MPFR_GET_EXP (x), 2, 0, rnd_mode, {}); MPFR_SAVE_EXPO_MARK (expo); yp = MPFR_PREC (y); m = yp + MPFR_INT_CEIL_LOG2 (yp) + 13; if (MPFR_LIKELY ((mpfr_cmp_ui (x, 0) > 0) && (mpfr_cmp_d (x, 0.5) <= 0))) /* 0 < x <= 1/2: Li2(x) = S(-log(1-x))-log^2(1-x)/4 */ { mpfr_t s, u; mp_exp_t expo_l; int k; mpfr_init2 (u, m); mpfr_init2 (s, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_ui_sub (u, 1, x, GMP_RNDN); mpfr_log (u, u, GMP_RNDU); if (MPFR_IS_ZERO(u)) goto next_m; mpfr_neg (u, u, GMP_RNDN); /* u = -log(1-x) */ expo_l = MPFR_GET_EXP (u); k = li2_series (s, u, GMP_RNDU); err = 1 + MPFR_INT_CEIL_LOG2 (k + 1); mpfr_sqr (u, u, GMP_RNDU); mpfr_div_2ui (u, u, 2, GMP_RNDU); /* u = log^2(1-x) / 4 */ mpfr_sub (s, s, u, GMP_RNDN); /* error(s) <= (0.5 + 2^(d-EXP(s)) + 2^(3 + MAX(1, - expo_l) - EXP(s))) ulp(s) */ err = MAX (err, MAX (1, - expo_l) - 1) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err); if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; next_m: MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (u, m); mpfr_set_prec (s, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clear (u); mpfr_clear (s); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else if (!mpfr_cmp_ui (x, 1)) /* Li2(1)= pi^2 / 6 */ { mpfr_t u; mpfr_init2 (u, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_const_pi (u, GMP_RNDU); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_ui (u, u, 6, GMP_RNDN); err = m - 4; /* error(u) <= 19/2 ulp(u) */ if (MPFR_CAN_ROUND (u, err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (u, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, u, rnd_mode); mpfr_clear (u); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else if (mpfr_cmp_ui (x, 2) >= 0) /* x >= 2: Li2(x) = -S(-log(1-1/x))-log^2(x)/2+log^2(1-1/x)/4+pi^2/3 */ { int k; mp_exp_t expo_l; mpfr_t s, u, xx; if (mpfr_cmp_ui (x, 38) >= 0) { inexact = mpfr_li2_asympt_pos (y, x, rnd_mode); if (inexact != 0) goto end_of_case_gt2; } mpfr_init2 (u, m); mpfr_init2 (s, m); mpfr_init2 (xx, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_ui_div (xx, 1, x, GMP_RNDN); mpfr_neg (xx, xx, GMP_RNDN); mpfr_log1p (u, xx, GMP_RNDD); mpfr_neg (u, u, GMP_RNDU); /* u = -log(1-1/x) */ expo_l = MPFR_GET_EXP (u); k = li2_series (s, u, GMP_RNDN); mpfr_neg (s, s, GMP_RNDN); err = MPFR_INT_CEIL_LOG2 (k + 1) + 1; /* error(s) <= 2^err ulp(s) */ mpfr_sqr (u, u, GMP_RNDN); mpfr_div_2ui (u, u, 2, GMP_RNDN); /* u= log^2(1-1/x)/4 */ mpfr_add (s, s, u, GMP_RNDN); err = MAX (err, 3 + MAX (1, -expo_l) + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */ err += MPFR_GET_EXP (s); mpfr_log (u, x, GMP_RNDU); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_2ui (u, u, 1, GMP_RNDN); /* u = log^2(x)/2 */ mpfr_sub (s, s, u, GMP_RNDN); err = MAX (err, 3 + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */ err += MPFR_GET_EXP (s); mpfr_const_pi (u, GMP_RNDU); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_ui (u, u, 3, GMP_RNDN); /* u = pi^2/3 */ mpfr_add (s, s, u, GMP_RNDN); err = MAX (err, 2) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err); /* error(s) <= 2^err ulp(s) */ if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (u, m); mpfr_set_prec (s, m); mpfr_set_prec (xx, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clears (s, u, xx, (mpfr_ptr) 0); end_of_case_gt2: MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else if (mpfr_cmp_ui (x, 1) > 0) /* 2 > x > 1: Li2(x) = S(log(x))+log^2(x)/4-log(x)log(x-1)+pi^2/6 */ { int k; mp_exp_t e1, e2; mpfr_t s, u, v, xx; mpfr_init2 (s, m); mpfr_init2 (u, m); mpfr_init2 (v, m); mpfr_init2 (xx, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_log (v, x, GMP_RNDU); k = li2_series (s, v, GMP_RNDN); e1 = MPFR_GET_EXP (s); mpfr_sqr (u, v, GMP_RNDN); mpfr_div_2ui (u, u, 2, GMP_RNDN); /* u = log^2(x)/4 */ mpfr_add (s, s, u, GMP_RNDN); mpfr_sub_ui (xx, x, 1, GMP_RNDN); mpfr_log (u, xx, GMP_RNDU); e2 = MPFR_GET_EXP (u); mpfr_mul (u, v, u, GMP_RNDN); /* u = log(x) * log(x-1) */ mpfr_sub (s, s, u, GMP_RNDN); mpfr_const_pi (u, GMP_RNDU); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_ui (u, u, 6, GMP_RNDN); /* u = pi^2/6 */ mpfr_add (s, s, u, GMP_RNDN); /* error(s) <= (31 + (k+1) * 2^(1-e1) + 2^(1-e2)) ulp(s) see algorithms.tex */ err = MAX (MPFR_INT_CEIL_LOG2 (k + 1) + 1 - e1, 1 - e2); err = 2 + MAX (5, err); if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (s, m); mpfr_set_prec (u, m); mpfr_set_prec (v, m); mpfr_set_prec (xx, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clears (s, u, v, xx, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else if (mpfr_cmp_ui_2exp (x, 1, -1) > 0) /* 1/2 < x < 1 */ /* 1 > x > 1/2: Li2(x) = -S(-log(x))+log^2(x)/4-log(x)log(1-x)+pi^2/6 */ { int k; mpfr_t s, u, v, xx; mpfr_init2 (s, m); mpfr_init2 (u, m); mpfr_init2 (v, m); mpfr_init2 (xx, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_log (u, x, GMP_RNDD); mpfr_neg (u, u, GMP_RNDN); k = li2_series (s, u, GMP_RNDN); mpfr_neg (s, s, GMP_RNDN); err = 1 + MPFR_INT_CEIL_LOG2 (k + 1) - MPFR_GET_EXP (s); mpfr_ui_sub (xx, 1, x, GMP_RNDN); mpfr_log (v, xx, GMP_RNDU); mpfr_mul (v, v, u, GMP_RNDN); /* v = - log(x) * log(1-x) */ mpfr_add (s, s, v, GMP_RNDN); err = MAX (err, 1 - MPFR_GET_EXP (v)); err = 2 + MAX (3, err) - MPFR_GET_EXP (s); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_2ui (u, u, 2, GMP_RNDN); /* u = log^2(x)/4 */ mpfr_add (s, s, u, GMP_RNDN); err = MAX (err, 2 + MPFR_GET_EXP (u)) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err) + MPFR_GET_EXP (s); mpfr_const_pi (u, GMP_RNDU); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_ui (u, u, 6, GMP_RNDN); /* u = pi^2/6 */ mpfr_add (s, s, u, GMP_RNDN); err = MAX (err, 3) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err); if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (s, m); mpfr_set_prec (u, m); mpfr_set_prec (v, m); mpfr_set_prec (xx, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clears (s, u, v, xx, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else if (mpfr_cmp_si (x, -1) >= 0) /* 0 > x >= -1: Li2(x) = -S(log(1-x))-log^2(1-x)/4 */ { int k; mp_exp_t expo_l; mpfr_t s, u, xx; mpfr_init2 (s, m); mpfr_init2 (u, m); mpfr_init2 (xx, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_neg (xx, x, GMP_RNDN); mpfr_log1p (u, xx, GMP_RNDN); k = li2_series (s, u, GMP_RNDN); mpfr_neg (s, s, GMP_RNDN); expo_l = MPFR_GET_EXP (u); err = 1 + MPFR_INT_CEIL_LOG2 (k + 1) - MPFR_GET_EXP (s); mpfr_sqr (u, u, GMP_RNDN); mpfr_div_2ui (u, u, 2, GMP_RNDN); /* u = log^2(1-x)/4 */ mpfr_sub (s, s, u, GMP_RNDN); err = MAX (err, - expo_l); err = 2 + MAX (err, 3); if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (s, m); mpfr_set_prec (u, m); mpfr_set_prec (xx, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clears (s, u, xx, (mpfr_ptr) 0); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } else /* x < -1: Li2(x) = S(log(1-1/x))-log^2(-x)/4-log(1-x)log(-x)/2+log^2(1-x)/4-pi^2/6 */ { int k; mpfr_t s, u, v, w, xx; if (mpfr_cmp_si (x, -7) <= 0) { inexact = mpfr_li2_asympt_neg (y, x, rnd_mode); if (inexact != 0) goto end_of_case_ltm1; } mpfr_init2 (s, m); mpfr_init2 (u, m); mpfr_init2 (v, m); mpfr_init2 (w, m); mpfr_init2 (xx, m); MPFR_ZIV_INIT (loop, m); for (;;) { mpfr_ui_div (xx, 1, x, GMP_RNDN); mpfr_neg (xx, xx, GMP_RNDN); mpfr_log1p (u, xx, GMP_RNDN); k = li2_series (s, u, GMP_RNDN); mpfr_ui_sub (xx, 1, x, GMP_RNDN); mpfr_log (u, xx, GMP_RNDU); mpfr_neg (xx, x, GMP_RNDN); mpfr_log (v, xx, GMP_RNDU); mpfr_mul (w, v, u, GMP_RNDN); mpfr_div_2ui (w, w, 1, GMP_RNDN); /* w = log(-x) * log(1-x) / 2 */ mpfr_sub (s, s, w, GMP_RNDN); err = 1 + MAX (3, MPFR_INT_CEIL_LOG2 (k+1) + 1 - MPFR_GET_EXP (s)) + MPFR_GET_EXP (s); mpfr_sqr (w, v, GMP_RNDN); mpfr_div_2ui (w, w, 2, GMP_RNDN); /* w = log^2(-x) / 4 */ mpfr_sub (s, s, w, GMP_RNDN); err = MAX (err, 3 + MPFR_GET_EXP(w)) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err) + MPFR_GET_EXP (s); mpfr_sqr (w, u, GMP_RNDN); mpfr_div_2ui (w, w, 2, GMP_RNDN); /* w = log^2(1-x) / 4 */ mpfr_add (s, s, w, GMP_RNDN); err = MAX (err, 3 + MPFR_GET_EXP (w)) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err) + MPFR_GET_EXP (s); mpfr_const_pi (w, GMP_RNDU); mpfr_sqr (w, w, GMP_RNDN); mpfr_div_ui (w, w, 6, GMP_RNDN); /* w = pi^2 / 6 */ mpfr_sub (s, s, w, GMP_RNDN); err = MAX (err, 3) - MPFR_GET_EXP (s); err = 2 + MAX (-1, err) + MPFR_GET_EXP (s); if (MPFR_CAN_ROUND (s, (mp_exp_t) m - err, yp, rnd_mode)) break; MPFR_ZIV_NEXT (loop, m); mpfr_set_prec (s, m); mpfr_set_prec (u, m); mpfr_set_prec (v, m); mpfr_set_prec (w, m); mpfr_set_prec (xx, m); } MPFR_ZIV_FREE (loop); inexact = mpfr_set (y, s, rnd_mode); mpfr_clears (s, u, v, w, xx, (mpfr_ptr) 0); end_of_case_ltm1: MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); } MPFR_ASSERTN (0); /* should never reach this point */ }