mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
134 lines
3.4 KiB
C
134 lines
3.4 KiB
C
/*
|
|
Copyright (C) 2016 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"
|
|
|
|
#define ONE_OVER_LOG2 1.4426950408889634
|
|
|
|
void
|
|
acb_dirichlet_l_euler_product(acb_t res, const acb_t s,
|
|
const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)
|
|
{
|
|
arf_t left;
|
|
slong wp, powprec, left_s;
|
|
ulong val, p, p_limit;
|
|
double p_needed_approx, powmag, logp, errmag;
|
|
int is_real;
|
|
acb_t t, u, v, c;
|
|
acb_dirichlet_roots_t roots;
|
|
mag_t err;
|
|
|
|
if (!acb_is_finite(s))
|
|
{
|
|
acb_indeterminate(res);
|
|
return;
|
|
}
|
|
|
|
arf_init(left);
|
|
arf_set_mag(left, arb_radref(acb_realref(s)));
|
|
arf_sub(left, arb_midref(acb_realref(s)), left, 2 * MAG_BITS, ARF_RND_FLOOR);
|
|
|
|
/* Require re(s) >= 2. */
|
|
if (arf_cmp_si(left, 2) < 0)
|
|
{
|
|
acb_indeterminate(res);
|
|
arf_clear(left);
|
|
return;
|
|
}
|
|
|
|
is_real = acb_is_real(s) && dirichlet_char_is_real(G, chi);
|
|
|
|
/* L(s) ~= 1. */
|
|
if (arf_cmp_si(left, prec) > 0)
|
|
{
|
|
acb_one(res);
|
|
mag_hurwitz_zeta_uiui(arb_radref(acb_realref(res)), prec, 2);
|
|
if (!is_real)
|
|
mag_set(arb_radref(acb_imagref(res)), arb_radref(acb_realref(res)));
|
|
acb_inv(res, res, prec);
|
|
arf_clear(left);
|
|
return;
|
|
}
|
|
|
|
left_s = arf_get_si(left, ARF_RND_FLOOR);
|
|
|
|
/* Heuristic. */
|
|
wp = prec + FLINT_BIT_COUNT(prec) + (prec / left_s) + 4;
|
|
|
|
/* Don't work too hard if a small s was passed as input. */
|
|
p_limit = 100 + prec * sqrt(prec);
|
|
|
|
/* Truncating at p ~= 2^(prec/s) gives an error of 2^-prec */
|
|
if (((double) prec) / left_s > 50.0)
|
|
p_needed_approx = pow(2.0, 50.0);
|
|
else
|
|
p_needed_approx = pow(2.0, ((double) prec) / left_s);
|
|
|
|
p_needed_approx = FLINT_MIN(p_limit, p_needed_approx);
|
|
|
|
/* todo: use exponent of chi instead of G? */
|
|
acb_dirichlet_roots_init(roots, G->expo,
|
|
p_needed_approx / (1.0 + log(p_needed_approx)), wp);
|
|
|
|
acb_init(t);
|
|
acb_init(u);
|
|
acb_init(v);
|
|
acb_init(c);
|
|
|
|
acb_one(v);
|
|
|
|
for (p = 2; p < p_limit; p = n_nextprime(p, 1))
|
|
{
|
|
/* p^s */
|
|
logp = log(p);
|
|
powmag = left_s * logp * ONE_OVER_LOG2;
|
|
|
|
/* zeta(s,p) ~= 1/p^s + 1/((s-1) p^(s-1)) */
|
|
errmag = (log(left_s - 1.0) + (left_s - 1.0) * logp) * ONE_OVER_LOG2;
|
|
errmag = FLINT_MIN(powmag, errmag);
|
|
|
|
if (errmag > prec + 2)
|
|
break;
|
|
|
|
powprec = FLINT_MAX(wp - powmag, 8);
|
|
|
|
val = dirichlet_chi(G, chi, p);
|
|
|
|
if (val != DIRICHLET_CHI_NULL)
|
|
{
|
|
acb_dirichlet_root(c, roots, val, powprec);
|
|
acb_set_ui(t, p);
|
|
acb_pow(t, t, s, powprec);
|
|
acb_set_round(u, v, powprec);
|
|
acb_div(t, u, t, powprec);
|
|
acb_mul(t, t, c, powprec);
|
|
acb_sub(v, v, t, wp);
|
|
}
|
|
}
|
|
|
|
mag_init(err);
|
|
mag_hurwitz_zeta_uiui(err, left_s, p);
|
|
if (is_real)
|
|
arb_add_error_mag(acb_realref(v), err);
|
|
else
|
|
acb_add_error_mag(v, err);
|
|
mag_clear(err);
|
|
|
|
acb_inv(res, v, prec);
|
|
|
|
acb_dirichlet_roots_clear(roots);
|
|
acb_clear(t);
|
|
acb_clear(u);
|
|
acb_clear(v);
|
|
acb_clear(c);
|
|
arf_clear(left);
|
|
}
|
|
|