mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
274 lines
6.7 KiB
C
274 lines
6.7 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"
|
|
|
|
static void
|
|
_mag_pow(mag_t res, const mag_t x, const mag_t y)
|
|
{
|
|
arb_t t, u;
|
|
arb_init(t);
|
|
arb_init(u);
|
|
|
|
arf_set_mag(arb_midref(t), x);
|
|
arf_set_mag(arb_midref(u), y);
|
|
arb_pow(t, t, u, 2 * MAG_BITS);
|
|
arb_get_mag(res, t);
|
|
|
|
arb_clear(t);
|
|
arb_clear(u);
|
|
}
|
|
|
|
/* zeta(1+s) < 1+1/s */
|
|
static void
|
|
mag_zeta1p(mag_t res, const mag_t s)
|
|
{
|
|
mag_t t;
|
|
mag_init(t);
|
|
mag_one(t);
|
|
mag_div(t, t, s);
|
|
mag_add_ui(res, t, 1);
|
|
mag_clear(t);
|
|
}
|
|
|
|
/* |zeta(s)| <= (2pi)^sigma |gamma(1-s)| exp(pi|t|/2) zeta(1-sigma) / pi */
|
|
void
|
|
acb_dirichlet_zeta_bound_functional_equation(mag_t res, const acb_t s)
|
|
{
|
|
slong prec, p;
|
|
acb_t z;
|
|
arb_t x;
|
|
mag_t t;
|
|
|
|
if (!arb_is_negative(acb_realref(s)))
|
|
{
|
|
mag_inf(res);
|
|
return;
|
|
}
|
|
|
|
acb_init(z);
|
|
arb_init(x);
|
|
mag_init(t);
|
|
|
|
prec = 0;
|
|
p = arf_abs_bound_lt_2exp_si(arb_midref(acb_imagref(s)));
|
|
prec = FLINT_MAX(p, prec);
|
|
p = arf_abs_bound_lt_2exp_si(arb_midref(acb_realref(s)));
|
|
prec = FLINT_MAX(p, prec);
|
|
/* we *could* increase the precision even further to return finite
|
|
results for huge input... but there's not much practical reason to... */
|
|
prec = FLINT_MIN(prec, 1000);
|
|
|
|
prec += MAG_BITS;
|
|
|
|
/* gamma(1-s) */
|
|
acb_sub_ui(z, s, 1, prec);
|
|
acb_neg(z, z);
|
|
acb_gamma(z, z, prec);
|
|
acb_get_mag(res, z);
|
|
|
|
/* (2pi)^sigma */
|
|
arb_const_pi(x, prec);
|
|
arb_mul_2exp_si(x, x, 1);
|
|
arb_pow(x, x, acb_realref(s), prec);
|
|
arb_get_mag(t, x);
|
|
mag_mul(res, res, t);
|
|
|
|
/* 1/pi */
|
|
mag_div_ui(res, res, 3);
|
|
|
|
/* exp(pi|t|/2) */
|
|
arb_const_pi(x, prec);
|
|
arb_mul(x, x, acb_imagref(s), prec);
|
|
arb_abs(x, x);
|
|
arb_mul_2exp_si(x, x, -1);
|
|
arb_exp(x, x, prec);
|
|
arb_get_mag(t, x);
|
|
mag_mul(res, res, t);
|
|
|
|
/* zeta(1-s) */
|
|
arb_neg(x, acb_realref(s));
|
|
arb_get_mag_lower(t, x);
|
|
mag_zeta1p(t, t);
|
|
mag_mul(res, res, t);
|
|
|
|
acb_clear(z);
|
|
arb_clear(x);
|
|
mag_clear(t);
|
|
}
|
|
|
|
/*
|
|
Rademacher 43.3:
|
|
Assume -eta <= sigma <= 1 + eta where 0 < eta <= 1/2. Then:
|
|
|
|
|zeta(s)| < 3 |(1+s)/(1-s)| |(1+s)/(2pi)|^e zeta(1+eta)
|
|
|
|
where e = (1+eta-sigma)/2. Inside the strip, we use this formula with
|
|
eta = 0.1 (this could be improved).
|
|
*/
|
|
void
|
|
acb_dirichlet_zeta_bound_strip(mag_t res, const acb_t s)
|
|
{
|
|
arf_t eta, a;
|
|
acb_t s1;
|
|
mag_t t, u, v;
|
|
|
|
acb_init(s1);
|
|
arf_init(eta);
|
|
arf_init(a);
|
|
mag_init(t);
|
|
mag_init(u);
|
|
mag_init(v);
|
|
|
|
/* We need -eta <= sigma <= 1 + eta where sigma = m +/- r,
|
|
i.e. eta >= max(-m, m-1) + r. */
|
|
arf_neg(eta, arb_midref(acb_realref(s)));
|
|
arf_sub_ui(a, arb_midref(acb_realref(s)), 1, MAG_BITS, ARF_RND_CEIL);
|
|
arf_max(eta, eta, a);
|
|
arf_set_mag(a, arb_radref(acb_realref(s)));
|
|
arf_add(eta, eta, a, MAG_BITS, ARF_RND_CEIL);
|
|
/* eta = max(eta, 0.1), to avoid the pole */
|
|
arf_set_d(a, 0.1);
|
|
arf_max(eta, eta, a);
|
|
|
|
/* Requires 0 <= eta <= 1/2. */
|
|
if (arf_cmpabs_2exp_si(eta, -1) <= 0)
|
|
{
|
|
/* t = |1+s|/(2pi) */
|
|
acb_add_ui(s1, s, 1, MAG_BITS);
|
|
acb_get_mag(t, s1);
|
|
mag_set_ui_2exp_si(u, 163, -10); /* 1/(2pi) < 163/1024 */
|
|
mag_mul(t, t, u);
|
|
|
|
/* a = (1+eta-sigma)/2 */
|
|
arf_set_mag(a, arb_radref(acb_realref(s)));
|
|
arf_add(a, eta, a, MAG_BITS, ARF_RND_CEIL);
|
|
arf_sub(a, a, arb_midref(acb_realref(s)), MAG_BITS, ARF_RND_CEIL);
|
|
arf_add_ui(a, a, 1, MAG_BITS, ARF_RND_CEIL);
|
|
arf_mul_2exp_si(a, a, -1);
|
|
if (arf_sgn(a) < 0)
|
|
arf_zero(a);
|
|
arf_get_mag(u, a);
|
|
|
|
/* t = (|1+s|/(2pi))^((1+eta-sigma)/2) */
|
|
_mag_pow(t, t, u);
|
|
|
|
/* 3|1+s|/|1-s| */
|
|
acb_get_mag(u, s1);
|
|
mag_mul(t, t, u);
|
|
acb_sub_ui(s1, s, 1, MAG_BITS);
|
|
acb_get_mag_lower(u, s1);
|
|
mag_div(t, t, u);
|
|
mag_mul_ui(t, t, 3);
|
|
|
|
/* zeta(1+eta) */
|
|
arf_get_mag_lower(u, eta);
|
|
mag_zeta1p(u, u);
|
|
mag_mul(t, t, u);
|
|
|
|
mag_set(res, t);
|
|
}
|
|
else
|
|
{
|
|
mag_inf(res);
|
|
}
|
|
|
|
acb_clear(s1);
|
|
arf_clear(eta);
|
|
arf_clear(a);
|
|
mag_clear(t);
|
|
mag_clear(u);
|
|
mag_clear(v);
|
|
}
|
|
|
|
/*
|
|
We have three cases: Rademacher's bound valid on -0.5 <= sigma <= 1.5, the
|
|
trivial bound on sigma > 1, and the functional equation valid on sigma < 0.
|
|
We intersect s with three separate domains for evaluation: right, inside,
|
|
and left of the extended strip [-0.25,1.25].
|
|
|
|
Sharper bounds could be used precisely when sigma = 1/2,
|
|
or very close to the line sigma = 1.
|
|
*/
|
|
void
|
|
acb_dirichlet_zeta_bound(mag_t res, const acb_t s)
|
|
{
|
|
arb_t strip;
|
|
mag_t t;
|
|
|
|
if (!acb_is_finite(s))
|
|
{
|
|
mag_inf(res);
|
|
return;
|
|
}
|
|
|
|
arb_init(strip);
|
|
mag_init(t);
|
|
|
|
arf_set_ui_2exp_si(arb_midref(strip), 1, -1);
|
|
mag_set_ui_2exp_si(arb_radref(strip), 3, -2);
|
|
|
|
if (arb_le(strip, acb_realref(s)))
|
|
{
|
|
arb_get_mag_lower(res, acb_realref(s));
|
|
mag_one(t);
|
|
mag_sub_lower(res, res, t);
|
|
mag_zeta1p(res, res);
|
|
}
|
|
else if (arb_contains(strip, acb_realref(s)))
|
|
{
|
|
acb_dirichlet_zeta_bound_strip(res, s);
|
|
}
|
|
else if (arb_le(acb_realref(s), strip))
|
|
{
|
|
acb_dirichlet_zeta_bound_functional_equation(res, s);
|
|
}
|
|
else
|
|
{
|
|
acb_t ss;
|
|
arf_t x1, x2;
|
|
|
|
acb_init(ss);
|
|
arf_init(x1);
|
|
arf_init(x2);
|
|
|
|
/* Since s overlaps at least two regions, it must certainly
|
|
overlap with the extended strip. */
|
|
arb_set(acb_imagref(ss), acb_imagref(s));
|
|
arb_intersection(acb_realref(ss), acb_realref(s), strip, MAG_BITS);
|
|
acb_dirichlet_zeta_bound_strip(res, ss);
|
|
|
|
/* We may have real parts > 1.25. */
|
|
/* The bound computed for the extended strip *should* already be
|
|
larger than zeta(1.25) < 5, but just to be sure... */
|
|
mag_set_ui(t, 5);
|
|
mag_max(res, res, t);
|
|
|
|
/* Finally, we may have have real parts < -0.25. */
|
|
arf_set_mag(x1, arb_radref(acb_realref(s)));
|
|
arf_sub(x1, arb_midref(acb_realref(s)), x1, MAG_BITS, ARF_RND_FLOOR);
|
|
arf_set_d(x2, -0.25);
|
|
if (arf_cmp(x1, x2) < 0)
|
|
{
|
|
arb_set_interval_arf(acb_realref(ss), x1, x2, MAG_BITS);
|
|
acb_dirichlet_zeta_bound_functional_equation(t, ss);
|
|
mag_max(res, res, t);
|
|
}
|
|
|
|
acb_clear(ss);
|
|
arf_clear(x1);
|
|
arf_clear(x2);
|
|
}
|
|
|
|
arb_clear(strip);
|
|
mag_clear(t);
|
|
}
|
|
|