void _fmprb_poly_evaluate_rectangular(fmprb_t y, fmprb_srcptr poly, long len, const fmprb_t x, long prec) { long i, j, m, r; fmprb_ptr xs; fmprb_t s, t, c; if (len < 3) { if (len == 0) { fmprb_zero(y); } else if (len == 1) { fmprb_set_round(y, poly + 0, prec); } else if (len == 2) { fmprb_mul(y, x, poly + 1, prec); fmprb_add(y, y, poly + 0, prec); } return; } m = n_sqrt(len) + 1; r = (len + m - 1) / m; xs = _fmprb_vec_init(m + 1); fmprb_init(s); fmprb_init(t); fmprb_init(c); _fmprb_vec_set_powers(xs, x, m + 1, prec); fmprb_set(y, poly + (r - 1) * m); for (j = 1; (r - 1) * m + j < len; j++) fmprb_addmul(y, xs + j, poly + (r - 1) * m + j, prec); for (i = r - 2; i >= 0; i--) { fmprb_set(s, poly + i * m); for (j = 1; j < m; j++) fmprb_addmul(s, xs + j, poly + i * m + j, prec); fmprb_mul(y, y, xs + m, prec); fmprb_add(y, y, s, prec); } _fmprb_vec_clear(xs, m + 1); fmprb_clear(s); fmprb_clear(t); fmprb_clear(c); }
void fmprb_agm(fmprb_t z, const fmprb_t x, const fmprb_t y, long prec) { fmprb_t t, u, v, w; if (fmprb_contains_negative(x) || fmprb_contains_negative(y)) { fmprb_indeterminate(z); return; } if (fmprb_is_zero(x) || fmprb_is_zero(y)) { fmprb_zero(z); return; } fmprb_init(t); fmprb_init(u); fmprb_init(v); fmprb_init(w); fmprb_set(t, x); fmprb_set(u, y); while (!fmprb_overlaps(t, u) && !fmprb_contains_nonpositive(t) && !fmprb_contains_nonpositive(u)) { fmprb_add(v, t, u, prec); fmprb_mul_2exp_si(v, v, -1); fmprb_mul(w, t, u, prec); fmprb_sqrt(w, w, prec); fmprb_swap(v, t); fmprb_swap(w, u); } if (!fmprb_is_finite(t) || !fmprb_is_finite(u)) { fmprb_indeterminate(z); } else { fmprb_union(z, t, u, prec); } fmprb_clear(t); fmprb_clear(u); fmprb_clear(v); fmprb_clear(w); }
int fmprb_mat_lu(long * P, fmprb_mat_t LU, const fmprb_mat_t A, long prec) { fmprb_t d, e; fmprb_ptr * a; long i, j, m, n, r, row, col; int result; m = fmprb_mat_nrows(A); n = fmprb_mat_ncols(A); result = 1; if (m == 0 || n == 0) return result; fmprb_mat_set(LU, A); a = LU->rows; row = col = 0; for (i = 0; i < m; i++) P[i] = i; fmprb_init(d); fmprb_init(e); while (row < m && col < n) { r = fmprb_mat_find_pivot_partial(LU, row, m, col); if (r == -1) { result = 0; break; } else if (r != row) fmprb_mat_swap_rows(LU, P, row, r); fmprb_set(d, a[row] + col); for (j = row + 1; j < m; j++) { fmprb_div(e, a[j] + col, d, prec); fmprb_neg(e, e); _fmprb_vec_scalar_addmul(a[j] + col, a[row] + col, n - col, e, prec); fmprb_zero(a[j] + col); fmprb_neg(a[j] + row, e); } row++; col++; } fmprb_clear(d); fmprb_clear(e); return result; }
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 fmprb_zeta(fmprb_t y, const fmprb_t s, long prec) { fmpcb_t t; fmpcb_init(t); fmpcb_set_fmprb(t, s), fmpcb_zeta(t, t, prec); fmprb_set(y, fmpcb_realref(t)); fmpcb_clear(t); }
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 _fmprb_poly_shift_left(fmprb_ptr res, fmprb_srcptr poly, long len, long n) { long i; /* Copy in reverse to avoid writing over unshifted coefficients */ if (res != poly) { for (i = len; i--; ) fmprb_set(res + n + i, poly + i); } else { for (i = len; i--; ) fmprb_swap(res + n + i, res + i); } for (i = 0; i < n; i++) fmprb_zero(res + i); }
static __inline__ void fmprb_nonnegative_part(fmprb_t z, const fmprb_t x, slong prec) { if (fmprb_contains_negative(x)) { fmpr_add(fmprb_midref(z), fmprb_midref(x), fmprb_radref(x), prec, FMPR_RND_CEIL); if (fmpr_sgn(fmprb_midref(z)) <= 0) { fmpr_zero(fmprb_radref(z)); } else { fmpr_mul_2exp_si(fmprb_midref(z), fmprb_midref(z), -1); fmpr_set(fmprb_midref(z), fmprb_radref(z)); } } else { fmprb_set(z, x); } }
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); }
void _fmprb_poly_evaluate_horner(fmprb_t y, fmprb_srcptr f, long len, const fmprb_t x, long prec) { if (len == 0) { fmprb_zero(y); } else if (len == 1 || fmprb_is_zero(x)) { fmprb_set_round(y, f, prec); } else if (len == 2) { fmprb_mul(y, x, f + 1, prec); fmprb_add(y, y, f + 0, prec); } else { long i = len - 1; fmprb_t t, u; fmprb_init(t); fmprb_init(u); fmprb_set(u, f + i); for (i = len - 2; i >= 0; i--) { fmprb_mul(t, u, x, prec); fmprb_add(u, f + i, t, prec); } fmprb_swap(y, u); fmprb_clear(t); 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); }
int main() { long iter; flint_rand_t state; printf("digamma...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 3000; iter++) { fmprb_t a, b, c; long prec1, prec2; prec1 = 2 + n_randint(state, 1000); prec2 = prec1 + 30; fmprb_init(a); fmprb_init(b); fmprb_init(c); fmprb_randtest_precise(a, state, 1 + n_randint(state, 1000), 10); fmprb_digamma(b, a, prec1); fmprb_digamma(c, a, prec2); if (!fmprb_overlaps(b, c)) { printf("FAIL: overlap\n\n"); printf("a = "); fmprb_print(a); printf("\n\n"); printf("b = "); fmprb_print(b); printf("\n\n"); printf("c = "); fmprb_print(c); printf("\n\n"); abort(); } fmprb_set(c, a); fmprb_digamma(c, c, prec2); if (!fmprb_overlaps(b, c)) { printf("FAIL: aliasing\n\n"); printf("a = "); fmprb_print(a); printf("\n\n"); printf("b = "); fmprb_print(b); printf("\n\n"); printf("c = "); fmprb_print(c); printf("\n\n"); abort(); } /* check digamma(z+1) = digamma(z) + 1/z */ fmprb_inv(c, a, prec1); fmprb_add(b, b, c, prec1); fmprb_add_ui(c, a, 1, prec1); fmprb_digamma(c, c, prec1); if (!fmprb_overlaps(b, c)) { printf("FAIL: functional equation\n\n"); printf("a = "); fmprb_print(a); printf("\n\n"); printf("b = "); fmprb_print(b); printf("\n\n"); printf("c = "); fmprb_print(c); printf("\n\n"); abort(); } fmprb_clear(a); fmprb_clear(b); fmprb_clear(c); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
void _fmprb_poly_compose_divconquer(fmprb_ptr res, fmprb_srcptr poly1, long len1, fmprb_srcptr poly2, long len2, long prec) { long i, j, k, n; long *hlen, alloc, powlen; fmprb_ptr v, pow, temp; fmprb_ptr * h; if (len1 == 1) { fmprb_set(res, poly1); return; } if (len2 == 1) { _fmprb_poly_evaluate(res, poly1, len1, poly2, prec); return; } if (len1 == 2) { _fmprb_poly_compose_horner(res, poly1, len1, poly2, len2, prec); return; } /* Initialisation */ hlen = (long *) flint_malloc(((len1 + 1) / 2) * sizeof(long)); for (k = 1; (2 << k) < len1; k++) ; hlen[0] = hlen[1] = ((1 << k) - 1) * (len2 - 1) + 1; for (i = k - 1; i > 0; i--) { long hi = (len1 + (1 << i) - 1) / (1 << i); for (n = (hi + 1) / 2; n < hi; n++) hlen[n] = ((1 << i) - 1) * (len2 - 1) + 1; } powlen = (1 << k) * (len2 - 1) + 1; alloc = 0; for (i = 0; i < (len1 + 1) / 2; i++) alloc += hlen[i]; v = _fmprb_vec_init(alloc + 2 * powlen); h = (fmprb_ptr *) flint_malloc(((len1 + 1) / 2) * sizeof(fmprb_ptr)); h[0] = v; for (i = 0; i < (len1 - 1) / 2; i++) { h[i + 1] = h[i] + hlen[i]; hlen[i] = 0; } hlen[(len1 - 1) / 2] = 0; pow = v + alloc; temp = pow + powlen; /* Let's start the actual work */ for (i = 0, j = 0; i < len1 / 2; i++, j += 2) { if (!fmprb_is_zero(poly1 + j + 1)) { _fmprb_vec_scalar_mul(h[i], poly2, len2, poly1 + j + 1, prec); fmprb_add(h[i], h[i], poly1 + j, prec); hlen[i] = len2; } else if (!fmprb_is_zero(poly1 + j)) { fmprb_set(h[i], poly1 + j); hlen[i] = 1; } } if ((len1 & 1L)) { if (!fmprb_is_zero(poly1 + j)) { fmprb_set(h[i], poly1 + j); hlen[i] = 1; } } _fmprb_poly_mul(pow, poly2, len2, poly2, len2, prec); powlen = 2 * len2 - 1; for (n = (len1 + 1) / 2; n > 2; n = (n + 1) / 2) { if (hlen[1] > 0) { long templen = powlen + hlen[1] - 1; _fmprb_poly_mul(temp, pow, powlen, h[1], hlen[1], prec); _fmprb_poly_add(h[0], temp, templen, h[0], hlen[0], prec); hlen[0] = FLINT_MAX(hlen[0], templen); } for (i = 1; i < n / 2; i++) { if (hlen[2*i + 1] > 0) { _fmprb_poly_mul(h[i], pow, powlen, h[2*i + 1], hlen[2*i + 1], prec); hlen[i] = hlen[2*i + 1] + powlen - 1; } else hlen[i] = 0; _fmprb_poly_add(h[i], h[i], hlen[i], h[2*i], hlen[2*i], prec); hlen[i] = FLINT_MAX(hlen[i], hlen[2*i]); } if ((n & 1L)) { _fmprb_vec_set(h[i], h[2*i], hlen[2*i]); hlen[i] = hlen[2*i]; } _fmprb_poly_mul(temp, pow, powlen, pow, powlen, prec); powlen += powlen - 1; { fmprb_ptr t = pow; pow = temp; temp = t; } } _fmprb_poly_mul(res, pow, powlen, h[1], hlen[1], prec); _fmprb_vec_add(res, res, h[0], hlen[0], prec); _fmprb_vec_clear(v, alloc + 2 * powlen); flint_free(h); flint_free(hlen); }
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); }
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 _fmprb_poly_evaluate_vec_fast_precomp(fmprb_ptr vs, fmprb_srcptr poly, long plen, fmprb_ptr * tree, long len, long prec) { long height, i, j, pow, left; long tree_height; long tlen; fmprb_ptr t, u, swap, pa, pb, pc; /* avoid worrying about some degenerate cases */ if (len < 2 || plen < 2) { if (len == 1) { fmprb_t tmp; fmprb_init(tmp); fmprb_neg(tmp, tree[0] + 0); _fmprb_poly_evaluate(vs + 0, poly, plen, tmp, prec); fmprb_clear(tmp); } else if (len != 0 && plen == 0) { _fmprb_vec_zero(vs, len); } else if (len != 0 && plen == 1) { for (i = 0; i < len; i++) fmprb_set(vs + i, poly + 0); } return; } t = _fmprb_vec_init(len); u = _fmprb_vec_init(len); left = len; /* Initial reduction. We allow the polynomial to be larger or smaller than the number of points. */ height = FLINT_BIT_COUNT(plen - 1) - 1; tree_height = FLINT_CLOG2(len); while (height >= tree_height) height--; pow = 1L << height; for (i = j = 0; i < len; i += pow, j += (pow + 1)) { tlen = ((i + pow) <= len) ? pow : len % pow; _fmprb_poly_rem(t + i, poly, plen, tree[height] + j, tlen + 1, prec); } for (i = height - 1; i >= 0; i--) { pow = 1L << i; left = len; pa = tree[i]; pb = t; pc = u; while (left >= 2 * pow) { _fmprb_poly_rem_2(pc, pb, 2 * pow, pa, pow + 1, prec); _fmprb_poly_rem_2(pc + pow, pb, 2 * pow, pa + pow + 1, pow + 1, prec); pa += 2 * pow + 2; pb += 2 * pow; pc += 2 * pow; left -= 2 * pow; } if (left > pow) { _fmprb_poly_rem(pc, pb, left, pa, pow + 1, prec); _fmprb_poly_rem(pc + pow, pb, left, pa + pow + 1, left - pow + 1, prec); } else if (left > 0) _fmprb_vec_set(pc, pb, left); swap = t; t = u; u = swap; } _fmprb_vec_set(vs, t, len); _fmprb_vec_clear(t, len); _fmprb_vec_clear(u, len); }
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); }
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); }