FLINT3.7.0-dev

Sieved power sums with dfloat balls

Synopsis#include <flint/dfloat.h>
int gr_powsum_sieved(acb_t res, const acb_t s, ulong N, gr_ctx_t T, gr_ctx_t P, gr_ctx_t F, double dm, double da, ulong M)source

Sets res to an enclosure of ∑n=1Nn−s\sum_{n=1}^N n^{-s}, as acb_dirichlet_powsum_sieved with len = 1, computed with the ball ring TT for the terms, the ball ring PP for the phases and optionally the plain ring FF for the composite terms and block sums (NULL: all balls), whose products and sums have relative errors at most dm and da. M is the table bound (0 for the default). Returns a gr status.

int dfloat_powsum_sieved(acb_t res, const acb_t s, ulong N, slong prec)source
int _dfloat_powsum_sieved(acb_t res, const acb_t s, ulong N, int tn, int pn, ulong M)source
int _dfloat_powsum_sieved_ball(acb_t res, const acb_t s, ulong N, int tn, int pn, ulong M)source

The dfloat instantiations of gr_powsum_sieved, with terms in dTb and phases in dPb for (T,P)(T, P) = (tn, pn) one of (1,2)(1, 2), (1,3)(1, 3), (2,3)(2, 3), (2,4)(2, 4), (3,4)(3, 4). dfloat_powsum_sieved chooses TT and PP for about prec bits after the binary point. They return 1 on success and 0, leaving res undefined, for unsupported arguments.

These functions compute the partial sums

S=∑n=1Nn−sS = \sum_{n=1}^{N} n^{-s}

that make up the main sum of the Riemann–Siegel formula for ζ(s)\zeta(s) at large height t=Im⁡(s)t = \operatorname{Im}(s). gr_powsum_sieved is a generic implementation over three rings given at run time, and dfloat_powsum_sieved instantiates it with dfloat balls and plain expansions. acb_dirichlet_zeta_rs_r calls dfloat_powsum_sieved for N≥16N \ge 16 and falls back to acb_dirichlet_powsum_sieved when it returns 0; this makes the Riemann–Siegel evaluations used to isolate zeros 17 to 18 times faster at the heights of the 101510^{15}-th to 101710^{17}-th zeros.

The algorithm#

The algorithm is that of acb_dirichlet_powsum_sieved. The function f(n)=n−sf(n) = n^{-s} is completely multiplicative, so the term of a composite nn is the product f(d)f(n/d)f(d) f(n/d) with dd the smallest prime factor of nn, taken from a table of f(k)f(k) for odd k≤N/3k \le N/3; only the prime terms need logarithms, sines, cosines and exponentials. The even nn are handled by Horner's rule in 2−s2^{-s} over the dyadic ranges of the odd part.

The implementation rearranges this so that all the bulk work goes through vector operations of the generic rings:

  • the odd numbers are processed in blocks of 4096 with a segmented sieve that carries, for each small prime, its next multiple and the cofactor of that multiple, so that no divisions are needed;
  • the primes of a block are evaluated together: _gr_vec_log in the phase ring PP, the phase (t/2π)log⁡p(t/2\pi)\log p reduced by subtracting a nearby integer exactly, rounded to the term ring TT with _gr_vec_set_other, then _gr_vec_sin_cos, _gr_vec_exp and _gr_vec_mul; on the critical line σ=1/2\sigma = 1/2 the magnitudes p−1/2p^{-1/2} come from _gr_vec_rsqrt instead of the exponential;
  • the composite terms of a block are gathered from the table with _gr_vec_gather (real and imaginary parts interleaved, so that a lookup touches one cache line), multiplied with four _gr_vec_mul, and scattered back with _gr_vec_scatter;
  • the terms of each dyadic range are summed pairwise with _gr_vec_add.

The phase ring PP needs about log⁡2(tlog⁡N)\log_2(t \log N) more bits than the term ring TT, because the phase tlog⁡pt \log p is reduced modulo 2π2\pi.

Bounded memory: the two-phase version#

The table of f(k)f(k) for k≤N/3k \le N/3 takes 8N/38N/3 bytes per double of the table ring, which limits the plain algorithm. With a table bound N2/3≤M<N/3N^{2/3} \le M < N/3, the odd k≤Mk \le M are processed as above, and among the odd c>Mc > M only the roots are computed: the primes and the composites with cofactor c/d≤Mc/d \le M. Every n≤Nn \le N whose odd part exceeds MM is uniquely n=mcn = mc with cc a root and m≤N/c<N/Mm \le N/c < N/M an integer whose odd part has no prime factor above dd (the chain of divisions of nn by its smallest prime factor reaches cc as its last element above MM). Hence

∑n≤Nf(n)=∑jf(2)j∑k oddk≤min⁡(M,N/2j)f(k)+∑c rootf(c) G(⌊N/c⌋,dc),\sum_{n \le N} f(n) = \sum_j f(2)^j \sum_{\substack{k \text{ odd} \\ k \le \min(M, N/2^j)}} f(k) + \sum_{c \text{ root}} f(c)\, G(\lfloor N/c \rfloor, d_c),

