FLINT3.7.0-dev
Algorithm

Binary splitting of hypergeometric series in mp_real

Cost
O(M(N)log⁡2N)O(M(N)\log^2 N) for NN bits of a geometrically convergent series with polynomial coefficients.

Binary splitting evaluates a sum of NN terms of a hypergeometric series exactly as a ratio of two integers, organised as a balanced tree so that the products at each level have similar sizes (Binary splitting and product trees) [Bre1976] [HP1998]. It is the method of choice for constants such as π\pi, ee, log⁡2\log 2 and ζ(3)\zeta(3), and for the Taylor series of elementary functions at a rational point (the bit-burst algorithm).

The recursion#

mp_real_hypgeom_series sums

S=cQ+cP∑k≥1P(k)Q(k)∏j=1k−1R(j)Q(j)cDS = \frac{c_Q + c_P\sum_{k \ge 1} \frac{P(k)}{Q(k)}\prod_{j=1}^{k-1}\frac{R(j)}{Q(j)}}{c_D}

(or its reciprocal) for integer polynomials PP, QQ, RR, in the format of y-cruncher's formula files [Yee2025]. Over a range [a,b)[a, b) of terms let

T(a,b)=∑k=ab−1P(k)∏j=ak−1R(j)∏j=k+1b−1Q(j),Q(a,b)=∏k=ab−1Q(k),R(a,b)=∏k=ab−1R(k),T(a, b) = \sum_{k=a}^{b-1} P(k)\prod_{j=a}^{k-1} R(j)\prod_{j=k+1}^{b-1} Q(j), \qquad Q(a, b) = \prod_{k=a}^{b-1} Q(k), \qquad R(a, b) = \prod_{k=a}^{b-1} R(k),

so that the partial sum over [a,b)[a, b), relative to the product of the ratios before aa, is T(a,b)/Q(a,b)T(a, b)/Q(a, b).

Proposition 1. For a<m<ba < m < b, with the left values T1,Q1,R1T_1, Q_1, R_1 over [a,m)[a, m) and the right values T2,Q2,R2T_2, Q_2, R_2 over [m,b)[m, b),

T(a,b)=T1Q2+R1T2,Q(a,b)=Q1Q2,R(a,b)=R1R2.T(a, b) = T_1 Q_2 + R_1 T_2, \qquad Q(a, b) = Q_1 Q_2, \qquad R(a, b) = R_1 R_2.

Proof. The terms with k<mk < m of T(a,b)T(a, b) are those of T1T_1 multiplied by ∏j=mb−1Q(j)=Q2\prod_{j=m}^{b-1} Q(j) = Q_2; the terms with k≥mk \ge m are those of T2T_2 multiplied by ∏j=am−1R(j)=R1\prod_{j=a}^{m-1} R(j) = R_1.

RR is needed only by left children, so the right spine of the tree skips it. The result is T(1,N+1)/Q(1,N+1)T(1, N+1)/Q(1, N+1) followed by one division and the scalar factors.

Leaves#

The tree splits at leaf boundaries, and a leaf of LL terms (24 to 32, or about 24 limbs of TT) is evaluated exactly in one scratch buffer by the backward recurrence

T←P(k) Qs+R(k) T,Qs←Q(k) Qs,Rs←R(k) Rs,T \gets P(k)\,Q_s + R(k)\,T, \qquad Q_s \gets Q(k)\,Q_s, \qquad R_s \gets R(k)\,R_s,

for kk from the end of the leaf down. When RR divides PP, P=ARP = AR (as for π\pi, log⁡2\log 2 and most formulas), the step becomes T←R(k)(T+A(k)Qs)T \gets R(k)(T + A(k)Q_s), where A(k)A(k) is typically a single word even when P(k)P(k) is not. The polynomial values are computed by Horner's rule in two's complement with a word count fixed by a bound on the values up to the last term: whole leaves at a time for single-word values, then mpn_mul_1 and mpn_addmul_1 passes with the signs folded in.

Common factors#

Content powers. When QQ (or RR) has a large constant content cc, such as q2q^2 in the series of atan⁡(p/q)\operatorname{atan}(p/q), the products are carried without it, Q(a,b)=cb−aQ′(a,b)Q(a, b) = c^{b-a}Q'(a, b), and the merges use T=T1Q2′cb−m+R1T2T = T_1 Q_2' c^{b-m} + R_1 T_2 with the pure powers cL2ic^{L2^i} taken from a table built by squarings over a perfectly balanced tree of 2J2^J leaves. This replaces a full-size product Q1Q2Q_1Q_2 by a short one but adds a product by a power, so it pays only when the content dominates: the table is used when the content has at least eight times the bits per term of the rest of QQ.

