int main (int argc, char *argv[]) { mpfr_t x, y; long n; if (argc > 1) { mpfr_init2 (x, atoi (argv[1])); mpfr_set_str (x, argv[3], 10, MPFR_RNDN); mpfr_jn (x, atoi (argv[2]), x, MPFR_RNDN); mpfr_out_str (stdout, 10, 10, x, MPFR_RNDN); printf ("\n"); mpfr_clear (x); return 0; } tests_start_mpfr (); mpfr_init (x); mpfr_init (y); /* special values */ mpfr_set_nan (x); mpfr_jn (y, 17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_nan_p (y)); mpfr_set_inf (x, 1); /* +Inf */ mpfr_jn (y, 17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); mpfr_set_inf (x, -1); /* -Inf */ mpfr_jn (y, 17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); mpfr_set_ui (x, 0, MPFR_RNDN); /* +0 */ mpfr_jn (y, 0, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 1) == 0); /* j0(+0)=1 */ mpfr_jn (y, 17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); /* j17(+0)=+0 */ mpfr_jn (y, -17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_NEG (y)); /* j-17(+0)=-0 */ mpfr_jn (y, 42, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); /* j42(+0)=+0 */ mpfr_set_ui (x, 0, MPFR_RNDN); mpfr_neg (x, x, MPFR_RNDN); /* -0 */ mpfr_jn (y, 0, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 1) == 0); /* j0(-0)=1 */ mpfr_jn (y, 17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_NEG (y)); /* j17(-0)=-0 */ mpfr_jn (y, -17, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); /* j-17(-0)=+0 */ mpfr_jn (y, 42, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_cmp_ui (y, 0) == 0 && MPFR_IS_POS (y)); /* j42(-0)=+0 */ mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_jn (y, 0, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.1100001111100011111111101101111010111101110001111"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=0, x=1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_si (x, -1, MPFR_RNDN); mpfr_jn (y, 0, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.1100001111100011111111101101111010111101110001111"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=0, x=-1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_jn (y, 1, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.0111000010100111001001111011101001011100001100011011"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=1, x=1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_jn (y, 17, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.1100011111001010101001001001000110110000010001011E-65"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=17, x=1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_jn (y, 42, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.10000111100011010100111011100111101101000100000001001E-211"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=42, x=1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_jn (y, -42, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.10000111100011010100111011100111101101000100000001001E-211"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=-42, x=1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_si (x, -1, MPFR_RNDN); mpfr_jn (y, 42, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.10000111100011010100111011100111101101000100000001001E-211"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=42, x=-1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_si (x, -1, MPFR_RNDN); mpfr_jn (y, -42, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.10000111100011010100111011100111101101000100000001001E-211"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=-42, x=-1, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 4, x, MPFR_RNDN); mpfr_set_str_binary (x, "-0.0001110001011001100010100111100111100000111110111011111"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=4, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 16, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.0011101111100111101111010100000111111001111001001010011"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=16, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 256, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.11111101111100110000000010111101101011101011110001011E-894"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=256, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 65536, x, MPFR_RNDN); mpfr_set_str_binary (x, "100010010010011010110101100001000100011100010111011E-751747"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=65536, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 131072, x, MPFR_RNDN); mpfr_set_str_binary (x, "1000001001110011111001110110000010011010000001001101E-1634508"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=131072, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 262144, x, MPFR_RNDN); mpfr_set_str_binary (x, "1010011011000100111011001011110001000010000010111111E-3531100"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=262144, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, 524288, x, MPFR_RNDN); mpfr_set_str_binary (x, "110000001010001111011011000011001011010100010001011E-7586426"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=524288, x=17, rnd=MPFR_RNDN\n"); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } n = LONG_MAX; /* ensures n is odd */ if (n % 2 == 0) n --; mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, n, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.0"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=%ld, x=17, rnd=MPFR_RNDN\n", n); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_si (x, -17, MPFR_RNDN); mpfr_jn (y, n, x, MPFR_RNDN); mpfr_set_str_binary (x, "-0.0"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=%ld, x=-17, rnd=MPFR_RNDN\n", n); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_ui (x, 17, MPFR_RNDN); mpfr_jn (y, -n, x, MPFR_RNDN); mpfr_set_str_binary (x, "-0.0"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=%ld, x=17, rnd=MPFR_RNDN\n", -n); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_set_si (x, -17, MPFR_RNDN); mpfr_jn (y, -n, x, MPFR_RNDN); mpfr_set_str_binary (x, "0.0"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_jn for n=%ld, x=-17, rnd=MPFR_RNDN\n", -n); printf ("Expected "); mpfr_dump (x); printf ("Got "); mpfr_dump (y); exit (1); } mpfr_clear (x); mpfr_clear (y); tests_end_mpfr (); return 0; }
int mpfr_yn (mpfr_ptr res, long n, mpfr_srcptr z, mpfr_rnd_t r) { int inex; unsigned long absn; MPFR_SAVE_EXPO_DECL (expo); MPFR_LOG_FUNC (("n=%ld x[%Pu]=%.*Rg rnd=%d", n, mpfr_get_prec (z), mpfr_log_prec, z, r), ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (res), mpfr_log_prec, res, inex)); absn = SAFE_ABS (unsigned long, n); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (z))) { if (MPFR_IS_NAN (z)) { MPFR_SET_NAN (res); /* y(n,NaN) = NaN */ MPFR_RET_NAN; } /* y(n,z) tends to zero when z goes to +Inf, oscillating around 0. We choose to return +0 in that case. */ else if (MPFR_IS_INF (z)) { if (MPFR_SIGN(z) > 0) return mpfr_set_ui (res, 0, r); else /* y(n,-Inf) = NaN */ { MPFR_SET_NAN (res); MPFR_RET_NAN; } } else /* y(n,z) tends to -Inf for n >= 0 or n even, to +Inf otherwise, when z goes to zero */ { MPFR_SET_INF(res); if (n >= 0 || ((unsigned long) n & 1) == 0) MPFR_SET_NEG(res); else MPFR_SET_POS(res); mpfr_set_divby0 (); MPFR_RET(0); } } /* for z < 0, y(n,z) is imaginary except when j(n,|z|) = 0, which we assume does not happen for a rational z. */ if (MPFR_SIGN(z) < 0) { MPFR_SET_NAN (res); MPFR_RET_NAN; } /* now z is not singular, and z > 0 */ MPFR_SAVE_EXPO_MARK (expo); /* Deal with tiny arguments. We have: y0(z) = 2 log(z)/Pi + 2 (euler - log(2))/Pi + O(log(z)*z^2), more precisely for 0 <= z <= 1/2, with g(z) = 2/Pi + 2(euler-log(2))/Pi/log(z), g(z) - 0.41*z^2 < y0(z)/log(z) < g(z) thus since log(z) is negative: g(z)*log(z) < y0(z) < (g(z) - z^2/2)*log(z) and since |g(z)| >= 0.63 for 0 <= z <= 1/2, the relative error on y0(z)/log(z) is bounded by 0.41*z^2/0.63 <= 0.66*z^2. Note: we use both the main term in log(z) and the constant term, because otherwise the relative error would be only in 1/log(|log(z)|). */ if (n == 0 && MPFR_EXP(z) < - (mpfr_exp_t) (MPFR_PREC(res) / 2)) { mpfr_t l, h, t, logz; mpfr_prec_t prec; int ok, inex2; prec = MPFR_PREC(res) + 10; mpfr_init2 (l, prec); mpfr_init2 (h, prec); mpfr_init2 (t, prec); mpfr_init2 (logz, prec); /* first enclose log(z) + euler - log(2) = log(z/2) + euler */ mpfr_log (logz, z, MPFR_RNDD); /* lower bound of log(z) */ mpfr_set (h, logz, MPFR_RNDU); /* exact */ mpfr_nextabove (h); /* upper bound of log(z) */ mpfr_const_euler (t, MPFR_RNDD); /* lower bound of euler */ mpfr_add (l, logz, t, MPFR_RNDD); /* lower bound of log(z) + euler */ mpfr_nextabove (t); /* upper bound of euler */ mpfr_add (h, h, t, MPFR_RNDU); /* upper bound of log(z) + euler */ mpfr_const_log2 (t, MPFR_RNDU); /* upper bound of log(2) */ mpfr_sub (l, l, t, MPFR_RNDD); /* lower bound of log(z/2) + euler */ mpfr_nextbelow (t); /* lower bound of log(2) */ mpfr_sub (h, h, t, MPFR_RNDU); /* upper bound of log(z/2) + euler */ mpfr_const_pi (t, MPFR_RNDU); /* upper bound of Pi */ mpfr_div (l, l, t, MPFR_RNDD); /* lower bound of (log(z/2)+euler)/Pi */ mpfr_nextbelow (t); /* lower bound of Pi */ mpfr_div (h, h, t, MPFR_RNDD); /* upper bound of (log(z/2)+euler)/Pi */ mpfr_mul_2ui (l, l, 1, MPFR_RNDD); /* lower bound on g(z)*log(z) */ mpfr_mul_2ui (h, h, 1, MPFR_RNDU); /* upper bound on g(z)*log(z) */ /* we now have l <= g(z)*log(z) <= h, and we need to add -z^2/2*log(z) to h */ mpfr_mul (t, z, z, MPFR_RNDU); /* upper bound on z^2 */ /* since logz is negative, a lower bound corresponds to an upper bound for its absolute value */ mpfr_neg (t, t, MPFR_RNDD); mpfr_div_2ui (t, t, 1, MPFR_RNDD); mpfr_mul (t, t, logz, MPFR_RNDU); /* upper bound on z^2/2*log(z) */ mpfr_add (h, h, t, MPFR_RNDU); inex = mpfr_prec_round (l, MPFR_PREC(res), r); inex2 = mpfr_prec_round (h, MPFR_PREC(res), r); /* we need h=l and inex=inex2 */ ok = (inex == inex2) && mpfr_equal_p (l, h); if (ok) mpfr_set (res, h, r); /* exact */ mpfr_clear (l); mpfr_clear (h); mpfr_clear (t); mpfr_clear (logz); if (ok) goto end; } /* small argument check for y1(z) = -2/Pi/z + O(log(z)): for 0 <= z <= 1, |y1(z) + 2/Pi/z| <= 0.25 */ if (n == 1 && MPFR_EXP(z) + 1 < - (mpfr_exp_t) MPFR_PREC(res)) { mpfr_t y; mpfr_prec_t prec; mpfr_exp_t err1; int ok; MPFR_BLOCK_DECL (flags); /* since 2/Pi > 0.5, and |y1(z)| >= |2/Pi/z|, if z <= 2^(-emax-1), then |y1(z)| > 2^emax */ prec = MPFR_PREC(res) + 10; mpfr_init2 (y, prec); mpfr_const_pi (y, MPFR_RNDU); /* Pi*(1+u)^2, where here and below u represents a quantity <= 1/2^prec */ mpfr_mul (y, y, z, MPFR_RNDU); /* Pi*z * (1+u)^4, upper bound */ MPFR_BLOCK (flags, mpfr_ui_div (y, 2, y, MPFR_RNDZ)); /* 2/Pi/z * (1+u)^6, lower bound, with possible overflow */ if (MPFR_OVERFLOW (flags)) { mpfr_clear (y); MPFR_SAVE_EXPO_FREE (expo); return mpfr_overflow (res, r, -1); } mpfr_neg (y, y, MPFR_RNDN); /* (1+u)^6 can be written 1+7u [for another value of u], thus the error on 2/Pi/z is less than 7ulp(y). The truncation error is less than 1/4, thus if ulp(y)>=1/4, the total error is less than 8ulp(y), otherwise it is less than 1/4+7/8 <= 2. */ if (MPFR_EXP(y) + 2 >= MPFR_PREC(y)) /* ulp(y) >= 1/4 */ err1 = 3; else /* ulp(y) <= 1/8 */ err1 = (mpfr_exp_t) MPFR_PREC(y) - MPFR_EXP(y) + 1; ok = MPFR_CAN_ROUND (y, prec - err1, MPFR_PREC(res), r); if (ok) inex = mpfr_set (res, y, r); mpfr_clear (y); if (ok) goto end; } /* we can use the asymptotic expansion as soon as z > p log(2)/2, but to get some margin we use it for z > p/2 */ if (mpfr_cmp_ui (z, MPFR_PREC(res) / 2 + 3) > 0) { inex = mpfr_yn_asympt (res, n, z, r); if (inex != 0) goto end; } /* General case */ { mpfr_prec_t prec; mpfr_exp_t err1, err2, err3; mpfr_t y, s1, s2, s3; MPFR_ZIV_DECL (loop); mpfr_init (y); mpfr_init (s1); mpfr_init (s2); mpfr_init (s3); prec = MPFR_PREC(res) + 2 * MPFR_INT_CEIL_LOG2 (MPFR_PREC (res)) + 13; MPFR_ZIV_INIT (loop, prec); for (;;) { mpfr_set_prec (y, prec); mpfr_set_prec (s1, prec); mpfr_set_prec (s2, prec); mpfr_set_prec (s3, prec); mpfr_mul (y, z, z, MPFR_RNDN); mpfr_div_2ui (y, y, 2, MPFR_RNDN); /* z^2/4 */ /* store (z/2)^n temporarily in s2 */ mpfr_pow_ui (s2, z, absn, MPFR_RNDN); mpfr_div_2si (s2, s2, absn, MPFR_RNDN); /* compute S1 * (z/2)^(-n) */ if (n == 0) { mpfr_set_ui (s1, 0, MPFR_RNDN); err1 = 0; } else err1 = mpfr_yn_s1 (s1, y, absn - 1); mpfr_div (s1, s1, s2, MPFR_RNDN); /* (z/2)^(-n) * S1 */ /* See algorithms.tex: the relative error on s1 is bounded by (3n+3)*2^(e+1-prec). */ err1 = MPFR_INT_CEIL_LOG2 (3 * absn + 3) + err1 + 1; /* rel_err(s1) <= 2^(err1-prec), thus err(s1) <= 2^err1 ulps */ /* compute (z/2)^n * S3 */ mpfr_neg (y, y, MPFR_RNDN); /* -z^2/4 */ err3 = mpfr_yn_s3 (s3, y, s2, absn); /* (z/2)^n * S3 */ /* the error on s3 is bounded by 2^err3 ulps */ /* add s1+s3 */ err1 += MPFR_EXP(s1); mpfr_add (s1, s1, s3, MPFR_RNDN); /* the error is bounded by 1/2 + 2^err1*2^(- EXP(s1)) + 2^err3*2^(EXP(s3) - EXP(s1)) */ err3 += MPFR_EXP(s3); err1 = (err3 > err1) ? err3 + 1 : err1 + 1; err1 -= MPFR_EXP(s1); err1 = (err1 >= 0) ? err1 + 1 : 1; /* now the error on s1 is bounded by 2^err1*ulp(s1) */ /* compute S2 */ mpfr_div_2ui (s2, z, 1, MPFR_RNDN); /* z/2 */ mpfr_log (s2, s2, MPFR_RNDN); /* log(z/2) */ mpfr_const_euler (s3, MPFR_RNDN); err2 = MPFR_EXP(s2) > MPFR_EXP(s3) ? MPFR_EXP(s2) : MPFR_EXP(s3); mpfr_add (s2, s2, s3, MPFR_RNDN); /* log(z/2) + gamma */ err2 -= MPFR_EXP(s2); mpfr_mul_2ui (s2, s2, 1, MPFR_RNDN); /* 2*(log(z/2) + gamma) */ mpfr_jn (s3, absn, z, MPFR_RNDN); /* Jn(z) */ mpfr_mul (s2, s2, s3, MPFR_RNDN); /* 2*(log(z/2) + gamma)*Jn(z) */ err2 += 4; /* the error on s2 is bounded by 2^err2 ulps, see algorithms.tex */ /* add all three sums */ err1 += MPFR_EXP(s1); /* the error on s1 is bounded by 2^err1 */ err2 += MPFR_EXP(s2); /* the error on s2 is bounded by 2^err2 */ mpfr_sub (s2, s2, s1, MPFR_RNDN); /* s2 - (s1+s3) */ err2 = (err1 > err2) ? err1 + 1 : err2 + 1; err2 -= MPFR_EXP(s2); err2 = (err2 >= 0) ? err2 + 1 : 1; /* now the error on s2 is bounded by 2^err2*ulp(s2) */ mpfr_const_pi (y, MPFR_RNDN); /* error bounded by 1 ulp */ mpfr_div (s2, s2, y, MPFR_RNDN); /* error bounded by 2^(err2+1)*ulp(s2) */ err2 ++; if (MPFR_LIKELY (MPFR_CAN_ROUND (s2, prec - err2, MPFR_PREC(res), r))) break; MPFR_ZIV_NEXT (loop, prec); } MPFR_ZIV_FREE (loop); /* Assume two's complement for the test n & 1 */ inex = mpfr_set4 (res, s2, r, n >= 0 || (n & 1) == 0 ? MPFR_SIGN (s2) : - MPFR_SIGN (s2)); mpfr_clear (y); mpfr_clear (s1); mpfr_clear (s2); mpfr_clear (s3); } end: MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (res, inex, r); }