arb/acb_dirichlet/zeta_jet_rs.c

184 lines
4.4 KiB
C
Raw Normal View History

/*
Copyright (C) 2017 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_dirichlet.h"
/*
f(s) = (f(s+hi) + f(s-hi))/2 + err0
f'(s) = (f(s+hi) - f(s-hi))/(2hi) + err1
|err0| <= |f(s +/- R)| (1/R)^2 h^2 / (1 - h/R)
|err1| <= |f(s +/- R)| (1/R)^3 h^2 / (1 - h/R)
assuming h/R < 1
*/
static void
acb_dirichlet_zeta_jet_rs_mid(acb_ptr res, const acb_t s, slong prec)
{
acb_t t, u;
arb_t hh;
mag_t h, R, err0, err1, tmp;
slong hexp;
acb_init(t);
acb_init(u);
arb_init(hh);
mag_init(h);
mag_init(R);
mag_init(err0);
mag_init(err1);
mag_init(tmp);
hexp = -(prec / 2) - 10;
mag_set_ui_2exp_si(h, 1, hexp);
mag_set_ui_2exp_si(R, 1, -5);
acb_set(t, s);
mag_add(arb_radref(acb_realref(t)), arb_radref(acb_realref(t)), R);
mag_add(arb_radref(acb_imagref(t)), arb_radref(acb_imagref(t)), R);
/* tmp = |f(s +/- R)| */
acb_dirichlet_zeta_bound(tmp, t);
/* err0 = (1/R)^2 h^2 / (1 - h/R) */
mag_div(err0, h, R);
mag_geom_series(err0, err0, 2);
/* err0 *= tmp */
mag_mul(err0, err0, tmp);
/* err1 = err0 / R */
mag_div(err1, err0, R);
/* hh = h as an arb_t */
arb_one(hh);
arb_mul_2exp_si(hh, hh, hexp);
acb_set(t, s);
acb_set(u, s);
arb_add(acb_imagref(t), acb_imagref(t), hh, 10 * prec);
arb_sub(acb_imagref(u), acb_imagref(u), hh, 10 * prec);
/* zeta(mid(s)+ih) */
acb_dirichlet_zeta_rs(res, t, 0, 1.5 * prec + 10);
/* zeta(mid(s)-ih) */
acb_dirichlet_zeta_rs(res + 1, u, 0, 1.5 * prec + 10);
acb_sub(t, res, res + 1, prec);
acb_add(res, res, res + 1, prec);
acb_swap(res + 1, t);
acb_mul_2exp_si(res, res, -1);
acb_mul_2exp_si(res + 1, res + 1, -1);
acb_mul_2exp_si(res + 1, res + 1, -hexp);
acb_div_onei(res + 1, res + 1);
acb_add_error_mag(res, err0);
acb_add_error_mag(res + 1, err1);
acb_clear(t);
acb_clear(u);
arb_clear(hh);
mag_clear(h);
mag_clear(R);
mag_clear(err0);
mag_clear(err1);
mag_clear(tmp);
}
void
acb_dirichlet_zeta_jet_rs(acb_ptr res, const acb_t s, slong len, slong prec)
{
if (len > 2)
{
flint_printf("acb_dirichlet_zeta_jet_rs: len > 2 not implemented\n");
flint_abort();
}
if (len <= 0)
return;
if (len == 1)
{
acb_dirichlet_zeta_rs(res, s, 0, prec);
}
else if (acb_is_exact(s))
{
acb_dirichlet_zeta_jet_rs_mid(res, s, prec);
}
else
{
acb_t t;
mag_t r, err0, err1, der1, der2, M;
/*
slong acc;
acc = acb_rel_accuracy_bits(s);
acc = FLINT_MAX(acc, 0);
acc = FLINT_MIN(acc, prec);
prec = FLINT_MIN(prec, acc + 20);
*/
/*
assume s = m +/- r
f(s) = f(m) + err0
f'(s) = f'(m) + err1
|err1| <= |f''(s)| r
|err0| <= min(|f'(s)| r, |f'(m)| r + 0.5 |f''(s)| r^2)
= r min(|f'(s)|, |f'(m)| + 0.5 |f''(s)| r)
*/
acb_init(t);
mag_init(r);
mag_init(err0);
mag_init(err1);
mag_init(der1);
mag_init(der2);
mag_init(M);
/* r = rad(s) */
mag_hypot(r, arb_radref(acb_realref(s)), arb_radref(acb_imagref(s)));
/* Bound zeta'(s), zeta''(s) */
acb_dirichlet_zeta_deriv_bound(der1, der2, s);
/* f(m), f'(m) */
acb_set(t, s);
mag_zero(arb_radref(acb_realref(t)));
mag_zero(arb_radref(acb_imagref(t)));
acb_dirichlet_zeta_jet_rs_mid(res, t, prec);
/* err1 = |f''(s)| r */
mag_mul(err1, der2, r);
/* err0 = |f'(m)| + 0.5 |f''(s)| r */
acb_get_mag(M, res + 1);
mag_mul_2exp_si(err0, err1, -1);
mag_add(err0, err0, M);
/* err0 = min(err0, |f'(s)| */
mag_min(err0, err0, der1);
/* err0 = err0 * r */
mag_mul(err0, err0, r);
acb_add_error_mag(res, err0);
acb_add_error_mag(res + 1, err1);
acb_clear(t);
mag_clear(r);
mag_clear(err0);
mag_clear(err1);
mag_clear(der1);
mag_clear(der2);
mag_clear(M);
}
}