Content removal. A node only represents the ratios T/QT/Q and R/QR/Q, and g=gcd⁡(R1,Q2)g = \gcd(R_1, Q_2) divides TT, QQ and RR of the merge, so R1R_1 and Q2Q_2 can be divided by gg before the products [CHTZZ2007]. The cancellation is large: the final QQ shrinks from 230 to 50 bits per term for ζ(3)\zeta(3), from 64 to 19 for Catalan's constant, from 34 to 14 for log⁡2\log 2 and from 91 to 58 for π\pi. The gcd is not computed by an integer gcd but read off partial factorisations of QQ and RR over the primes below 2322^{32}, kept with every node: QQ and RR are factored over Z\mathbb{Z}, the values of their linear factors are factored by a segmented sieve in O(N)O(\sqrt N) memory, and a node's lists are merged from its children's. A prime shared by R(j)R(j) (left) and Q(k)Q(k) (right) divides a fixed linear combination of k−jk - j for each pair of linear factors, so only primes below a bound linear in the node's size need to be compared, and larger ones wait until the level at which they can cancel. The removal costs exact divisions, so it is done only where it pays (not near the root, and not at small precisions).

Truncation near the root#

All values are mp_real_t balls, and exact ones stay exact as long as they fit the working precision ww; near the root the products exceed ww limbs and are rounded, so the top levels of the tree are floating-point computations with rigorous radii. Content removal stops there, since it needs exact values.

Lemma 2. Let e1=exp⁡(T1)+exp⁡(Q2)e_1 = \operatorname{exp}(T_1) + \operatorname{exp}(Q_2) and e2=exp⁡(R1)+exp⁡(T2)e_2 = \operatorname{exp}(R_1) + \operatorname{exp}(T_2) be the sums of the limb exponents of the factors, g=e1−e2g = e_1 - e_2, and let T1Q2T_1Q_2 be rounded to ww limbs. Then at most w−g+1w - g + 1 limbs of R1T2R_1T_2 lie above the last limb of the rounded T1Q2T_1Q_2.

Proof. A product of balls with limb exponents ee and e′e' has its top limb at position e+e′−1e + e' - 1 or e+e′−2e + e' - 2 (in units of BB), so the rounded T1Q2T_1Q_2 ends at or above position e1−2−w+1=e1−w−1e_1 - 2 - w + 1 = e_1 - w - 1, and R1T2R_1T_2 starts at or below position e2−1e_2 - 1. The number of limb positions from e1−w−1e_1 - w - 1 to e2−1e_2 - 1 is e2−e1+w+1=w−g+1e_2 - e_1 + w + 1 = w - g + 1.

The sum takes nothing below the last limb of an inexact operand (Sums), so R1T2R_1T_2 is formed at w−g+1w - g + 1 limbs. For a convergent series, R1T2/Q1Q2R_1T_2/Q_1Q_2 is the right partial sum times the product of the left ratios, which is small: at the root gg is about half the working precision. Computing R1T2R_1T_2 at w−g+1w - g + 1 limbs cuts that product by a third at 10710^7 digits of π\pi.

Tail bound#

The number of terms NN is the least for which a rigorous bound on the tail is below the target. The product ∏j<k∣R(j)/Q(j)∣\prod_{j<k}|R(j)/Q(j)| is accumulated exactly (with bounded double rounding) for small jj and bounded in closed form beyond the point where every polynomial is dominated by its leading term; the terms beyond NN are bounded by a geometric series from leading-term bounds. The bound is added to the radius of the result, which therefore encloses the exact SS. A series whose ratio does not tend to a limit below 1 in absolute value, or whose bound cannot be established, throws.

Transform reuse in the merges#

At large sizes the products of a merge are FFT products, each costing two forward transforms, a pointwise product and an inverse transform. The four products of Proposition 1 come in two pairs with a common operand:

{T1Q2,  Q1Q2} share Q2,{R1T2,  R1R2} share R1.\{T_1 Q_2,\; Q_1 Q_2\} \text{ share } Q_2, \qquad \{R_1 T_2,\; R_1 R_2\} \text{ share } R_1.

Each pair is formed by _fft_small_mpn_mul_shared (Integer products with a common operand; see also multiplication with several primes), which computes the transform of the common operand once: three forward and two inverse transforms instead of four and two. The pairs are those that the two threads of a parallel merge take, so the sharing combines with parallelism.

