void bound_I(fmprb_ptr I, const fmprb_t A, const fmprb_t B, const fmprb_t C, long len, long wp) { long k; fmprb_t D, Dk, L, T, Bm1; fmprb_init(D); fmprb_init(Dk); fmprb_init(Bm1); fmprb_init(T); fmprb_init(L); fmprb_sub_ui(Bm1, B, 1, wp); fmprb_one(L); /* T = 1 / (A^Bm1 * Bm1) */ fmprb_inv(T, A, wp); fmprb_pow(T, T, Bm1, wp); fmprb_div(T, T, Bm1, wp); if (len > 1) { fmprb_log(D, A, wp); fmprb_add(D, D, C, wp); fmprb_mul(D, D, Bm1, wp); fmprb_set(Dk, D); } for (k = 0; k < len; k++) { if (k > 0) { fmprb_mul_ui(L, L, k, wp); fmprb_add(L, L, Dk, wp); fmprb_mul(Dk, Dk, D, wp); } fmprb_mul(I + k, L, T, wp); fmprb_div(T, T, Bm1, wp); } fmprb_clear(D); fmprb_clear(Dk); fmprb_clear(Bm1); fmprb_clear(T); fmprb_clear(L); }
/* series of c^(d+x) */ static __inline__ void _fmprb_poly_pow_cpx(fmprb_ptr res, const fmprb_t c, const fmprb_t d, long trunc, long prec) { long i; fmprb_t logc; fmprb_init(logc); fmprb_log(logc, c, prec); fmprb_mul(res + 0, logc, d, prec); fmprb_exp(res + 0, res + 0, prec); for (i = 1; i < trunc; i++) { fmprb_mul(res + i, res + i - 1, logc, prec); fmprb_div_ui(res + i, res + i, i, prec); } fmprb_clear(logc); }
void _fmprb_poly_riemann_siegel_theta_series(fmprb_ptr res, fmprb_srcptr h, long hlen, long len, long prec) { fmpcb_ptr s; fmprb_t u; long i; hlen = FLINT_MIN(hlen, len); s = _fmpcb_vec_init(len); fmprb_init(u); /* s = 1/4 + (1/2) i h */ for (i = 0; i < hlen; i++) fmprb_mul_2exp_si(fmpcb_imagref(s + i), h + i, -1); fmprb_one(u); fmprb_mul_2exp_si(u, u, -2); fmprb_add(fmpcb_realref(s), fmpcb_realref(s), u, prec); /* log gamma */ _fmpcb_poly_lgamma_series(s, s, hlen, len, prec); /* imaginary part */ for (i = 0; i < len; i++) fmprb_set(res + i, fmpcb_imagref(s + i)); /* subtract log(pi)/2 * h */ fmprb_const_pi(u, prec); fmprb_log(u, u, prec); fmprb_mul_2exp_si(u, u, -1); fmprb_neg(u, u); _fmprb_vec_scalar_addmul(res, h, hlen, u, prec); _fmpcb_vec_clear(s, len); fmprb_clear(u); }
long gamma_taylor_bound_mag(long n) { fmprb_t t, u; long v; fmprb_init(t); fmprb_init(u); /* (pi-1) n */ fmprb_const_pi(t, FMPRB_RAD_PREC); fmprb_sub_ui(t, t, 1, FMPRB_RAD_PREC); fmprb_mul_ui(t, t, n, FMPRB_RAD_PREC); /* (3-5n) log(n/6) */ fmprb_set_ui(u, n); fmprb_div_ui(u, u, 6, FMPRB_RAD_PREC); fmprb_log(u, u, FMPRB_RAD_PREC); fmprb_mul_si(u, u, 3 - 5*n, FMPRB_RAD_PREC); fmprb_add(t, t, u, FMPRB_RAD_PREC); /* divide by 6 log(2) */ fmprb_log_ui(u, 2, FMPRB_RAD_PREC); fmprb_mul_ui(u, u, 6, FMPRB_RAD_PREC); fmprb_div(t, t, u, FMPRB_RAD_PREC); /* upper bound */ fmpr_add(fmprb_midref(t), fmprb_midref(t), fmprb_radref(t), FMPRB_RAD_PREC, FMPR_RND_CEIL); v = fmpr_get_si(fmprb_midref(t), FMPR_RND_CEIL); fmprb_clear(t); fmprb_clear(u); return v; }
void fmprb_lgamma(fmprb_t y, const fmprb_t x, long prec) { int reflect; long r, n, wp; fmprb_t t, u; wp = prec + FLINT_BIT_COUNT(prec); gamma_stirling_choose_param_fmprb(&reflect, &r, &n, x, 0, 0, wp); /* log(gamma(x)) = log(gamma(x+r)) - log(rf(x,r)) */ fmprb_init(t); fmprb_init(u); fmprb_add_ui(t, x, r, wp); gamma_stirling_eval_fmprb(u, t, n, 0, wp); gamma_rising_fmprb_ui_bsplit(t, x, r, wp); fmprb_log(t, t, wp); fmprb_sub(y, u, t, prec); fmprb_clear(t); fmprb_clear(u); }
void gamma_stirling_eval_fmprb(fmprb_t s, const fmprb_t z, long nterms, int digamma, long prec) { fmprb_t b, t, logz, zinv, zinv2; fmpr_t err; long k, term_prec; double z_mag, term_mag; fmprb_init(b); fmprb_init(t); fmprb_init(logz); fmprb_init(zinv); fmprb_init(zinv2); fmprb_log(logz, z, prec); fmprb_ui_div(zinv, 1UL, z, prec); nterms = FLINT_MAX(nterms, 1); fmprb_zero(s); if (nterms > 1) { fmprb_mul(zinv2, zinv, zinv, prec); z_mag = fmpr_get_d(fmprb_midref(logz), FMPR_RND_UP) * 1.44269504088896; for (k = nterms - 1; k >= 1; k--) { term_mag = bernoulli_bound_2exp_si(2 * k); term_mag -= (2 * k - 1) * z_mag; term_prec = prec + term_mag; term_prec = FLINT_MIN(term_prec, prec); term_prec = FLINT_MAX(term_prec, 10); if (prec > 2000) { fmprb_set_round(t, zinv2, term_prec); fmprb_mul(s, s, t, term_prec); } else fmprb_mul(s, s, zinv2, term_prec); gamma_stirling_coeff(b, k, digamma, term_prec); fmprb_add(s, s, b, term_prec); } if (digamma) fmprb_mul(s, s, zinv2, prec); else fmprb_mul(s, s, zinv, prec); } /* remainder bound */ fmpr_init(err); gamma_stirling_bound_fmprb(err, z, digamma ? 1 : 0, 1, nterms); fmprb_add_error_fmpr(s, err); fmpr_clear(err); if (digamma) { fmprb_neg(s, s); fmprb_mul_2exp_si(zinv, zinv, -1); fmprb_sub(s, s, zinv, prec); fmprb_add(s, s, logz, prec); } else { /* (z-0.5)*log(z) - z + log(2*pi)/2 */ fmprb_one(t); fmprb_mul_2exp_si(t, t, -1); fmprb_sub(t, z, t, prec); fmprb_mul(t, logz, t, prec); fmprb_add(s, s, t, prec); fmprb_sub(s, s, z, prec); fmprb_const_log_sqrt2pi(t, prec); fmprb_add(s, s, t, prec); } fmprb_clear(t); fmprb_clear(b); fmprb_clear(zinv); fmprb_clear(zinv2); fmprb_clear(logz); }