arb/acb_poly/zeta_em_tail_bsplit.c
2016-04-26 17:20:05 +02:00

131 lines
3.2 KiB
C

/*
Copyright (C) 2014 Fredrik Johansson
This file is part of Arb.
Arb is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See <http://www.gnu.org/licenses/>.
*/
#include "acb_poly.h"
#include "bernoulli.h"
static void
bsplit(acb_ptr P, acb_ptr T, const acb_t s, const acb_t Na,
slong a, slong b, int cont, slong len, slong prec)
{
slong plen = FLINT_MIN(2 * (b - a) + 1, len);
if (b - a == 1)
{
slong j = a;
fmpz_t t;
fmpz_init(t);
if (j == 0)
{
acb_set(P, s);
if (len > 1) acb_one(P + 1);
if (len > 2) acb_zero(P + 2);
}
else
{
/* P = ((s+x)+2j-1)(s+x)+2j) */
/* constant term = s^2 + (4j-1)s + (4j^2-2j)*/
acb_mul(P, s, s, prec);
acb_addmul_ui(P, s, 4*j-1, prec);
fmpz_set_ui(t, 2*j);
fmpz_mul_ui(t, t, 2*j-1);
acb_add_fmpz(P, P, t, prec);
/* x term = (2s+4j-1) */
if (len > 1)
{
acb_mul_ui(P + 1, s, 2, prec);
acb_add_ui(P + 1, P + 1, 4*j-1, prec);
}
/* x^2 term = 1 */
if (len > 2)
acb_one(P + 2);
}
/* P = P / ((2j+1)*(2j+2)) */
fmpz_set_ui(t, 2*j+1);
fmpz_mul_ui(t, t, 2*j+2);
_acb_vec_scalar_div_fmpz(P, P, plen, t, prec);
/* P = P / Na or P / Na^2 */
if (j == 0)
acb_set(T, Na);
else
acb_mul(T, Na, Na, prec);
_acb_vec_scalar_div(P, P, plen, T, prec);
/* T = P * B_{2j+2} */
_acb_vec_scalar_mul_fmpz(T, P, plen, fmpq_numref(bernoulli_cache + 2 * j + 2), prec);
_acb_vec_scalar_div_fmpz(T, T, plen, fmpq_denref(bernoulli_cache + 2 * j + 2), prec);
fmpz_clear(t);
}
else
{
slong m, len1, len2, alloc;
acb_ptr P1, T1, P2, T2;
m = a + (b - a) / 2;
len1 = FLINT_MIN(2 * (m - a) + 1, len);
len2 = FLINT_MIN(2 * (b - m) + 1, len);
alloc = 2 * len1 + 2 * len2;
P1 = _acb_vec_init(alloc);
T1 = P1 + len1;
P2 = T1 + len1;
T2 = P2 + len2;
bsplit(P1, T1, s, Na, a, m, 1, len, prec);
bsplit(P2, T2, s, Na, m, b, 1, len, prec);
/* P = P1 * P2 */
if (cont)
_acb_poly_mullow(P, P2, len2, P1, len1, plen, prec);
/* T = T1 + P1 * T2 */
_acb_poly_mullow(T, T2, len2, P1, len1, plen, prec);
_acb_vec_add(T, T, T1, len1, prec);
_acb_vec_clear(P1, alloc);
}
}
void
_acb_poly_zeta_em_tail_bsplit(acb_ptr z, const acb_t s, const acb_t Na, acb_srcptr Nasx, slong M, slong len, slong prec)
{
acb_ptr P, T;
if (M < 1)
{
_acb_vec_zero(z, len);
return;
}
BERNOULLI_ENSURE_CACHED(2 * M);
P = _acb_vec_init(len);
T = _acb_vec_init(len);
bsplit(P, T, s, Na, 0, M, 0, len, prec);
_acb_poly_mullow(z, T, len, Nasx, len, len, prec);
_acb_vec_clear(P, len);
_acb_vec_clear(T, len);
}