A pair is shared when all three operands are exact and nonzero, both products are kept whole (at most ww limbs), and _flint_mpn_mul_shared_use_fft accepts the sizes (the longer product in the FFT range of flint_mpn_mul, the shorter in half of it). Near the root, where the products are truncated to middle products, separate products are used. The second product of each pair is written over its operand Q1Q_1 (resp. R1R_1), and a shared pair needs no more memory than one product, so the peak memory is unchanged. Measured on Emerald Rapids for π\pi, this makes the whole computation 6 to 10% faster at 10510^5 and 10610^6 digits, 4 to 5% at 10710^7 and 3% at 10810^8 on one thread, and 3 to 7% on two threads.

Summing T1Q2+R1T2T_1Q_2 + R_1T_2 in transform space, which would save one more inverse transform, is not done: Q2Q_2 lacks the low zero limbs stripped from its mantissa (the 2-adic part of QQ, for π\pi a third of its length), so the two products are aligned differently, and padding them to a common bottom lengthens every transform by more than the inverse transform saves.

Power tables with precomputed transforms#

The bit-burst splittings of the exponential and of the sine and cosine (Bit-burst evaluation) have P(k)=xP(k) = x (resp. x2x^2), a constant, so R1R_1 of a merge over [a,b)[a, b) with midpoint mm is the power xm−ax^{m-a}. The tree splits at fixed midpoints m=a+⌊(b−a)/2⌋m = a + \lfloor(b - a)/2\rfloor, so only O(log⁡N)O(\log N) distinct steps s=m−as = m - a occur, and the powers xsx^s are tabulated once (a power table, as in arb). Every merge with step ss multiplies xsx^s by its right child, so the fft_small transform of xsx^s can be computed once per tree, and each such product saves the conversion and forward transform of the table entry, about 30% of a two-prime product (_fft_small_mpn_mul_precomp, Integer products with a common operand).

Lemma 3. In a binary splitting of NN terms with fixed midpoints, the ranges of any level have at most two distinct lengths, differing by one. Consequently the number of merges using each step ss, and the longest right child among them, can be computed in O(log⁡N)O(\log N) operations from NN alone.

Proof. By induction on the level: if all ranges of a level have length ℓ\ell or ℓ+1\ell + 1, their halves have lengths ⌊ℓ/2⌋\lfloor\ell/2\rfloor, ⌈ℓ/2⌉\lceil\ell/2\rceil, ⌊(ℓ+1)/2⌋\lfloor(\ell+1)/2\rfloor and ⌈(ℓ+1)/2⌉\lceil(\ell+1)/2\rceil, which take at most two consecutive values. Tracking the (at most two) lengths and their multiplicities level by level gives the counts.

_mp_real_bs_step_uses computes these counts, and _mp_real_powtab_pre_init transforms the entries used by at least two merges, for partners up to the longest right child; the root's entry, the largest, is used once and is not transformed, since that would only add the storage of its transform. The transforms are made before the recursion and only read during it, so the two halves of a merge can use them on two threads. Their storage is one block, about four times the transform of the largest entry kept; entries whose products exceed 2202^{20} limbs are not transformed, which bounds the extra memory to about 50 MB per tree. Measured on Emerald Rapids, the exponential becomes 8% faster at 10610^6 digits and 5% at 3⋅1053 \cdot 10^5, the sine and cosine 4% and 3%; at 10710^7 digits the gain is about 3%, with 17% (exp) and 8% (sine and cosine) more peak memory.

Parallelism#

A splitting with a thread budget gives each half of a node half the threads, as flint_parallel_binary_splitting does, but only while the exact values of the node (estimated from the bits per term) stay within four times the working precision (MP_REAL_PAR_CAP). Above that, two concurrent halves would each hold full-size numbers, so they run one after the other with the whole budget, and the merge runs its two pairs of products on two threads, each pair's FFT using its half of the threads. The result does not depend on the number of threads.

Use in FLINT#

Referenced from#

References#

  • [Bre1976] R. P. Brent. The complexity of multiple-precision arithmetic. In R. S. Anderssen and R. P. Brent (eds.), The Complexity of Computational Problem Solving, University of Queensland Press, 1976, 126–165.
  • [HP1998] B. Haible and T. Papanikolaou, "Fast multiprecision evaluation of series of rational numbers", Algorithmic Number Theory (ANTS-III), LNCS 1423 (1998), 338–350
  • [Yee2025] A. J. Yee. y-cruncher: a multi-threaded pi-program, and its formula collection. http://www.numberworld.org/y-cruncher/ and https://github.com/Mysticial/y-cruncher-Formulas
  • [CHTZZ2007] H. Cheng, G. Hanrot, E. Thomé, E. Zima and P. Zimmermann. Time- and space-efficient evaluation of some hypergeometric constants. ISSAC 2007, 85–91. https://doi.org/10.1145/1277548.1277561
Cite this page

The FLINT team, “Binary splitting of hypergeometric series in mp_real,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/floating-point/hypergeometric-series.html (generated 2026-11-02).