where G(z,p)G(z, p) is the sum of f(m)f(m) over the m≤zm \le z whose odd part has no prime factor above pp, and dc=∞d_c = \infty for a prime cc. With Z=⌊N/(M+1)⌋≤N1/3Z = \lfloor N/(M+1) \rfloor \le N^{1/3}, the values of GG form a table of about Z2/(2log⁡Z)Z^2/(2\log Z) entries. The second phase gathers G(⌊N/c⌋,dc)G(\lfloor N/c \rfloor, d_c) for each root and needs one complex product per root; all other composites (all but a fraction of about 1.12/log⁡(N/M)1.12/\log(N/M)) are never computed.

The default table bound (M = 0) is the full table for N<2048N < 2048 and ⌈N2/3⌉\lceil N^{2/3} \rceil otherwise. Besides bounding the memory by O(N2/3)O(N^{2/3}), this is faster, since the table fits in the cache and fewer products are needed: at N=108N = 10^8, with (T,P)=(1,3)(T, P) = (1, 3), the time per term drops from 24.6 to 15.8 ns and the memory from 262 MB to 11 MB.

The second phase, all but O(N2/3)O(N^{2/3}) of the work, is split into chunks of at least 2182^{18} odd numbers, each with its own sieve state, and run with flint_parallel_do on flint_get_num_threads threads. The partial sums are added in the order of the chunks, so the result does not depend on the number of threads.

Error bounds#

With F = NULL, every term is a ball and the result is rigorous by construction. With a plain ring FF, only the prime terms are balls, and the error of the composite terms and block sums is bounded a priori and added per dyadic range. With ε\varepsilon the largest relative radius of a prime term (obtained with _gr_vec_get_interval_mid_rad) and μ=2(δm+δa+δmδa)\mu = \sqrt{2}(\delta_m + \delta_a + \delta_m \delta_a) the relative error of a plain complex product, a term f(n)f(n) with Ω(n)\Omega(n) prime factors has a relative error of at most (1+ε)Ω(1+μ)Ω−1−1(1 + \varepsilon)^{\Omega}(1 + \mu)^{\Omega - 1} - 1, where Ω≤log⁡3N\Omega \le \log_3 N; the pairwise sums of at most 4096 terms add (1+δa)12−1(1 + \delta_a)^{12} - 1 times the sum of the magnitudes, which is bounded by an integral. In the two-phase version, the sum over the roots of g(c)=c−σg(c) = c^{-\sigma} times the sum of g(m)g(m) over the corresponding mm is exactly the sum of g(n)g(n) over the n≤Nn \le N with odd part above MM, so the bound is as tight as in the first phase.

The dfloat instantiation uses δm=δa=u\delta_m = \delta_a = u for d1 and δm=8u2\delta_m = 8u^2, δa=3u2\delta_a = 3u^2 for d2, u=2−53u = 2^{-53}, from the error analysis of the kernels (Double-word and multi-double arithmetic); the phase context is strong (canonical), so that rounding the reduced phases to TT is a truncation.

Choosing the precisions#

dfloat_powsum_sieved chooses TT so that the terms have b=prec+log⁡2(N)/2+8b = \mathit{prec} + \log_2(N)/2 + 8 bits (the accumulated error grows like NuT\sqrt{N} u^T, so that the result has about prec bits after the binary point), and PP so that the phase tlog⁡Nt \log N leaves b+6b + 6 bits after the binary point. With P=4P = 4, a phase short by up to 8 bits is accepted. It returns 0 if no pair (T,P)(T, P) in {(1,2),(1,3),(2,3),(2,4),(3,4)}\{(1, 2), (1, 3), (2, 3), (2, 4), (3, 4)\} fits, if ∣Re⁡(s)∣>210|\operatorname{Re}(s)| > 2^{10}, ∣t∣≥1060|t| \ge 10^{60} or N≥250N \ge 2^{50}, if the tables would take more than DFLOAT_POWSUM_MAX_BYTES, or if dfloat_is_supported returns 0. The plain composites are used for T≤2T \le 2; _dfloat_powsum_sieved_ball keeps every term a ball (and is the only variant for T=3T = 3): its radii are about 10 times smaller and it is 20 to 30% slower.

Performance#

At the height of the 101510^{15}-th zero (t≈2.1⋅1014t \approx 2.1 \cdot 10^{14}, N=5 760 732N = 5\,760\,732, one core), acb_dirichlet_powsum_sieved at 179 bits takes 2.4 s, while the full-table dfloat version takes 0.13 s with (1,2)(1, 2) (radius 2−302^{-30}), 0.27 s with (2,3)(2, 3) (radius 2−792^{-79}) and 0.60 s with (3,4)(3, 4) (radius 2−1332^{-133}); the default two-phase version is another 25 to 30% faster. About half of the time goes to the prime terms, a quarter to the composites (dominated by cache misses of the table lookups), and the rest to the sieve and the sums. At low heights the fixed setup cost of a few microseconds makes the arb_t version faster for N<16N < 16, which is why acb_dirichlet_zeta_rs_r uses the dfloat version only from N=16N = 16 on.

Cite this page

The FLINT team, “Sieved power sums with dfloat balls (dfloat.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/dfloat/powsum.html (generated 2026-11-02).