void _fmprb_poly_product_roots(fmprb_ptr poly, fmprb_srcptr xs, long n, long prec) { if (n == 0) { fmprb_one(poly); } else if (n == 1) { fmprb_neg(poly, xs); fmprb_one(poly + 1); } else if (n == 2) { fmprb_mul(poly, xs + 0, xs + 1, prec); fmprb_add(poly + 1, xs + 0, xs + 1, prec); fmprb_neg(poly + 1, poly + 1); fmprb_one(poly + 2); } else { const long m = (n + 1) / 2; fmprb_ptr tmp; tmp = _fmprb_vec_init(n + 2); _fmprb_poly_product_roots(tmp, xs, m, prec); _fmprb_poly_product_roots(tmp + m + 1, xs + m, n - m, prec); _fmprb_poly_mul_monic(poly, tmp, m + 1, tmp + m + 1, n - m + 1, prec); _fmprb_vec_clear(tmp, n + 2); } }
void fmprb_mat_det(fmprb_t det, const fmprb_mat_t A, long prec) { long n = fmprb_mat_nrows(A); if (n == 0) { fmprb_one(det); } else if (n == 1) { fmprb_set(det, fmprb_mat_entry(A, 0, 0)); } else if (n == 2) { fmprb_mul(det, fmprb_mat_entry(A, 0, 0), fmprb_mat_entry(A, 1, 1), prec); fmprb_submul(det, fmprb_mat_entry(A, 0, 1), fmprb_mat_entry(A, 1, 0), prec); } else { fmprb_mat_t T; fmprb_mat_init(T, fmprb_mat_nrows(A), fmprb_mat_ncols(A)); fmprb_mat_set(T, A); fmprb_mat_det_inplace(det, T, prec); fmprb_mat_clear(T); } }
void bound_K(fmprb_t C, const fmprb_t AN, const fmprb_t B, const fmprb_t T, long wp) { if (fmprb_is_zero(B) || fmprb_is_zero(T)) { fmprb_one(C); } else { fmprb_div(C, B, AN, wp); /* TODO: atan is dumb, should also bound by pi/2 */ fmprb_atan(C, C, wp); fmprb_mul(C, C, T, wp); if (fmprb_is_nonpositive(C)) fmprb_one(C); else fmprb_exp(C, C, wp); } }
int sin_x(fmprb_ptr out, const fmprb_t inp, void * params, long order, long prec) { int xlen = FLINT_MIN(2, order); fmprb_set(out, inp); if (xlen > 1) fmprb_one(out + 1); _fmprb_poly_sin_series(out, out, xlen, order, prec); eval_count++; return 0; }
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); }
void gamma_rising_fmprb_ui_bsplit_eight(fmprb_t y, const fmprb_t x, ulong n, long prec) { if (n == 0) { fmprb_one(y); } else if (n == 1) { fmprb_set_round(y, x, prec); } else { ulong k, a; long wp; fmprb_t t, u; wp = FMPR_PREC_ADD(prec, FLINT_BIT_COUNT(n)); fmprb_init(t); fmprb_init(u); if (n >= 8) { bsplit(t, x, 0, (n / 8) * 8, wp); a = (n / 8) * 8; } else { fmprb_set(t, x); a = 1; } for (k = a; k < n; k++) { fmprb_add_ui(u, x, k, wp); fmprb_mul(t, t, u, wp); } fmprb_set_round(y, t, prec); fmprb_clear(t); fmprb_clear(u); } }
int z_function(fmprb_ptr out, const fmprb_t inp, void * params, long order, long prec) { fmprb_struct x[2]; fmprb_init(x); fmprb_init(x + 1); fmprb_set(x, inp); fmprb_one(x + 1); _fmprb_poly_riemann_siegel_z_series(out, x, FLINT_MIN(2, order), order, prec); fmprb_clear(x); fmprb_clear(x + 1); eval_count++; return 0; }
int sin_1x(fmprb_ptr out, const fmprb_t inp, void * params, long order, long prec) { fmprb_ptr x; int xlen = FLINT_MIN(2, order); x = _fmprb_vec_init(xlen); fmprb_set(x, inp); if (xlen > 1) fmprb_one(x + 1); _fmprb_poly_inv_series(out, x, xlen, order, prec); _fmprb_poly_sin_series(out, out, order, order, prec); _fmprb_vec_clear(x, xlen); eval_count++; return 0; }
void bound_rfac(fmprb_ptr F, const fmpcb_t s, ulong n, long len, long wp) { if (len == 1) { fmpcb_rfac_abs_ubound2(fmprb_midref(F + 0), s, n, wp); fmpr_zero(fmprb_radref(F + 0)); } else { fmprb_struct sx[2]; fmprb_init(sx + 0); fmprb_init(sx + 1); fmpcb_abs(sx + 0, s, wp); fmprb_one(sx + 1); _fmprb_vec_zero(F, len); _fmprb_poly_rising_ui_series(F, sx, 2, n, len, wp); fmprb_clear(sx + 0); fmprb_clear(sx + 1); } }
void fmprb_hypgeom_sum(fmprb_t P, fmprb_t Q, const hypgeom_t hyp, long n, long prec) { if (n < 1) { fmprb_zero(P); fmprb_one(Q); } else { fmprb_t B, T; fmprb_init(B); fmprb_init(T); bsplit_recursive_fmprb(P, Q, B, T, hyp, 0, n, 0, prec); if (!fmprb_is_one(B)) fmprb_mul(Q, Q, B, prec); fmprb_swap(P, T); fmprb_clear(B); fmprb_clear(T); } }
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); }
static __inline__ void zeta_coeff_k(zeta_bsplit_t S, long k, long n, long s) { fmprb_set_si(S->D, 2 * (n + k)); fmprb_mul_si(S->D, S->D, n - k, FMPR_PREC_EXACT); fmprb_set_si(S->Q1, k + 1); fmprb_mul_si(S->Q1, S->Q1, 2*k + 1, FMPR_PREC_EXACT); if (k == 0) { fmprb_zero(S->A); fmprb_one(S->Q2); } else { fmprb_set_si(S->A, k % 2 ? 1 : -1); fmprb_mul(S->A, S->A, S->Q1, FMPR_PREC_EXACT); fmprb_ui_pow_ui(S->Q2, k, s, FMPR_PREC_EXACT); } fmprb_mul(S->Q3, S->Q1, S->Q2, FMPR_PREC_EXACT); fmprb_zero(S->B); fmprb_set(S->C, S->Q1); }
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 fmpcb_calc_cauchy_bound(fmprb_t bound, fmpcb_calc_func_t func, void * param, const fmpcb_t x, const fmprb_t radius, long maxdepth, long prec) { long i, n, depth, wp; fmprb_t pi, theta, v, s1, c1, s2, c2, st, ct; fmpcb_t t, u; fmprb_t b; fmprb_init(pi); fmprb_init(theta); fmprb_init(v); fmprb_init(s1); fmprb_init(c1); fmprb_init(s2); fmprb_init(c2); fmprb_init(st); fmprb_init(ct); fmpcb_init(t); fmpcb_init(u); fmprb_init(b); wp = prec + 20; fmprb_const_pi(pi, wp); fmprb_zero_pm_inf(b); for (depth = 0, n = 16; depth < maxdepth; n *= 2, depth++) { fmprb_zero(b); /* theta = 2 pi / n */ fmprb_div_ui(theta, pi, n, wp); fmprb_mul_2exp_si(theta, theta, 1); /* sine and cosine of i*theta and (i+1)*theta */ fmprb_zero(s1); fmprb_one(c1); fmprb_sin_cos(st, ct, theta, wp); fmprb_set(s2, st); fmprb_set(c2, ct); for (i = 0; i < n; i++) { /* sine and cosine of 2 pi ([i,i+1]/n) */ /* since we use power of two subdivision points, the sine and cosine are monotone on each subinterval */ fmprb_union(fmpcb_realref(t), c1, c2, wp); fmprb_union(fmpcb_imagref(t), s1, s2, wp); fmpcb_mul_fmprb(t, t, radius, wp); fmpcb_add(t, t, x, prec); /* next angle */ fmprb_mul(v, c2, ct, wp); fmprb_mul(c1, s2, st, wp); fmprb_sub(c1, v, c1, wp); fmprb_mul(v, c2, st, wp); fmprb_mul(s1, s2, ct, wp); fmprb_add(s1, v, s1, wp); fmprb_swap(c1, c2); fmprb_swap(s1, s2); func(u, t, param, 1, prec); fmpcb_abs(v, u, prec); fmprb_add(b, b, v, prec); } fmprb_div_ui(b, b, n, prec); if (fmprb_is_exact(b) || fmpr_cmp(fmprb_radref(b), fmprb_midref(b)) < 0) break; } fmprb_set(bound, b); fmprb_clear(pi); fmprb_clear(theta); fmprb_clear(v); fmpcb_clear(t); fmpcb_clear(u); fmprb_clear(b); fmprb_clear(s1); fmprb_clear(c1); fmprb_clear(s2); fmprb_clear(c2); fmprb_clear(st); fmprb_clear(ct); }
void gamma_rising_fmprb_ui_delta(fmprb_t y, const fmprb_t x, ulong n, ulong m, long prec) { fmprb_ptr xs; fmprb_t t, u, v; ulong i, k, rem; fmpz_t c, h; fmpz *s, *d; long wp; if (n == 0) { fmprb_one(y); return; } if (n == 1) { fmprb_set_round(y, x, prec); return; } wp = FMPR_PREC_ADD(prec, FLINT_BIT_COUNT(n)); fmprb_init(t); fmprb_init(u); fmprb_init(v); fmpz_init(c); fmpz_init(h); if (m == 0) { ulong m1, m2; m1 = 0.2 * pow(wp, 0.4); m2 = n_sqrt(n); m = FLINT_MIN(m1, m2); } m = FLINT_MIN(m, n); m = FLINT_MAX(m, 1); xs = _fmprb_vec_init(m + 1); d = _fmpz_vec_init(m * m); s = _fmpz_vec_init(m + 1); _fmprb_vec_set_powers(xs, x, m + 1, wp); rising_difference_polynomial(s, d, m); /* tail */ rem = m; while (rem + m <= n) rem += m; fmprb_one(y); for (k = rem; k < n; k++) { fmprb_add_ui(t, xs + 1, k, wp); fmprb_mul(y, y, t, wp); } /* initial rising factorial */ fmprb_zero(t); for (i = 1; i <= m; i++) fmprb_addmul_fmpz(t, xs + i, s + i, wp); fmprb_mul(y, y, t, wp); /* the leading coefficient is always the same */ fmprb_mul_fmpz(xs + m - 1, xs + m - 1, d + m - 1 + 0, wp); for (k = 0; k + 2 * m <= n; k += m) { for (i = 0; i < m - 1; i++) { fmpz_set_ui(h, k); _fmpz_poly_evaluate_horner_fmpz(c, d + i * m, m - i, h); if (i == 0) fmprb_add_fmpz(t, t, c, wp); else fmprb_addmul_fmpz(t, xs + i, c, wp); } fmprb_add(t, t, xs + m - 1, wp); fmprb_mul(y, y, t, wp); } fmprb_set_round(y, y, prec); fmprb_clear(t); fmprb_clear(u); fmprb_clear(v); _fmprb_vec_clear(xs, m + 1); _fmpz_vec_clear(d, m * m); _fmpz_vec_clear(s, m + 1); fmpz_clear(c); fmpz_clear(h); }
void _fmprb_poly_rgamma_series(fmprb_ptr res, fmprb_srcptr h, long hlen, long len, long prec) { int reflect; long i, rflen, r, n, wp; fmprb_ptr t, u, v; fmprb_struct f[2]; hlen = FLINT_MIN(hlen, len); wp = prec + FLINT_BIT_COUNT(prec); t = _fmprb_vec_init(len); u = _fmprb_vec_init(len); v = _fmprb_vec_init(len); fmprb_init(f); fmprb_init(f + 1); /* use zeta values at small integers */ if (fmprb_is_int(h) && (fmpr_cmpabs_ui(fmprb_midref(h), prec / 2) < 0)) { r = fmpr_get_si(fmprb_midref(h), FMPR_RND_DOWN); gamma_lgamma_series_at_one(u, len, wp); _fmprb_vec_neg(u, u, len); _fmprb_poly_exp_series(t, u, len, len, wp); if (r == 1) { _fmprb_vec_swap(v, t, len); } else if (r <= 0) { fmprb_set(f, h); fmprb_one(f + 1); rflen = FLINT_MIN(len, 2 - r); _fmprb_poly_rising_ui_series(u, f, FLINT_MIN(2, len), 1 - r, rflen, wp); _fmprb_poly_mullow(v, t, len, u, rflen, len, wp); } else { fmprb_one(f); fmprb_one(f + 1); rflen = FLINT_MIN(len, r); _fmprb_poly_rising_ui_series(v, f, FLINT_MIN(2, len), r - 1, rflen, wp); /* TODO: use div_series? */ _fmprb_poly_inv_series(u, v, rflen, len, wp); _fmprb_poly_mullow(v, t, len, u, len, len, wp); } } else { /* otherwise use Stirling series */ gamma_stirling_choose_param_fmprb(&reflect, &r, &n, h, 1, 0, wp); /* rgamma(h) = (gamma(1-h+r) sin(pi h)) / (rf(1-h, r) * pi), h = h0 + t*/ if (reflect) { /* u = gamma(r+1-h) */ fmprb_sub_ui(f, h, r + 1, wp); fmprb_neg(f, f); gamma_stirling_eval_fmprb_series(t, f, n, len, wp); _fmprb_poly_exp_series(u, t, len, len, wp); for (i = 1; i < len; i += 2) fmprb_neg(u + i, u + i); /* v = sin(pi x) */ fmprb_const_pi(f + 1, wp); fmprb_mul(f, h, f + 1, wp); _fmprb_poly_sin_series(v, f, 2, len, wp); _fmprb_poly_mullow(t, u, len, v, len, len, wp); /* rf(1-h,r) * pi */ if (r == 0) { fmprb_const_pi(u, wp); _fmprb_vec_scalar_div(v, t, len, u, wp); } else { fmprb_sub_ui(f, h, 1, wp); fmprb_neg(f, f); fmprb_set_si(f + 1, -1); rflen = FLINT_MIN(len, r + 1); _fmprb_poly_rising_ui_series(v, f, FLINT_MIN(2, len), r, rflen, wp); fmprb_const_pi(u, wp); _fmprb_vec_scalar_mul(v, v, rflen, u, wp); /* divide by rising factorial */ /* TODO: might better to use div_series, when it has a good basecase */ _fmprb_poly_inv_series(u, v, rflen, len, wp); _fmprb_poly_mullow(v, t, len, u, len, len, wp); } } else { /* rgamma(h) = rgamma(h+r) rf(h,r) */ if (r == 0) { fmprb_add_ui(f, h, r, wp); gamma_stirling_eval_fmprb_series(t, f, n, len, wp); _fmprb_vec_neg(t, t, len); _fmprb_poly_exp_series(v, t, len, len, wp); } else { fmprb_set(f, h); fmprb_one(f + 1); rflen = FLINT_MIN(len, r + 1); _fmprb_poly_rising_ui_series(t, f, FLINT_MIN(2, len), r, rflen, wp); fmprb_add_ui(f, h, r, wp); gamma_stirling_eval_fmprb_series(v, f, n, len, wp); _fmprb_vec_neg(v, v, len); _fmprb_poly_exp_series(u, v, len, len, wp); _fmprb_poly_mullow(v, u, len, t, rflen, len, wp); } } } /* compose with nonconstant part */ fmprb_zero(t); _fmprb_vec_set(t + 1, h + 1, hlen - 1); _fmprb_poly_compose_series(res, v, len, t, hlen, len, prec); fmprb_clear(f); fmprb_clear(f + 1); _fmprb_vec_clear(t, len); _fmprb_vec_clear(u, len); _fmprb_vec_clear(v, len); }