Binary splitting and product trees
- Cost
- A product of integers of total size bits in for factors; bits of a hypergeometric series in ; reduction modulo moduli of total size and the inverse CRT in .
Many computations with large integers produce the result as a product or a sum of many small terms: a factorial is a product of word-size integers, a partial sum of the series of or is a sum of rational numbers with growing numerators and denominators, and Chinese remaindering combines residues modulo many primes. Done term by term, such computations multiply a large number by a small one at every step and cost for an -bit result. Organising the work as a balanced binary tree, so that operands of similar size are multiplied at each level, reduces the cost to or , where is the cost of an -bit multiplication; with FFT multiplication this is quasi-linear.
Product trees#
To compute , split the list in halves, compute the two partial products recursively and multiply them.
Proposition 1. Let be positive integers with . The balanced product tree computes in bit operations, assuming that is nondecreasing. The sequential product costs word operations, where is the number of factors with at least one word, which is for word-size factors.
Proof. At each level of the tree the operands are partial products of disjoint sublists, so their total size is at most bits. A level multiplies pairs of operands of sizes and with , at a cost of , by the monotonicity of . There are levels. Sequentially, the -th step multiplies a partial product of up to bits by a factor, which costs word operations for a factor of one word , and there are such steps.
In practice the leaves of the tree are blocks of factors multiplied sequentially, since multiplying a number of a few words by one word is cheapest done directly, and several small factors are packed into one word before they enter the tree. If the factors have very different sizes, a balanced split by count is not optimal; combining the two smallest current operands, as in the construction of a Huffman code, keeps the products balanced by size.
Binary splitting for series#
A sum of the form
with integer-valued , , covers the hypergeometric series used for , , logarithms of rationals, Euler's constant and many special functions at rational points [Bre1976] [HP1998]. Define, for a range ,
Theorem 2. is an integer, and for ,
Proof. Splitting the sum at ,
because the terms with carry the factor in addition to the factors of . Multiplying by gives the formula for . Integrality follows by induction from .
Applying the theorem recursively evaluates with a tree of products, followed by one division. If , , are polynomials, , and over a range of length have bits, so the products at each level have total size bits. For a series that converges geometrically, terms give bits, and the cost is bit operations. The product is only needed for left children and is skipped along the right spine of the tree; when divides , the leaves can be evaluated with smaller numbers. Common factors of and , such as powers of two, can be removed at each node.
For example, has , for (with ) and , so and ; about terms give bits.
Remainder trees and the Chinese remainder theorem#
Product trees also speed up the two directions of multimodular arithmetic [BorMoe1974] [Ber2008]. Let be pairwise coprime with product .
Reduction. To compute for all , build the product tree of the moduli and reduce top-down: reduce modulo the product at the root, then each remainder modulo the products of the two children, and so on down to the leaves. Each level costs for , so the total is , instead of word operations for separate reductions of a number of bits by word-size moduli. Bernstein's scaled remainder trees [Ber2004] replace the divisions by multiplications with precomputed approximations.
Reconstruction. With and , the integer
satisfies for all . The sum is evaluated bottom-up in the product tree: a node with children and combines their values as , which is Theorem 2 with all ratios equal to 1. A single reduction modulo at the end puts in the desired range. The cost is again .
Use in FLINT#
Product trees.
_fmpz_vec_prodsplits the vector in halves down to three entries, and_fmpz_ui_vec_proddown to 15 words, which are multiplied in sequence.fmpz_primorialmultiplies the primes up to with a balanced tree over limb arrays (mpn_prod_limbs_balanced), with sequential products of fewer than 50 factors at the leaves._fmpz_rfac_ui, behindfmpz_rfac_uiandfmpz_rfac_uiui, splits the range of factors in halves and packs as many consecutive factors into one word as fit at the leaves.fmpz_fac_ui(for ) calls GMP'smpz_fac_ui, which uses Luschny's prime-swing algorithm and multiplies the factors in product trees [Lus2008] [GMP];fmpz_bin_uiuicalls GMP'smpz_bin_uiui._gr_vec_productin the generic rings uses a parallel balanced product tree (flint_parallel_binary_splitting) for long vectors, and the polynomial analogue of product trees, the subproduct tree, is described in Multipoint evaluation and interpolation.fmpz_set_strconverts long decimal strings by splitting them in halves and combining the parts with powers of , in parallel; Radix conversion describes radix conversion in both directions.
Huffman trees. fmpz_multi_CRT_precompute and fmpz_multi_mod_precompute build their straight-line programs by repeatedly combining the two smallest moduli, which keeps the products balanced by size when the moduli have different sizes (Chinese remaindering).
Remainder trees and CRT for word-size moduli. fmpz_comb_t (behind fmpz_multi_mod_ui, fmpz_multi_CRT_ui and _fmpz_vec_multi_CRT_ui) wraps flint_mpn_crt_t of mpn_extras, which refines the scheme above in three ways. Small primes are batched into leaves of one word (for example pairs of 32-bit primes), and the leaf residues are split and combined with word arithmetic. Consecutive leaves are grouped into chunks of up to 2048 bits, which are the leaves of the product tree; within a chunk, the reconstruction is a linear combination with precomputed multipliers and the reduction is a dot product of the limbs of the input with precomputed powers . In the reconstruction, the nodes are combined as above without intermediate reductions, the values growing by at most one bit per level, and a single reduction modulo the product of all primes is done at the end. Large nodes are processed in parallel; Multimodular reduction and Chinese remaindering describes this design in detail. The multimodular algorithms of fmpz_mat (multiplication, characteristic polynomial), fmpz_poly (GCD, resultant, interpolation, Taylor shift), arith and bernoulli use this code for their Chinese remaindering.
Binary splitting for series.
mp_real_hypgeom_seriesandmp_real_hypgeom_series_int64implement binary splitting for general hypergeometric series in the format of Theorem 2, with leaves of several terms evaluated in limb arithmetic and the final division done once. The constants (Chudnovsky's series), , and Euler's constant, and thearbconstantsarb_const_piandarb_const_ethat call them, are computed this way, as are tables of and for the elementary functions.- The
arbelementary functions use binary splitting of the Taylor series of , , and at high precision (_arb_exp_sum_bs_powtab,_arb_atan_sum_bs_powtab), with a table of the powers of the argument needed at each level of the tree. fmpq_harmonic_uicomputes the harmonic number exactly by binary splitting over the odd denominators only, each weighted by the contribution of its multiples by powers of two.arb_hypgeom_sum_fmpq_arbandacb_hypgeom_pfq_sum_bssum hypergeometric series with rational parameters,arb_hypgeom_rising_ui_bscomputes rising factorials, andarith_stirling_number_1uand related functions expand by binary splitting over polynomials.
void _fmpz_vec_prod(fmpz_t res, const fmpz * vec, slong len)void fmpz_primorial(fmpz_t res, ulong n)void fmpz_rfac_ui(fmpz_t r, const fmpz_t x, ulong n)int fmpz_multi_CRT(fmpz_t output, const fmpz * moduli, const fmpz * values, slong len, int sign)void fmpz_multi_mod_ui(ulong * out, const fmpz_t in, const fmpz_comb_t C, fmpz_comb_temp_t CT)Referenced from#
- Binary splitting of hypergeometric series in mp_real (algorithm)
- Multiplying integers (overview)
- Continued fractions of rational numbers (algorithm)
- The gamma function (algorithm)
- Hypergeometric functions (algorithm)
arb_hypgeom_rising_ui_forward,arb_hypgeom_rising_ui_bs,arb_hypgeom_rising_ui_rs,arb_hypgeom_rising_ui_rec,arb_hypgeom_rising_ui,arb_hypgeom_risingfmpq_harmonic_ui,_fmpq_harmonic_ui- Chinese remaindering
- fmpz.h (module)
_fmpz_vec_prod,_fmpz_ui_vec_prod_gr_vec_sum,_gr_vec_product- Computing π and other constants (tutorial)
- Summing a series with a rigorous error bound (tutorial)
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
- [BorMoe1974] A. Borodin and R. Moenck, "Fast modular transforms", Journal of Computer and System Sciences 8:3 (1974), 366–386
- [Ber2008] D. J. Bernstein, "Fast multiplication and its applications", in Algorithmic Number Theory, MSRI Publications 44 (2008), 325–384
- [Ber2004] D. J. Bernstein. Scaled remainder trees. Preprint, 2004. https://cr.yp.to/arith/scaledmod-20040820.pdf
- [Lus2008] P. Luschny. Fast factorial functions. Web page, 2008. http://www.luschny.de/math/factorial/FastFactorialFunctions.htm
- [GMP] T. Granlund and the GMP development team. GNU MP: The GNU Multiple Precision Arithmetic Library, version 6.3.0. Manual, 2023. https://gmplib.org/manual/
The FLINT team, “Binary splitting and product trees,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/integers/binary-splitting.html (generated 2026-11-02).
@misc{flint-doc-algorithms-integers-binary-splitting,
author = {{The FLINT team}},
title = {{Binary splitting and product trees}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/integers/binary-splitting.html},
note = {Generated 2026-11-02}
}