acb_dirichlet.h
#include <flint/acb_dirichlet.h>This module evaluates Dirichlet L-functions
and their analytic continuations, where \chi is a Dirichlet character of the dirichlet module, together with the special cases and relatives of L(s, \chi): the Riemann zeta function (the trivial character), the Hurwitz zeta function \zeta(s, a), the Lerch transcendent and the Stieltjes constants. It also computes Gauss and Jacobi sums and theta series of characters, discrete Fourier transforms on groups of characters, the Hardy Z-function, and the nontrivial zeros of \zeta(s): counting them with Turing's method, isolating and refining them by the Riemann–Siegel formula, or many at a time at large height by Platt's method. All results are rigorous enclosures.
acb_zeta and acb_hurwitz_zeta of the acb module call acb_dirichlet_zeta and acb_dirichlet_hurwitz. The Euler–Maclaurin summation behind the Hurwitz zeta function is _acb_poly_zeta_cpx_series of acb_poly, and polylogarithms are acb_polylog. The methods are described in Zeta functions, polylogarithms and L-functions and Zeros of the Riemann zeta function, and the tutorial The Riemann zeta function, its zeros and L-functions computes zeros and L-function values in complete programs.
Conventions#
- A character is given by a group
G(the characters modulo q) and an elementchiofdirichlet_char_t, or by its Conrey number; seedirichletand Dirichlet characters. Functions that acceptG=chi=NULLthen use the trivial character modulo 1, that is, the Riemann zeta function. This is the case foracb_dirichlet_l,acb_dirichlet_l_jet,acb_dirichlet_l_fmpqand the Hardy Z-functions. - The parity of \chi is \delta = 0 if \chi(-1) = 1 and \delta = 1 if \chi(-1) = -1, and \overline{\chi} is the conjugate character.
- Power series in s ("jets") are written as vectors of Taylor coefficients: entry k of the output of
acb_dirichlet_zeta_jetis \zeta^{(k)}(s)/k!. - Outputs may alias inputs unless stated otherwise.
Roots of unity#
Precomputed data for evaluating the roots of unity e^{2\pi i k/n} of a fixed order n, as used for character values.
void acb_dirichlet_roots_init(acb_dirichlet_roots_t t, ulong order, slong num, slong prec)Initialise t for the roots of unity of order n = order, optimised for num evaluations at precision prec, and free it.
void acb_dirichlet_root(acb_t z, const acb_dirichlet_roots_t t, ulong n, slong prec)Sets z to e^{2\pi i n / \text{order}}.
Character values#
void acb_dirichlet_chi(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, ulong n, slong prec)Sets res to \chi(n), which is 0 if \gcd(n, q) > 1 and a root of unity otherwise.
void acb_dirichlet_chi_vec(acb_ptr v, const dirichlet_group_t G, const dirichlet_char_t chi, slong nv, slong prec)Sets v to (\chi(0), \chi(1), \ldots, \chi(\text{nv} - 1)), sharing the powers of one root of unity.
void acb_dirichlet_pairing(acb_t res, const dirichlet_group_t G, ulong m, ulong n, slong prec)void acb_dirichlet_pairing_char(acb_t res, const dirichlet_group_t G, const dirichlet_char_t a, const dirichlet_char_t b, slong prec)Set res to the value \chi_q(m, n) of the Conrey pairing, that is, the value at n of the character with Conrey number m; the second form takes the two characters as input.
Gauss and Jacobi sums#
void acb_dirichlet_gauss_sum(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_gauss_sum_naive(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_gauss_sum_factor(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_gauss_sum_order2(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_gauss_sum_theta(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Set res to the Gauss sum G_q(\chi) = \sum_{x \bmod q} \chi(x) e^{2\pi i x/q}. The naive version sums the definition; factor writes the sum as a product of local Gauss sums by the Chinese remainder theorem; order2 assumes that \chi is real and primitive and returns i^\delta \sqrt{q}; theta assumes that \chi is primitive and obtains the sum from the functional equation of the theta series at t = 1. The default version reduces an imprimitive character to the primitive one inducing it and then chooses among the methods.
void acb_dirichlet_jacobi_sum(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi1, const dirichlet_char_t chi2, slong prec)void acb_dirichlet_jacobi_sum_naive(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi1, const dirichlet_char_t chi2, slong prec)void acb_dirichlet_jacobi_sum_factor(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi1, const dirichlet_char_t chi2, slong prec)void acb_dirichlet_jacobi_sum_gauss(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi1, const dirichlet_char_t chi2, slong prec)void acb_dirichlet_jacobi_sum_ui(acb_t res, const dirichlet_group_t G, ulong a, ulong b, slong prec)Set res to the Jacobi sum J_q(\chi_1, \chi_2) = \sum_{x \bmod q} \chi_1(x) \chi_2(1-x). The naive version sums the definition; factor writes it as a product of local Jacobi sums; gauss assumes that \chi_1 \chi_2 is primitive and uses J_q(\chi_1, \chi_2) G_q(\chi_1\chi_2) = G_q(\chi_1) G_q(\chi_2). The default version handles trivial and inverse pairs by closed formulas (and returns 0 for even q) and otherwise chooses among the methods. The ui version takes the Conrey numbers a and b.
Theta series#
The theta series of a character \chi modulo q with parity \delta is
For primitive \chi it satisfies t^{1/2+\delta} \, \Theta_q(\chi, t) = \epsilon(\chi) \, \Theta_q(\overline{\chi}, 1/t), where \epsilon(\chi) is the root number, which gives the Gauss sum and the root number from \Theta_q(\chi, 1).
void acb_dirichlet_theta_arb(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, const arb_t t, slong prec)void acb_dirichlet_ui_theta_arb(acb_t res, const dirichlet_group_t G, ulong a, const arb_t t, slong prec)Set res to \Theta_q(\chi, t) for real t > 0; the ui version takes the Conrey number a. The series converges quickly only for t not too small; for t < 1 the caller should use the functional equation above, which is not applied automatically (to avoid recomputing the Gauss sum).
ulong acb_dirichlet_theta_length(ulong q, const arb_t t, slong prec)ulong acb_dirichlet_theta_length_d(ulong q, double t, slong prec)Return a number of terms N such that the tail of the theta series of modulus q at t is less than 2^{-\text{prec}}. The first version uses a lower bound for t.
void acb_dirichlet_qseries_arb_powers_naive(acb_t res, const arb_t x, int parity, const ulong * a, const acb_dirichlet_roots_t z, slong len, slong prec)void acb_dirichlet_qseries_arb_powers_smallorder(acb_t res, const arb_t x, int parity, const ulong * a, const acb_dirichlet_roots_t z, slong len, slong prec)Set res to \sum_{n<\text{len}} n^p z^{a_n} x^{n^2}, where p is parity (0 or 1), z is the root of unity of z, and the exponents a_n are given (with a special value for \chi(n) = 0, as produced by dirichlet_chi_vec_order). The naive version sums the series as written; the smallorder version sums it in the quotient ring by the cyclotomic polynomial and evaluates at the root of unity only at the end, ignoring z except for its order.
void acb_dirichlet_qseries_arb(acb_t res, acb_srcptr a, const arb_t x, slong len, slong prec)Sets res to \sum_{k=1}^{\text{len}-1} a_k x^{k^2} (the entry a_0 is ignored), computing x^{k^2} by two multiplications per term.
void acb_dirichlet_arb_quadratic_powers(arb_ptr v, slong nv, const arb_t x, slong prec)Sets v to (x^{k^2})_{0 \le k < \text{nv}}.
void acb_dirichlet_vec_mellin_arb(acb_ptr res, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, const arb_t t, slong n, slong prec)Sets res[k], for 0 \le k < n, to t^{k/2} \sum_{m=1}^{\text{len}-1} \chi(m) m^\delta e^{-\pi m^2 t^{2k}/q} (half the theta series at the geometric sequence t^k, scaled), with the tail bound for the truncation after len terms. These are samples for computing the Mellin transform of the theta series.
Power sums#
void acb_dirichlet_powsum_term(acb_ptr res, arb_t log_prev, ulong * prev, const acb_t s, ulong k, int integer, int critical_line, slong len, slong prec)Sets res to k^{-(s+x)} as a power series in x of length len. The flags integer and critical_line select optimisations for integer s and for \operatorname{Re}(s) = 1/2.
Sets z to \sum_{k=1}^n k^{-(s+x)} as a power series in x of length len. Powers of composite k = ij are computed as i^{-s} j^{-s} from a table, and the even terms are grouped as a polynomial in 2^{-(s+x)}. This needs about n / \log n powers, n/2 multiplications and storage for n/6 power series, so it is only faster than the naive sum for small len.
Sets z to \sum_{k=1}^n k^{-(s+x)} as a power series in x of length len, by partial sieving that adds the multiples of 5-smooth numbers into separate buckets. It computes about 4/15 of the powers, more than acb_dirichlet_powsum_sieved, but needs only logarithmic extra space and is faster for large len, since power series multiplications are replaced by additions.
The Riemann zeta function#
void acb_dirichlet_zeta(acb_t res, const acb_t s, slong prec)Sets res to \zeta(s), choosing the algorithm from s and prec: exact values at integers (Bernoulli numbers for negative integers, arb_zeta_ui for positive ones), the Riemann–Siegel formula for |\operatorname{Im}(s)| \ge 24 \, p^{3/2} and |\operatorname{Re}(s)| \le 10 + p/10 at precision p, and Euler–Maclaurin summation otherwise, after the reflection formula for \operatorname{Re}(s) < 0. The result is indeterminate if s contains the pole s = 1.
void acb_dirichlet_zeta_jet(acb_t res, const acb_t s, int deflate, slong len, slong prec)Sets res (a vector of length len) to the Taylor coefficients of \zeta(s + x), or of the deflated function \zeta(s + x) - 1/(s + x - 1) if deflate is nonzero. Euler–Maclaurin summation is used (with the reflection formula for \operatorname{Re}(s) < 0), or the Riemann–Siegel formula for len \le 2 high on the critical line.
void acb_dirichlet_zeta_bound(mag_t res, const acb_t s)Sets res to an upper bound for |\zeta(s)|, computed quickly: in and slightly around the critical strip by formula (43.3) of [Rad1973], to the right by the value at \operatorname{Re}(s), and to the left by the functional equation.
void acb_dirichlet_zeta_deriv_bound(mag_t der1, mag_t der2, const acb_t s)Sets der1 and der2 to upper bounds for |\zeta'(s)| and |\zeta''(s)|, meant for the critical strip. The bounds are not tight.
void acb_dirichlet_eta(acb_t res, const acb_t s, slong prec)Sets res to the Dirichlet eta function \eta(s) = \sum_{k=1}^{\infty} (-1)^{k+1} k^{-s} = (1-2^{1-s}) \zeta(s) (the alternating character is not a Dirichlet character). The removable singularity at s = 1, where \eta(1) = \log 2, is handled.
void acb_dirichlet_xi(acb_t res, const acb_t s, slong prec)Sets res to the Riemann xi function \xi(s) = \frac{1}{2} s (s-1) \pi^{-s/2} \Gamma(\tfrac{s}{2}) \zeta(s), which satisfies \xi(1-s) = \xi(s).
The Riemann–Siegel formula#
The Riemann–Siegel formula is implemented following Arias de Reyna [Ari2011]. For s = \sigma + it with t > 0,
where U = \exp(-i[\frac{t}{2} \log(\frac{t}{2\pi})-\frac{t}{2}-\frac{\pi}{8}]), a = \sqrt{t/(2\pi)}, N = \lfloor a \rfloor and p = 1-2(a-N). The coefficients C_k(p) are expressed through auxiliary coefficients d_j^{(k)} and the derivatives F^{(j)}(p). The cost is O(\sqrt{t}) terms, against O(t) for Euler–Maclaurin summation; see The Riemann–Siegel formula. Because of artificial discontinuities, s should be exact inside the evaluation; inexact input is handled by bounding the derivative.
If nonzero (the default), the main sum of the Riemann–Siegel formula is computed with dfloat_powsum_sieved (double-word arithmetic, see dfloat) when that gives enough accuracy. Set it to 0 to always use acb_dirichlet_powsum_sieved. This is a global variable, which should not be changed while other threads evaluate zeta.
void acb_dirichlet_zeta_rs_f_coeffs(acb_ptr c, const arb_t p, slong N, slong prec)Sets c to F^{(j)}(p) for 0 \le j < N, by power series division. This breaks down at p = \pm 1/2, which does not occur for exact s.
void acb_dirichlet_zeta_rs_d_coeffs(arb_ptr d, const arb_t sigma, slong k, slong prec)Updates d in place from d_j^{(k-1)} to d_j^{(k)} for 0 \le j \le \lfloor 3k/2 \rfloor + 1 (for k = 0, initialises it).
void acb_dirichlet_zeta_rs_bound(mag_t err, const acb_t s, slong K)Sets err to a bound for the error term RS_K, by Theorem 4.2 of [Ari2011].
void acb_dirichlet_zeta_rs_r(acb_t res, const acb_t s, slong K, slong prec)Sets res to \mathcal{R}(s) for s in the upper half-plane, with exactly K asymptotic terms if K > 0 and an automatic choice otherwise.
void acb_dirichlet_zeta_rs(acb_t res, const acb_t s, slong K, slong prec)Sets res to \zeta(s) by the Riemann–Siegel formula, with exactly K asymptotic terms if K > 0 and an automatic choice otherwise.
void acb_dirichlet_zeta_jet_rs(acb_ptr res, const acb_t s, slong len, slong prec)Sets res to the first len Taylor coefficients of \zeta at s by the Riemann–Siegel formula. Only len \le 2 is supported; the derivative is computed with a finite difference.
The Hurwitz zeta function#
void acb_dirichlet_hurwitz(acb_t res, const acb_t s, const acb_t a, slong prec)Sets res to the Hurwitz zeta function \zeta(s, a) = \sum_{k=0}^{\infty} (k + a)^{-s}, analytically continued. The case a = 1 calls acb_dirichlet_zeta, and s = 0 and small negative integers s use Bernoulli polynomials; otherwise Euler–Maclaurin summation is used (_acb_poly_zeta_cpx_series). The result is indeterminate if s contains 1.
Precomputed data for evaluating \zeta(s, a) at many a \in (0, 1] for a fixed s.
void acb_dirichlet_hurwitz_precomp_init(acb_dirichlet_hurwitz_precomp_t pre, const acb_t s, int deflate, slong A, slong K, slong N, slong prec)Precomputes a grid of N Taylor polynomials of length K for \zeta(s, a + A), for fast evaluation of \zeta(s, a) at a \in (0,1] with fixed s. This costs NK Hurwitz zeta values; each later evaluation costs 2K arithmetic operations plus A powers, with a truncation error O(1/(2AN)^K). With deflate nonzero, the deflated function (without the pole at s = 1) is used.
void acb_dirichlet_hurwitz_precomp_init_num(acb_dirichlet_hurwitz_precomp_t pre, const acb_t s, int deflate, double num_eval, slong prec)void acb_dirichlet_hurwitz_precomp_choose_param(ulong * A, ulong * K, ulong * N, const acb_t s, double num_eval, slong prec)Choose A, K and N to minimise the cost of num_eval evaluations at s and precision prec, and (for the first function) initialise pre with them. If evaluating each value from scratch is estimated to be cheaper, A = K = N = 0.
Frees the precomputed data.
Sets res to a bound for the truncation error (not including rounding errors) of the evaluation of \zeta(s, a) with parameters A, K, N, for 0 < a \le 1.
void acb_dirichlet_hurwitz_precomp_eval(acb_t res, const acb_dirichlet_hurwitz_precomp_t pre, ulong p, ulong q, slong prec)Sets res to \zeta(s, p/q) using the precomputed data, for 0 < p/q \le 1. Throws an exception if p > q.
The Lerch transcendent#
void acb_dirichlet_lerch_phi_direct(acb_t res, const acb_t z, const acb_t s, const acb_t a, slong prec)void acb_dirichlet_lerch_phi_integral(acb_t res, const acb_t z, const acb_t s, const acb_t a, slong prec)Set res to the Lerch transcendent \Phi(z,s,a) = \sum_{k=0}^{\infty} z^k (k+a)^{-s}, analytically continued to |z| \ge 1. The direct version sums the truncated series; the integral version uses a Hankel contour integral; the default version checks special cases that reduce to the Hurwitz zeta function or polylogarithms and otherwise chooses between the two.
Stieltjes constants#
void acb_dirichlet_stieltjes(acb_t res, const fmpz_t n, const acb_t a, slong prec)Sets res to the generalised Stieltjes constant \gamma_n(a) for an integer n \ge 0 (an exception is thrown for n < 0), the coefficient in the Laurent series \zeta(s,a) = \frac{1}{s-1} + \sum_{n=0}^\infty \frac{(-1)^n}{n!} \gamma_n(a) (s-1)^n. With a = 1 these are the ordinary Stieltjes constants.
Dirichlet L-functions#
For a primitive character \chi of conductor q and parity \delta, L(s, \chi) satisfies the functional equation
with the root number |\epsilon(\chi)| = 1.
void acb_dirichlet_root_number(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_root_number_theta(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Set res to the root number \epsilon(\chi) of a primitive character. The theta version uses \epsilon(\chi) = \Theta_q(\chi, 1) / \overline{\Theta_q(\chi, 1)}; the default version uses the Gauss sum, \epsilon(\chi) = G_q(\chi)/(i^\delta \sqrt q), when q has several prime factors, and the theta series otherwise. The default version throws an exception if \chi is not primitive.
void acb_dirichlet_l(acb_t res, const acb_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Sets res to L(s,\chi), choosing the algorithm: the Riemann zeta function for q = 1, the functional equation for primitive \chi and \operatorname{Re}(s) < -1/2 (or near s = 0 for even \chi), the Euler product for large \operatorname{Re}(s), and otherwise the decomposition into Hurwitz zeta functions with a precomputation shared by the \phi(q) values.
void acb_dirichlet_l_hurwitz(acb_t res, const acb_t s, const acb_dirichlet_hurwitz_precomp_t precomp, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Sets res to L(s,\chi) = q^{-s}\sum_{k=1}^q \chi(k) \zeta(s, k/q). For s = 1 and non-principal \chi, the deflated Hurwitz zeta function is used to avoid the poles. If precomp is NULL, each Hurwitz zeta value is computed directly; otherwise the precomputation is used.
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)void _acb_dirichlet_euler_product_real_ui(arb_t res, ulong s, const signed char * chi, int mod, int reciprocal, slong prec)Set res to L(s,\chi) by the Euler product, which is efficient for large \operatorname{Re}(s); the result is finite only if \operatorname{Re}(s) \ge 2. The underscore version takes an integer s and a real character given by the list chi of its values at 0, \ldots, \text{mod}-1, and computes 1/L(s, \chi) if reciprocal is nonzero.
void acb_dirichlet_l_fmpq(acb_t res, const fmpq_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)void acb_dirichlet_l_fmpq_afe(acb_t res, const fmpq_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Set res to L(s,\chi) for rational s. The afe version uses the approximate functional equation, a rapidly convergent series of incomplete gamma functions (evaluated by binary splitting and the bit-burst algorithm), which is fastest at very high precision or large modulus; the default version uses it when this is estimated to be faster and otherwise calls acb_dirichlet_l.
void acb_dirichlet_l_vec_hurwitz(acb_ptr res, const acb_t s, const acb_dirichlet_hurwitz_precomp_t precomp, const dirichlet_group_t G, slong prec)Sets res (of length \phi(q)) to L(s,\chi) for all characters \chi modulo q, from the \phi(q) values \zeta(s, k/q) and one discrete Fourier transform. The values are ordered by lexicographically ordered Conrey logarithms, as in acb_dirichlet_dft_index. If precomp is NULL, each Hurwitz zeta value is computed directly.
void acb_dirichlet_l_jet(acb_ptr res, const acb_t s, const dirichlet_group_t G, const dirichlet_char_t chi, int deflate, slong len, slong prec)Sets res to the Taylor coefficients L(s), L'(s), \ldots, L^{(\text{len}-1)}(s)/(\text{len}-1)!. With deflate nonzero and principal \chi, the expansion of L(s,\chi) - \frac{\phi(q)}{q (s-1)} is computed instead, which at s = 1 is the regular part of the Laurent expansion; for non-principal \chi, deflate has no effect.
void _acb_dirichlet_l_series(acb_ptr res, acb_srcptr s, slong slen, const dirichlet_group_t G, const dirichlet_char_t chi, int deflate, slong len, slong prec)void acb_dirichlet_l_series(acb_poly_t res, const acb_poly_t s, const dirichlet_group_t G, const dirichlet_char_t chi, int deflate, slong len, slong prec)Set res to L(s(x),\chi) truncated to length len, for a power series s(x), with deflate as in acb_dirichlet_l_jet.
Discrete Fourier transforms on characters#
The discrete Fourier transform of f : \mathbb{Z}/q\mathbb{Z} \to \mathbb{C} is the function \hat f(\chi) = \sum_{x \bmod q} \overline{\chi(x)} f(x) on the characters modulo q. Using the Conrey isomorphism between (\mathbb{Z}/q\mathbb{Z})^\times and its dual, it is computed as g(a) = \sum_{b \bmod q} \overline{\chi_q(a,b)} f(b). Both functions are thin wrappers around gr_dft_acb_dirichlet_index and gr_dft_acb_dirichlet of gr_dft, which compute a product DFT over the cyclic components of the group in fixed-point arithmetic with rigorous error bounds.
void acb_dirichlet_dft_index(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)Sets w to the DFT of v, both vectors of length \phi(q) indexed by the lexicographically ordered Conrey logarithms (the order of dirichlet_char_next and dirichlet_char_index).
void acb_dirichlet_dft(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)Sets w to the DFT of v, both vectors of length q indexed by Conrey numbers. The entries at indices not coprime to q are ignored.
Hardy Z-functions#
For a primitive character \chi (or for \zeta, with G and chi NULL), the Hardy Z-function is Z(t) = e^{i\theta(t)} L(1/2+it, \chi), where the phase is
Z(t) is real for real t, and its real zeros are the zeros of L(s, \chi) on the critical line. The functions throw an exception if \chi is not primitive.
void acb_dirichlet_hardy_theta(acb_ptr res, const acb_t t, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)Sets res to the first len Taylor coefficients of \theta(t), using the log-gamma function.
void acb_dirichlet_hardy_z(acb_ptr res, const acb_t t, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)Sets res to the first len Taylor coefficients of Z(t), computed as e^{i\theta(t)} L(1/2 + it, \chi) with acb_dirichlet_l_jet. For the Riemann zeta function, this uses the Riemann–Siegel formula when t is large and len \le 2. If t is real, the imaginary parts are set to exactly zero.
void _acb_dirichlet_hardy_theta_series(acb_ptr res, acb_srcptr s, slong slen, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)void acb_dirichlet_hardy_theta_series(acb_poly_t res, const acb_poly_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)void _acb_dirichlet_hardy_z_series(acb_ptr res, acb_srcptr s, slong slen, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)void acb_dirichlet_hardy_z_series(acb_poly_t res, const acb_poly_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec)Set res to \theta(t(x)), respectively Z(t(x)), truncated to length len, for a power series t(x) (given as s).
Gram points and counting zeros#
These functions concern the Riemann zeta function only. Let N(t) be the number of zeros of \zeta(s), counted with multiplicity, with 0 < \operatorname{Im}(s) \le t, and S(t) = N(t) - \theta(t)/\pi - 1. They implement Turing's method as described in Turing's method, following the implementation in mpmath [Joh2018b] by Arias de Reyna [Ari2012].
void acb_dirichlet_gram_point(arb_t res, const fmpz_t n, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec)Sets res to the n-th Gram point g_n, the unique solution in [7, \infty) of \theta(g_n) = \pi n, for n \ge -1. Only the Riemann zeta function is supported: G and chi must be NULL; otherwise, or for n < -1, the result is indeterminate.
ulong acb_dirichlet_turing_method_bound(const fmpz_t p)void acb_dirichlet_zeta_nzeros(arb_t res, const arb_t t, slong prec)void _acb_dirichlet_exact_zeta_nzeros(fmpz_t res, const arf_t t)Set res to N(t). For exact t the result is an exact integer; for an inexact ball, it is the ball containing N(t_1), \ldots, N(t_2) where [t_1, t_2] encloses t. The underscore version takes an exact t and sets an integer.
void acb_dirichlet_zeta_nzeros_gram(fmpz_t res, const fmpz_t n)Sets res to N(g_n), for n \ge -1.
void acb_dirichlet_backlund_s(arb_t res, const arb_t t, slong prec)Sets res to S(t) = \frac{1}{\pi}\operatorname{arg}\zeta(\frac{1}{2} + it), where the argument is defined by continuous variation from s = 2 to 2 + it and then to \frac12 + it, not the principal value. It is computed as N(t) - \theta(t)/\pi - 1.
void acb_dirichlet_backlund_s_bound(mag_t res, const arb_t t)Sets res to an upper bound for |S(t)|, by Theorem 1 and (1.2) of [Tru2014].
slong acb_dirichlet_backlund_s_gram(const fmpz_t n)Returns S(g_n), for n \ge -1.
Zeros of the Riemann zeta function#
The n-th zero of the Hardy Z-function is \gamma_n, where \rho_n = 1/2 + i\gamma_n is the n-th nontrivial zero of \zeta(s) with positive imaginary part (assuming, as verified for every n handled by these functions, that the zeros are on the critical line and simple). Zeros of the Riemann zeta function explains the methods and gives an example.
void acb_dirichlet_hardy_z_zero(arb_t res, const fmpz_t n, slong prec)void acb_dirichlet_hardy_z_zeros(arb_ptr res, const fmpz_t n, slong len, slong prec)Set res to \gamma_n, respectively to the len consecutive values \gamma_n, \ldots, \gamma_{n+\text{len}-1}, accurate to about prec bits. Throws an exception if n < 1. The zeros are isolated rigorously and computed by the Riemann–Siegel method, or by Platt's method at large height when that is expected to be faster.
void acb_dirichlet_zeta_zero(acb_t res, const fmpz_t n, slong prec)void acb_dirichlet_zeta_zeros(acb_ptr res, const fmpz_t n, slong len, slong prec)Set res to \rho_n = 1/2 + i\gamma_n, respectively to len consecutive zeros starting with \rho_n. Requires n \ge 1.
void _acb_dirichlet_hardy_z_zeros_rs(arb_ptr res, const fmpz_t n, slong len, slong prec)The same as acb_dirichlet_hardy_z_zeros, always with the Riemann–Siegel method: isolation with Gram points and Turing's method, then refinement with _acb_dirichlet_refine_hardy_z_zero.
slong _acb_dirichlet_hardy_z_zeros_use_platt(const fmpz_t n, slong len, slong prec)Returns 0 if acb_dirichlet_hardy_z_zeros uses the Riemann–Siegel method for len zeros from the n-th at target precision prec (or at the default precision 64 + \lceil \log_2 n \rceil if prec is not positive), and otherwise the working precision of the large height method. The choice minimises a cost model measured with 2 threads.
void acb_dirichlet_isolate_hardy_z_zero(arf_t a, arf_t b, const fmpz_t n)void _acb_dirichlet_isolate_gram_hardy_z_zero(arf_t a, arf_t b, const fmpz_t n)void _acb_dirichlet_isolate_rosser_hardy_z_zero(arf_t a, arf_t b, const fmpz_t n)void _acb_dirichlet_isolate_turing_hardy_z_zero(arf_t a, arf_t b, const fmpz_t n)Set (a, b) to an interval that contains \gamma_n and no other zero of Z. The gram version uses Gram's law and requires 1 \le n \le 126; the rosser version uses Rosser's rule and requires 1 \le n \le 13999526; the turing version uses Turing's method and requires n \ge 2; the default version chooses among them and requires n \ge 1.
int _acb_dirichlet_definite_hardy_z(arb_t res, const arf_t t, slong * pprec)Sets res to Z(t), increasing the precision *pprec as needed until the sign of Z(t) is determined, and returns the sign.
void _acb_dirichlet_refine_hardy_z_zero(arb_t res, const arf_t a, const arf_t b, slong prec)Sets res to the unique zero of Z in (a, b), to prec bits.
void _acb_dirichlet_refine_hardy_z_zero_ball(arb_t res, const arb_t z, slong prec)Sets res to the zero of Z in the ball z, which must contain exactly one zero (for example a zero computed by Platt's method), to prec bits: z rounded if it is accurate enough, otherwise the last stage of the refinement above if z is accurate to about half the precision, and the full refinement otherwise.
Platt's method for zeros at large height#
Platt's method [Pla2017] evaluates the real function \Lambda(t) e^{\pi t/4}, which has the same zeros as Z(t), on a grid of AB points with spacing 1/A by a convolution computed with fast Fourier transforms, then interpolates between the grid points. One multi-evaluation isolates thousands of zeros; see Platt's method. The functions without underscore choose all parameters from the height and expect 10^4 \le n < 10^{37}; for smaller n they return 0. They use flint_get_num_threads() threads.
void acb_dirichlet_platt_scaled_lambda(arb_t res, const arb_t t, slong prec)Sets res to \Lambda(t) e^{\pi t/4}, where \Lambda(t) = \pi^{-it/2} \Gamma(\frac{1/2+it}{2}) \zeta(\frac12 + it) is defined at the beginning of §3 of [Pla2017]. By the functional equation it is real for real t, it has the same zeros as \zeta(1/2 + it) [Pla2011], and the exponential factor cancels the decay of the gamma factor.
void acb_dirichlet_platt_scaled_lambda_vec(arb_ptr res, const fmpz_t T, slong A, slong B, slong prec)Sets res to the values of acb_dirichlet_platt_scaled_lambda at the N = AB grid points T - B/2 + k/A, 0 \le k < N, by evaluating each point separately. N must be even.
void acb_dirichlet_platt_multieval(arb_ptr out, const fmpz_t T, slong A, slong B, const arb_t h, const fmpz_t J, slong K, slong sigma, slong prec)void acb_dirichlet_platt_multieval_threaded(arb_ptr out, const fmpz_t T, slong A, slong B, const arb_t h, const fmpz_t J, slong K, slong sigma, slong prec)Set out to the values of acb_dirichlet_platt_scaled_lambda on the same grid as acb_dirichlet_platt_scaled_lambda_vec, all at once with discrete Fourier transforms, in the notation of [Pla2017]: h is the width of the Gaussian, J the number of terms of the Dirichlet series, K the number of Taylor terms and sigma an odd integer used in the error bounds. The threaded version uses flint_get_num_threads() threads; the default version decides whether to use threads.
If nonzero (the default), acb_dirichlet_platt_multieval computes the sums over j with double-word arithmetic when the precision allows it. Set it to 0 to always use ball arithmetic.
void acb_dirichlet_platt_ws_interpolation(arb_t res, arf_t deriv, const arb_t t0, arb_srcptr p, const fmpz_t T, slong A, slong B, slong Ns_max, const arb_t H, slong sigma, slong prec)Sets res to acb_dirichlet_platt_scaled_lambda at t_0, by Gaussian-windowed Whittaker–Shannon interpolation of the grid values p. If deriv is not NULL, it is set to an approximation of the derivative. Ns_max is the maximum number of grid points used on either side of t_0, H is the standard deviation of the Gaussian window, and sigma is an odd positive integer used in the error bounds.
slong _acb_dirichlet_platt_local_hardy_z_zeros(arb_ptr res, const fmpz_t n, slong len, const fmpz_t T, slong A, slong B, const arb_t h, const fmpz_t J, slong K, slong sigma_grid, slong Ns_max, const arb_t H, slong sigma_interp, slong prec)Set at most len entries of res to consecutive zeros \gamma_n, \ldots of the Hardy Z-function and return the number found. The local versions make one grid evaluation; acb_dirichlet_platt_hardy_z_zeros repeats them until len zeros are found. The parameters of the underscore version have the meanings of acb_dirichlet_platt_multieval and acb_dirichlet_platt_ws_interpolation.
slong acb_dirichlet_platt_isolate_local_hardy_z_zeros(arf_interval_ptr res, const fmpz_t n, slong len, slong prec)slong _acb_dirichlet_platt_isolate_local_hardy_z_zeros(arf_interval_ptr res, const fmpz_t n, slong len, const fmpz_t T, slong A, slong B, const arb_t h, const fmpz_t J, slong K, slong sigma_grid, slong Ns_max, const arb_t H, slong sigma_interp, slong prec)Like the local functions above, but set res to isolating intervals of the zeros instead of refining them.
Sets at most len entries of res to consecutive zeros \rho_n, \ldots of \zeta(s) by Platt's method, and returns the number found.
The secondary zeta function#
void acb_dirichlet_secondary_zeta(acb_t res, const acb_t s, slong prec)Sets res to the secondary zeta function Z(s) = \sum_{n=1}^{\infty} \gamma_n^{-s}, where \rho_n = 1/2 + i\gamma_n runs over the zeros of \zeta(s) with positive imaginary part. The Riemann hypothesis is not assumed. The algorithm follows [Ari2020], with the decomposition Z(s) = A(s) - P(s) + E(s) - S(s) depending on a parameter a > 0, an improved tail bound for P, and rigorous bounds for the tails of A and S that replace the heuristic bounds of [Ari2020].
Internal functions#
void _acb_dirichlet_theta_argument_at_arb(arb_t xt, ulong q, const arb_t t, slong prec)Sets xt to \pi t^2 / q, the exponent of the theta series.
void _acb_dirichlet_theta_arb_series(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, const arb_t xt, slong len, slong prec)Sets res to \sum_{n=1}^{\text{len}-1} \chi(n) n^\delta x^{n^2} for x = xt, using acb_dirichlet_qseries_arb.
void mag_tail_kexpk2_arb(mag_t res, const arb_t a, ulong n)Sets res to an upper bound for \sum_{k > n} k e^{-a k^2}.
Sets res to the polynomial with the len coefficients v evaluated at z, by the baby-step giant-step method.
Returns the local factor at p (with p^e \| q and pe = p^e) of the Jacobi sum J_q(1, \chi) for a character of conductor cond. The value is a signed integer cast to ulong.
void acb_dirichlet_platt_beta(arb_t res, const arb_t t, slong prec)Sets res to \beta(t) = 1/6 + \log\log t / \log t, the exponent in the bound |\zeta(1/2 + it)| = O(t^{\beta(t)}) used in [Pla2017].
void acb_dirichlet_platt_lemma_32(arb_t out, const arb_t h, const arb_t t0, const arb_t x, slong prec)void acb_dirichlet_platt_lemma_A7(arb_t out, slong sigma, const arb_t t0, const arb_t h, slong k, slong A, slong prec)void acb_dirichlet_platt_lemma_A9(arb_t out, slong sigma, const arb_t t0, const arb_t h, slong A, slong prec)void acb_dirichlet_platt_lemma_B1(arb_t out, slong sigma, const arb_t t0, const arb_t h, const fmpz_t J, slong prec)Set out to the error bounds of Lemma 3.2 and Lemmas A.5, A.7, A.9, A.11, B.1 and B.2 of [Pla2017], which bound the errors of the grid evaluation in acb_dirichlet_platt_multieval (truncation of the Dirichlet series, of the Taylor expansion, aliasing of the discrete Fourier transform, and so on). Lemma A.5 requires B > h\sqrt{k}; when a lemma's hypotheses fail, the bound is infinite.
Precomputed constants of the interpolation error bounds.
void acb_dirichlet_platt_c_precomp_init(acb_dirichlet_platt_c_precomp_t pre, slong sigma, const arb_t h, ulong k, slong prec)void acb_dirichlet_platt_c_bound_precomp(arb_t res, const acb_dirichlet_platt_c_precomp_t pre, slong sigma, const arb_t t0, const arb_t h, slong k, slong prec)void acb_dirichlet_platt_c_bound(arb_t res, slong sigma, const arb_t t0, const arb_t h, slong k, slong prec)Set res to the bound C(\sigma, t_0, h, k) of [Pla2017] for the k-th derivative of the scaled function in the strip used for the error analysis, with or without precomputed constants that depend only on \sigma, h and k.
void acb_dirichlet_platt_i_precomp_init(acb_dirichlet_platt_i_precomp_t pre, slong A, const arb_t H, slong sigma, slong prec)void acb_dirichlet_platt_i_bound_precomp(arb_t res, const acb_dirichlet_platt_i_precomp_t pre_i, const acb_dirichlet_platt_c_precomp_t pre_c, const arb_t t0, slong A, const arb_t H, slong sigma, slong prec)void acb_dirichlet_platt_i_bound(arb_t res, const arb_t t0, slong A, const arb_t H, slong sigma, slong prec)Set res to the bound I of [Pla2017] for the error of the Whittaker–Shannon interpolation caused by the Gaussian window and the sampling rate A, with or without precomputed constants.
void acb_dirichlet_platt_ws_precomp_init(acb_dirichlet_platt_ws_precomp_t pre, slong A, const arb_t H, slong sigma, slong prec)void acb_dirichlet_platt_ws_interpolation_precomp(arb_t res, arf_t deriv, const acb_dirichlet_platt_ws_precomp_t pre, const arb_t t0, arb_srcptr p, const fmpz_t T, slong A, slong B, slong Ns_max, const arb_t H, slong sigma, slong prec)The interpolation acb_dirichlet_platt_ws_interpolation with the constants of both bounds precomputed, for many evaluations with the same A, H and \sigma.
References#
- [Rad1973] H. Rademacher, Topics in analytic number theory, Springer, 1973.
- [Ari2011] J. Arias de Reyna, "High precision computation of Riemann’s zeta function by the Riemann-Siegel formula, I", Mathematics of Computation 80 (2011), 995-1009
- [Joh2018b] F. Johansson and others, "mpmath: a Python library for arbitrary-precision floating-point arithmetic (version 1.1.0)", December 2018. https://mpmath.org/
- [Ari2012] J. Arias de Reyna, "Programs for Riemann's zeta function", (J. A. J. van Vonderen, Ed.) Leven met getallen : liber amicorum ter gelegenheid van de pensionering van Herman te Riele CWI (2012) 102-112, https://ir.cwi.nl/pub/19724
- [Tur1953] A. M. Turing, "Some Calculations of the Riemann Zeta-Function", Proc. of the London Mathematical Society 3(3) (1953), 99-117, https://doi.org/10.1112/plms/s3-3.1.99
- [Leh1970] R. S. Lehman, "On the Distribution of Zeros of the Riemann Zeta-Function", Proc. of the London Mathematical Society 20(3) (1970), 303-320, https://doi.org/10.1112/plms/s3-20.2.303
- [Bre1979] R. P. Brent, "On the Zeros of the Riemann Zeta Function in the Critical Strip", Mathematics of Computation 33 (1979), 1361-1372, https://doi.org/10.1090/S0025-5718-1979-0537983-2
- [Tru2011] T. S. Trudgian, "Improvements to Turing's method", Mathematics of Computation 80 (2011), 2259-2279, https://doi.org/10.1090/S0025-5718-2011-02470-1
- [Tru2014] T. S. Trudgian, "An improved upper bound for the argument of the Riemann zeta-function on the critical line II", Journal of Number Theory 134 (2014), 280-292, https://doi.org/10.1016/j.jnt.2013.07.017
- [Pla2017] D. J. Platt, "Isolating some non-trivial zeros of zeta", Mathematics of Computation 86 (2017), 2449-2467, https://doi.org/10.1090/mcom/3198
- [Pla2011] D. J. Platt, "Computing degree 1 L-functions rigorously", Ph.D. Thesis, University of Bristol (2011), https://people.maths.bris.ac.uk/~madjp/thesis5.pdf
- [Ari2020] J. Arias de Reyna, "Computation of the secondary zeta function", https://arxiv.org/abs/2006.04869
The FLINT team, “acb_dirichlet.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/acb_dirichlet/index.html (generated 2026-10-20).
@misc{flint-doc-acb-dirichlet-index,
author = {{The FLINT team}},
title = {{acb\_dirichlet.h (module overview)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/acb_dirichlet/index.html},
note = {Generated 2026-10-20}
}