void bernoulli_rev_init(bernoulli_rev_t iter, ulong nmax) { long j; fmpz_t t; fmprb_t x; int round1, round2; long wp; nmax -= (nmax % 2); iter->n = nmax; iter->alloc = 0; if (nmax < BERNOULLI_REV_MIN) return; iter->prec = wp = global_prec(nmax); iter->max_power = zeta_terms(nmax, iter->prec); iter->alloc = iter->max_power + 1; iter->powers = _fmpz_vec_init(iter->alloc); fmpz_init(iter->pow_error); fmprb_init(iter->prefactor); fmprb_init(iter->two_pi_squared); fmprb_init(x); fmpz_init(t); /* precompute powers */ for (j = 3; j <= iter->max_power; j += 2) { fmprb_ui_pow_ui(x, j, nmax, power_prec(j, nmax, wp)); fmprb_ui_div(x, 1UL, x, power_prec(j, nmax, wp)); round1 = fmpr_get_fmpz_fixed_si(t, fmprb_midref(x), -wp); fmpz_set(iter->powers + j, t); /* error: the radius, plus two roundings */ round2 = fmpr_get_fmpz_fixed_si(t, fmprb_radref(x), -wp); fmpz_add_ui(t, t, (round1 != 0) + (round2 != 0)); if (fmpz_cmp(iter->pow_error, t) < 0) fmpz_set(iter->pow_error, t); } /* precompute (2pi)^2 and 2*(n!)/(2pi)^n */ fmprb_fac_ui(iter->prefactor, nmax, wp); fmprb_mul_2exp_si(iter->prefactor, iter->prefactor, 1); fmprb_const_pi(x, wp); fmprb_mul_2exp_si(x, x, 1); fmprb_mul(iter->two_pi_squared, x, x, wp); fmprb_pow_ui(x, iter->two_pi_squared, nmax / 2, wp); fmprb_div(iter->prefactor, iter->prefactor, x, wp); fmpz_clear(t); fmprb_clear(x); }
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); }
void zeta_series_em_vec_bound(fmprb_ptr bound, const fmpcb_t s, const fmpcb_t a, ulong N, ulong M, long len, long wp) { fmprb_t K, C, AN, S2M; fmprb_ptr F, R; long k; fmprb_srcptr alpha = fmpcb_realref(a); fmprb_srcptr beta = fmpcb_imagref(a); fmprb_srcptr sigma = fmpcb_realref(s); fmprb_srcptr tau = fmpcb_imagref(s); fmprb_init(AN); fmprb_init(S2M); /* require alpha + N > 1, sigma + 2M > 1 */ fmprb_add_ui(AN, alpha, N - 1, wp); fmprb_add_ui(S2M, sigma, 2*M - 1, wp); if (!fmprb_is_positive(AN) || !fmprb_is_positive(S2M) || N < 1 || M < 1) { fmprb_clear(AN); fmprb_clear(S2M); for (k = 0; k < len; k++) { fmpr_pos_inf(fmprb_midref(bound + k)); fmpr_zero(fmprb_radref(bound + k)); } return; } /* alpha + N, sigma + 2M */ fmprb_add_ui(AN, AN, 1, wp); fmprb_add_ui(S2M, S2M, 1, wp); R = _fmprb_vec_init(len); F = _fmprb_vec_init(len); fmprb_init(K); fmprb_init(C); /* bound for power integral */ bound_C(C, AN, beta, wp); bound_K(K, AN, beta, tau, wp); bound_I(R, AN, S2M, C, len, wp); for (k = 0; k < len; k++) { fmprb_mul(R + k, R + k, K, wp); fmprb_div_ui(K, K, k + 1, wp); } /* bound for rising factorial */ bound_rfac(F, s, 2*M, len, wp); /* product (TODO: only need upper bound; write a function for this) */ _fmprb_poly_mullow(bound, F, len, R, len, len, wp); /* bound for bernoulli polynomials, 4 / (2pi)^(2M) */ fmprb_const_pi(C, wp); fmprb_mul_2exp_si(C, C, 1); fmprb_pow_ui(C, C, 2 * M, wp); fmprb_ui_div(C, 4, C, wp); _fmprb_vec_scalar_mul(bound, bound, len, C, wp); fmprb_clear(K); fmprb_clear(C); fmprb_clear(AN); fmprb_clear(S2M); _fmprb_vec_clear(R, len); _fmprb_vec_clear(F, len); }
void _fmprb_poly_zeta_series(fmprb_ptr res, fmprb_srcptr h, long hlen, const fmprb_t a, int deflate, long len, long prec) { long i; fmpcb_t cs, ca; fmpcb_ptr z; fmprb_ptr t, u; if (fmprb_contains_nonpositive(a)) { _fmprb_vec_indeterminate(res, len); return; } hlen = FLINT_MIN(hlen, len); z = _fmpcb_vec_init(len); t = _fmprb_vec_init(len); u = _fmprb_vec_init(len); fmpcb_init(cs); fmpcb_init(ca); /* use reflection formula */ if (fmpr_sgn(fmprb_midref(h)) < 0 && fmprb_is_one(a)) { /* zeta(s) = (2*pi)**s * sin(pi*s/2) / pi * gamma(1-s) * zeta(1-s) */ fmprb_t pi; fmprb_ptr f, s1, s2, s3, s4; fmprb_init(pi); f = _fmprb_vec_init(2); s1 = _fmprb_vec_init(len); s2 = _fmprb_vec_init(len); s3 = _fmprb_vec_init(len); s4 = _fmprb_vec_init(len); fmprb_const_pi(pi, prec); /* s1 = (2*pi)**s */ fmprb_mul_2exp_si(pi, pi, 1); _fmprb_poly_pow_cpx(s1, pi, h, len, prec); fmprb_mul_2exp_si(pi, pi, -1); /* s2 = sin(pi*s/2) / pi */ fmprb_mul_2exp_si(pi, pi, -1); fmprb_mul(f, pi, h, prec); fmprb_set(f + 1, pi); fmprb_mul_2exp_si(pi, pi, 1); _fmprb_poly_sin_series(s2, f, 2, len, prec); _fmprb_vec_scalar_div(s2, s2, len, pi, prec); /* s3 = gamma(1-s) */ fmprb_sub_ui(f, h, 1, prec); fmprb_neg(f, f); fmprb_set_si(f + 1, -1); _fmprb_poly_gamma_series(s3, f, 2, len, prec); /* s4 = zeta(1-s) */ fmprb_sub_ui(f, h, 1, prec); fmprb_neg(f, f); fmpcb_set_fmprb(cs, f); fmpcb_one(ca); zeta_series(z, cs, ca, 0, len, prec); for (i = 0; i < len; i++) fmprb_set(s4 + i, fmpcb_realref(z + i)); for (i = 1; i < len; i += 2) fmprb_neg(s4 + i, s4 + i); _fmprb_poly_mullow(u, s1, len, s2, len, len, prec); _fmprb_poly_mullow(s1, s3, len, s4, len, len, prec); _fmprb_poly_mullow(t, u, len, s1, len, len, prec); /* add 1/(1-(s+t)) = 1/(1-s) + t/(1-s)^2 + ... */ if (deflate) { fmprb_sub_ui(u, h, 1, prec); fmprb_neg(u, u); fmprb_ui_div(u, 1, u, prec); for (i = 1; i < len; i++) fmprb_mul(u + i, u + i - 1, u, prec); _fmprb_vec_add(t, t, u, len, prec); } fmprb_clear(pi); _fmprb_vec_clear(f, 2); _fmprb_vec_clear(s1, len); _fmprb_vec_clear(s2, len); _fmprb_vec_clear(s3, len); _fmprb_vec_clear(s4, len); } else { fmpcb_set_fmprb(cs, h); fmpcb_set_fmprb(ca, a); zeta_series(z, cs, ca, deflate, len, prec); for (i = 0; i < len; i++) fmprb_set(t + i, fmpcb_realref(z + i)); } /* compose with nonconstant part */ fmprb_zero(u); _fmprb_vec_set(u + 1, h + 1, hlen - 1); _fmprb_poly_compose_series(res, t, len, u, hlen, len, prec); _fmpcb_vec_clear(z, len); _fmprb_vec_clear(t, len); _fmprb_vec_clear(u, len); fmpcb_init(cs); fmpcb_init(ca); }
static void _fmprb_gamma(fmprb_t y, const fmprb_t x, long prec, int inverse) { int reflect; long r, n, wp; fmprb_t t, u, v; if (fmprb_is_exact(x)) { const fmpr_struct * mid = fmprb_midref(x); if (fmpr_is_special(mid)) { if (!inverse && fmpr_is_pos_inf(mid)) { fmprb_set(y, x); } else if (fmpr_is_nan(mid) || fmpr_is_neg_inf(mid) || !inverse) { fmpr_nan(fmprb_midref(y)); fmpr_pos_inf(fmprb_radref(y)); } else { fmprb_zero(y); } return; } else { const fmpz exp = *fmpr_expref(mid); const fmpz man = *fmpr_manref(mid); /* fast gamma(n), gamma(n/2) or gamma(n/4) */ if (!COEFF_IS_MPZ(exp) && (exp >= -2) && ((double) fmpz_bits(&man) + exp < prec)) { fmpq_t a; fmpq_init(a); fmpr_get_fmpq(a, mid); fmprb_gamma_fmpq(y, a, prec + 2 * inverse); if (inverse) fmprb_ui_div(y, 1, y, prec); fmpq_clear(a); return; } } } wp = prec + FLINT_BIT_COUNT(prec); gamma_stirling_choose_param_fmprb(&reflect, &r, &n, x, 1, 0, wp); fmprb_init(t); fmprb_init(u); fmprb_init(v); if (reflect) { /* gamma(x) = (rf(1-x, r) * pi) / (gamma(1-x+r) sin(pi x)) */ fmprb_sub_ui(t, x, 1, wp); fmprb_neg(t, t); gamma_rising_fmprb_ui_bsplit(u, t, r, wp); fmprb_const_pi(v, wp); fmprb_mul(u, u, v, wp); fmprb_add_ui(t, t, r, wp); gamma_stirling_eval_fmprb(v, t, n, 0, wp); fmprb_exp(v, v, wp); fmprb_sin_pi(t, x, wp); fmprb_mul(v, v, t, wp); } else { /* gamma(x) = gamma(x+r) / rf(x,r) */ fmprb_add_ui(t, x, r, wp); gamma_stirling_eval_fmprb(u, t, n, 0, wp); fmprb_exp(u, u, prec); gamma_rising_fmprb_ui_bsplit(v, x, r, wp); } if (inverse) fmprb_div(y, v, u, prec); else fmprb_div(y, u, v, prec); fmprb_clear(t); fmprb_clear(u); fmprb_clear(v); }