void _acb_poly_interpolate_fast_precomp(acb_ptr poly, acb_srcptr ys, acb_ptr * tree, acb_srcptr weights, slong len, slong prec) { acb_ptr t, u, pa, pb; slong i, pow, left; if (len == 0) return; t = _acb_vec_init(len); u = _acb_vec_init(len); for (i = 0; i < len; i++) acb_mul(poly + i, weights + i, ys + i, prec); for (i = 0; i < FLINT_CLOG2(len); i++) { pow = (WORD(1) << i); pa = tree[i]; pb = poly; left = len; while (left >= 2 * pow) { _acb_poly_mul(t, pa, pow + 1, pb + pow, pow, prec); _acb_poly_mul(u, pa + pow + 1, pow + 1, pb, pow, prec); _acb_vec_add(pb, t, u, 2 * pow, prec); left -= 2 * pow; pa += 2 * pow + 2; pb += 2 * pow; } if (left > pow) { _acb_poly_mul(t, pa, pow + 1, pb + pow, left - pow, prec); _acb_poly_mul(u, pb, pow, pa + pow + 1, left - pow + 1, prec); _acb_vec_add(pb, t, u, left, prec); } } _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
void _acb_poly_powsum_one_series_sieved(acb_ptr z, const acb_t s, slong n, slong len, slong prec) { slong * divisors; slong powers_alloc; slong i, j, k, ibound, kprev, power_of_two, horner_point; int critical_line, integer; acb_ptr powers; acb_ptr t, u, x; acb_ptr p1, p2; arb_t logk, v, w; critical_line = arb_is_exact(acb_realref(s)) && (arf_cmp_2exp_si(arb_midref(acb_realref(s)), -1) == 0); integer = arb_is_zero(acb_imagref(s)) && arb_is_int(acb_realref(s)); divisors = flint_calloc(n / 2 + 1, sizeof(slong)); powers_alloc = (n / 6 + 1) * len; powers = _acb_vec_init(powers_alloc); ibound = n_sqrt(n); for (i = 3; i <= ibound; i += 2) if (DIVISOR(i) == 0) for (j = i * i; j <= n; j += 2 * i) DIVISOR(j) = i; t = _acb_vec_init(len); u = _acb_vec_init(len); x = _acb_vec_init(len); arb_init(logk); arb_init(v); arb_init(w); power_of_two = 1; while (power_of_two * 2 <= n) power_of_two *= 2; horner_point = n / power_of_two; _acb_vec_zero(z, len); kprev = 0; COMPUTE_POWER(x, 2, kprev); for (k = 1; k <= n; k += 2) { /* t = k^(-s) */ if (DIVISOR(k) == 0) { COMPUTE_POWER(t, k, kprev); } else { p1 = POWER(DIVISOR(k)); p2 = POWER(k / DIVISOR(k)); if (len == 1) acb_mul(t, p1, p2, prec); else _acb_poly_mullow(t, p1, len, p2, len, len, prec); } if (k * 3 <= n) _acb_vec_set(POWER(k), t, len); _acb_vec_add(u, u, t, len, prec); while (k == horner_point && power_of_two != 1) { _acb_poly_mullow(t, z, len, x, len, len, prec); _acb_vec_add(z, t, u, len, prec); power_of_two /= 2; horner_point = n / power_of_two; horner_point -= (horner_point % 2 == 0); } } _acb_poly_mullow(t, z, len, x, len, len, prec); _acb_vec_add(z, t, u, len, prec); flint_free(divisors); _acb_vec_clear(powers, powers_alloc); _acb_vec_clear(t, len); _acb_vec_clear(u, len); _acb_vec_clear(x, len); arb_clear(logk); arb_clear(v); arb_clear(w); }
void _acb_poly_zeta_cpx_reflect(acb_ptr t, const acb_t h, const acb_t a, int deflate, slong len, slong prec) { /* use reflection formula */ if (arf_sgn(arb_midref(acb_realref(h))) < 0 && acb_is_one(a)) { /* zeta(s) = (2*pi)**s * sin(pi*s/2) / pi * gamma(1-s) * zeta(1-s) */ acb_t pi, hcopy; acb_ptr f, s1, s2, s3, s4, u; slong i; acb_init(pi); acb_init(hcopy); f = _acb_vec_init(2); s1 = _acb_vec_init(len); s2 = _acb_vec_init(len); s3 = _acb_vec_init(len); s4 = _acb_vec_init(len); u = _acb_vec_init(len); acb_set(hcopy, h); acb_const_pi(pi, prec); /* s1 = (2*pi)**s */ acb_mul_2exp_si(pi, pi, 1); _acb_poly_pow_cpx(s1, pi, h, len, prec); acb_mul_2exp_si(pi, pi, -1); /* s2 = sin(pi*s/2) / pi */ acb_set(f, h); acb_one(f + 1); acb_mul_2exp_si(f, f, -1); acb_mul_2exp_si(f + 1, f + 1, -1); _acb_poly_sin_pi_series(s2, f, 2, len, prec); _acb_vec_scalar_div(s2, s2, len, pi, prec); /* s3 = gamma(1-s) */ acb_sub_ui(f, hcopy, 1, prec); acb_neg(f, f); acb_set_si(f + 1, -1); _acb_poly_gamma_series(s3, f, 2, len, prec); /* s4 = zeta(1-s) */ acb_sub_ui(f, hcopy, 1, prec); acb_neg(f, f); _acb_poly_zeta_cpx_series(s4, f, a, 0, len, prec); for (i = 1; i < len; i += 2) acb_neg(s4 + i, s4 + i); _acb_poly_mullow(u, s1, len, s2, len, len, prec); _acb_poly_mullow(s1, s3, len, s4, len, len, prec); _acb_poly_mullow(t, u, len, s1, len, len, prec); /* add 1/(1-(s+t)) = 1/(1-s) + t/(1-s)^2 + ... */ if (deflate) { acb_sub_ui(u, hcopy, 1, prec); acb_neg(u, u); acb_inv(u, u, prec); for (i = 1; i < len; i++) acb_mul(u + i, u + i - 1, u, prec); _acb_vec_add(t, t, u, len, prec); } acb_clear(pi); acb_clear(hcopy); _acb_vec_clear(f, 2); _acb_vec_clear(s1, len); _acb_vec_clear(s2, len); _acb_vec_clear(s3, len); _acb_vec_clear(s4, len); _acb_vec_clear(u, len); } else { _acb_poly_zeta_cpx_series(t, h, a, deflate, len, prec); } }
void _acb_poly_zeta_em_tail_naive(acb_ptr sum, const acb_t s, const acb_t Na, acb_srcptr Nasx, slong M, slong d, slong prec) { acb_ptr u, term; acb_t Na2, splus, rec; arb_t x; fmpz_t c; int aint; slong r; BERNOULLI_ENSURE_CACHED(2 * M); u = _acb_vec_init(d); term = _acb_vec_init(d); acb_init(splus); acb_init(rec); acb_init(Na2); arb_init(x); fmpz_init(c); _acb_vec_zero(sum, d); /* u = 1/2 * Nasx */ _acb_vec_scalar_mul_2exp_si(u, Nasx, d, -WORD(1)); /* term = u * (s+x) / (N+a) */ _acb_poly_mullow_cpx(u, u, d, s, d, prec); _acb_vec_scalar_div(term, u, d, Na, prec); /* (N+a)^2 or 1/(N+a)^2 */ acb_mul(Na2, Na, Na, prec); aint = acb_is_int(Na2); if (!aint) acb_inv(Na2, Na2, prec); for (r = 1; r <= M; r++) { /* flint_printf("sum 2: %wd %wd\n", r, M); */ /* sum += bernoulli number * term */ arb_set_round_fmpz(x, fmpq_numref(bernoulli_cache + 2 * r), prec); arb_div_fmpz(x, x, fmpq_denref(bernoulli_cache + 2 * r), prec); _acb_vec_scalar_mul_arb(u, term, d, x, prec); _acb_vec_add(sum, sum, u, d, prec); /* multiply term by ((s+x)+2r-1)((s+x)+2r) / ((N+a)^2 * (2*r+1)*(2*r+2)) */ acb_set(splus, s); arb_add_ui(acb_realref(splus), acb_realref(splus), 2*r-1, prec); _acb_poly_mullow_cpx(term, term, d, splus, d, prec); arb_add_ui(acb_realref(splus), acb_realref(splus), 1, prec); _acb_poly_mullow_cpx(term, term, d, splus, d, prec); /* TODO: combine with previous multiplication? */ if (aint) { arb_mul_ui(x, acb_realref(Na2), 2*r+1, prec); arb_mul_ui(x, x, 2*r+2, prec); _acb_vec_scalar_div_arb(term, term, d, x, prec); } else { fmpz_set_ui(c, 2*r+1); fmpz_mul_ui(c, c, 2*r+2); acb_div_fmpz(rec, Na2, c, prec); _acb_vec_scalar_mul(term, term, d, rec, prec); } } _acb_vec_clear(u, d); _acb_vec_clear(term, d); acb_clear(splus); acb_clear(rec); acb_clear(Na2); arb_clear(x); fmpz_clear(c); }
void _acb_poly_zeta_em_sum(acb_ptr z, const acb_t s, const acb_t a, int deflate, ulong N, ulong M, slong d, slong prec) { acb_ptr t, u, v, term, sum; acb_t Na, one; slong i; t = _acb_vec_init(d + 1); u = _acb_vec_init(d); v = _acb_vec_init(d); term = _acb_vec_init(d); sum = _acb_vec_init(d); acb_init(Na); acb_init(one); prec += 2 * (FLINT_BIT_COUNT(N) + FLINT_BIT_COUNT(d)); acb_one(one); /* sum 1/(k+a)^(s+x) */ if (acb_is_one(a) && d <= 3) _acb_poly_powsum_one_series_sieved(sum, s, N, d, prec); else if (N > 50 && flint_get_num_threads() > 1) _acb_poly_powsum_series_naive_threaded(sum, s, a, one, N, d, prec); else _acb_poly_powsum_series_naive(sum, s, a, one, N, d, prec); /* t = 1/(N+a)^(s+x); we might need one extra term for deflation */ acb_add_ui(Na, a, N, prec); _acb_poly_acb_invpow_cpx(t, Na, s, d + 1, prec); /* sum += (N+a) * 1/((s+x)-1) * t */ if (!deflate) { /* u = (N+a)^(1-(s+x)) */ acb_sub_ui(v, s, 1, prec); _acb_poly_acb_invpow_cpx(u, Na, v, d, prec); /* divide by 1/((s-1) + x) */ acb_sub_ui(v, s, 1, prec); acb_div(u, u, v, prec); for (i = 1; i < d; i++) { acb_sub(u + i, u + i, u + i - 1, prec); acb_div(u + i, u + i, v, prec); } _acb_vec_add(sum, sum, u, d, prec); } /* sum += ((N+a)^(1-(s+x)) - 1) / ((s+x) - 1) */ else { /* at s = 1, this becomes (N*t - 1)/x, i.e. just remove one coeff */ if (acb_is_one(s)) { for (i = 0; i < d; i++) acb_mul(u + i, t + i + 1, Na, prec); _acb_vec_add(sum, sum, u, d, prec); } else { /* TODO: this is numerically unstable for large derivatives, and divides by zero if s contains 1. We want a good way to evaluate the power series ((N+a)^y - 1) / y where y has nonzero constant term, without doing a division. How is this best done? */ _acb_vec_scalar_mul(t, t, d, Na, prec); acb_sub_ui(t + 0, t + 0, 1, prec); acb_sub_ui(u + 0, s, 1, prec); acb_inv(u + 0, u + 0, prec); for (i = 1; i < d; i++) acb_mul(u + i, u + i - 1, u + 0, prec); for (i = 1; i < d; i += 2) acb_neg(u + i, u + i); _acb_poly_mullow(v, u, d, t, d, d, prec); _acb_vec_add(sum, sum, v, d, prec); _acb_poly_acb_invpow_cpx(t, Na, s, d, prec); } } /* sum += u = 1/2 * t */ _acb_vec_scalar_mul_2exp_si(u, t, d, -WORD(1)); _acb_vec_add(sum, sum, u, d, prec); /* Euler-Maclaurin formula tail */ if (d < 5 || d < M / 10) _acb_poly_zeta_em_tail_naive(u, s, Na, t, M, d, prec); else _acb_poly_zeta_em_tail_bsplit(u, s, Na, t, M, d, prec); _acb_vec_add(z, sum, u, d, prec); _acb_vec_clear(t, d + 1); _acb_vec_clear(u, d); _acb_vec_clear(v, d); _acb_vec_clear(term, d); _acb_vec_clear(sum, d); acb_clear(Na); acb_clear(one); }
void _acb_poly_sin_cos_series_tangent(acb_ptr s, acb_ptr c, const acb_srcptr h, slong hlen, slong len, slong prec, int times_pi) { acb_ptr t, u, v; acb_t s0, c0; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { if (times_pi) acb_sin_cos_pi(s, c, h, prec); else acb_sin_cos(s, c, h, prec); _acb_vec_zero(s + 1, len - 1); _acb_vec_zero(c + 1, len - 1); return; } /* sin(x) = 2*tan(x/2)/(1+tan(x/2)^2) cos(x) = (1-tan(x/2)^2)/(1+tan(x/2)^2) */ acb_init(s0); acb_init(c0); t = _acb_vec_init(3 * len); u = t + len; v = u + len; /* sin, cos of h0 */ if (times_pi) acb_sin_cos_pi(s0, c0, h, prec); else acb_sin_cos(s0, c0, h, prec); /* t = tan((h-h0)/2) */ acb_zero(u); _acb_vec_scalar_mul_2exp_si(u + 1, h + 1, hlen - 1, -1); if (times_pi) { acb_const_pi(t, prec); _acb_vec_scalar_mul(u + 1, u + 1, hlen - 1, t, prec); } _acb_poly_tan_series(t, u, hlen, len, prec); /* v = 1 + t^2 */ _acb_poly_mullow(v, t, len, t, len, len, prec); acb_add_ui(v, v, 1, prec); /* u = 1/(1+t^2) */ _acb_poly_inv_series(u, v, len, len, prec); /* sine */ _acb_poly_mullow(s, t, len, u, len, len, prec); _acb_vec_scalar_mul_2exp_si(s, s, len, 1); /* cosine */ acb_sub_ui(v, v, 2, prec); _acb_vec_neg(v, v, len); _acb_poly_mullow(c, v, len, u, len, len, prec); /* sin(h0 + h1) = cos(h0) sin(h1) + sin(h0) cos(h1) cos(h0 + h1) = cos(h0) cos(h1) - sin(h0) sin(h1) */ if (!acb_is_zero(s0)) { _acb_vec_scalar_mul(t, s, len, c0, prec); _acb_vec_scalar_mul(u, c, len, s0, prec); _acb_vec_scalar_mul(v, s, len, s0, prec); _acb_vec_add(s, t, u, len, prec); _acb_vec_scalar_mul(t, c, len, c0, prec); _acb_vec_sub(c, t, v, len, prec); } _acb_vec_clear(t, 3 * len); acb_clear(s0); acb_clear(c0); }