FLINT3.7.0-dev

Bell numbers

Synopsis#include <flint/arith.h>
void arith_bell_number(fmpz_t b, ulong n)source
void arith_bell_number_dobinski(fmpz_t res, ulong n)source
void arith_bell_number_multi_mod(fmpz_t res, ulong n)source

Set the result to the Bell number BnB_n. The default version uses a table for n≤25n \le 25 (64-bit), the Bell triangle in fixed-size multiword arithmetic for n≤58n \le 58, Dobiński's formula for n≤3400n \le 3400 and the multimodular algorithm above.

The dobinski version computes P=N!∑k=0Nkn/k!P = N! \sum_{k=0}^N k^n/k! and Q=N!∑k=0N1/k!≈N! eQ = N! \sum_{k=0}^N 1/k! \approx N!\, e for N≈n(1+1.2/log⁡n)N \approx n (1 + 1.2/\log n) and returns ⌈P/Q⌉\lceil P/Q \rceil, an exact form of Dobiński's formula Bn=e−1∑k≥0kn/k!B_n = e^{-1} \sum_{k \ge 0} k^n/k! [Dob1877] without floating-point arithmetic. Powers of even kk are obtained from those of odd kk by shifts.

The multi_mod version computes BnB_n modulo primes of FLINT_BITS−3\mathtt{FLINT\_BITS} - 3 bits with the sum used by arith_bell_number_nmod, in Montgomery arithmetic and with powers jnj^n for composite jj obtained as products from a divisor table, and combines the residues by Chinese remaindering. The number of primes is determined by arith_bell_number_size. The primes are processed in parallel with the threads set by flint_set_num_threads.

void arith_bell_number_vec(fmpz * b, slong n)source
void arith_bell_number_vec_recursive(fmpz * b, slong n)source
void arith_bell_number_vec_multi_mod(fmpz * b, slong n)source

Set bb to B0,B1,…,Bn−1B_0, B_1, \ldots, B_{n-1}. The recursive version uses the Bell triangle (Aitken's array), with O(n2)O(n^2) additions of numbers of O(nlog⁡n)O(n \log n) bits; the multi_mod version computes the vector modulo word-size primes with arith_bell_number_nmod_vec and combines them by Chinese remaindering, in O(n2log⁡O(1)n)O(n^2 \log^{O(1)} n). The default version uses the recursive algorithm for n<5000n < 5000.

ulong arith_bell_number_nmod(ulong n, nmod_t mod)source

Returns BnB_n modulo the modulus of mod, which can be any integer ≥1\ge 1.

Small nn are read from the table, and the moduli 2 and 3 use the periods 3 and 13 of the sequence. If nn is less than the modulus and n!n! is invertible, the function evaluates

Bn=∑k=0n(n−k)n(n−k)!∑j=0k(−1)jj!B_n = \sum_{k=0}^n \frac{(n-k)^n}{(n-k)!} \sum_{j=0}^k \frac{(-1)^j}{j!}

with the factorials scaled by n!n! so that the main loop only multiplies, the powers of composite numbers sieved from those of their factors, and the sum accumulated in three words; this costs O(n)O(n) multiplications and O(n)O(n) memory. Otherwise it computes B0,…,BnB_0, \ldots, B_n with arith_bell_number_nmod_vec (and throws if n>2FLINT_BITS−3n > 2^{\mathtt{FLINT\_BITS} - 3}).

void arith_bell_number_nmod_vec(nn_ptr b, slong n, nmod_t mod)source
void arith_bell_number_nmod_vec_recursive(nn_ptr b, slong n, nmod_t mod)source
void arith_bell_number_nmod_vec_ogf(nn_ptr b, slong n, nmod_t mod)source
int arith_bell_number_nmod_vec_series(nn_ptr b, slong n, nmod_t mod)source

Set bb to B0,…,Bn−1B_0, \ldots, B_{n-1} modulo the modulus of mod.

The recursive version uses the Bell triangle, with O(n2)O(n^2) additions. The ogf version expands the ordinary generating function

∑n≥0Bnxn=∑k≥0xk(1−x)(1−2x)⋯(1−kx)\sum_{n \ge 0} B_n x^n = \sum_{k \ge 0} \frac{x^k}{(1 - x)(1 - 2x) \cdots (1 - kx)}

truncated to length nn, with the partial sums computed by binary splitting as a fraction R/QR/Q and one power series division, in O(M(n)log⁡n)O(M(n) \log n). The series version computes exp⁡(ex−1)\exp(e^x - 1) as a power series and multiplies by factorials, in O(M(n))O(M(n)); it requires (n−1)!(n-1)! to be invertible modulo the modulus and returns 0 (with bb unspecified) if it is not, 1 on success. The recursive and ogf versions work for any modulus. The default version uses the recursive algorithm for n<300n < 300, the series version if the modulus is at least nn and it succeeds, the recursive algorithm for n<500+bits2n < 500 + \mathit{bits}^2 where bits\mathit{bits} is the bit size of the modulus, and the ogf version otherwise.

double arith_bell_number_size(ulong n)source

Returns bb such that Bn<2⌊b⌋B_n < 2^{\lfloor b \rfloor}, from de Bruijn's asymptotic expansion of log⁡Bn\log B_n [deB1958] with a margin. The bound is verified for n<264n < 2^{64} but not proved in general; an earlier version used the weaker bound Bn<(0.792n/log⁡(n+1))nB_n < (0.792n/\log(n+1))^n of [BerTas2010].

The Bell number BnB_n is the number of partitions of a set of nn elements: B0,B1,…=1,1,2,5,15,52,203,…B_0, B_1, \ldots = 1, 1, 2, 5, 15, 52, 203, \ldots In terms of Stirling numbers of the second kind, Bn=∑k=0nS(n,k)B_n = \sum_{k=0}^n S(n,k), and the exponential generating function is ∑n≥0Bnxn/n!=exp⁡(ex−1)\sum_{n \ge 0} B_n x^n/n! = \exp(e^x - 1) [Comtet1974]. The numbers grow slightly slower than n!n!: log⁡Bn=n(log⁡n−log⁡log⁡n−1+o(1))\log B_n = n(\log n - \log\log n - 1 + o(1)), 6403 bits for n=1000n = 1000.

The module computes an isolated BnB_n (arith_bell_number), the vector B0,…,Bn−1B_0, \ldots, B_{n-1} (arith_bell_number_vec), and the same modulo a word-size integer (arith_bell_number_nmod, arith_bell_number_nmod_vec), which is much cheaper when only the residue is needed.

AlgorithmStirling and Bell numbersIsolated Stirling numbers by binary splitting of rising factorials, power sums or power series, chosen by k/n; rows by convolution; Bell numbers by Dobiński's formula, a multimodular sum, the Bell triangle or generating functions modulo primes.

Isolated values#

arith_bell_number reads BnB_n from a table for n≤25n \le 25 (64-bit), runs the Bell triangle in fixed-size arrays of up to three words for n≤58n \le 58, uses Dobiński's formula

Bn=1e∑k=0∞knk!B_n = \frac{1}{e} \sum_{k=0}^{\infty} \frac{k^n}{k!}

for n≤3400n \le 3400, in an exact form without floating-point arithmetic (arith_bell_number_dobinski), and the multimodular algorithm above (arith_bell_number_multi_mod). The latter computes BnB_n modulo primes p>np > n of FLINT_BITS−3\mathtt{FLINT\_BITS} - 3 bits with the identity

Bn=∑k=0n(n−k)n(n−k)!∑j=0k(−1)jj!,B_n = \sum_{k=0}^n \frac{(n-k)^n}{(n-k)!} \sum_{j=0}^k \frac{(-1)^j}{j!},

which needs O(n)O(n) multiplications modulo pp per prime, and combines the residues by Chinese remaindering; the primes are processed in parallel by the threads of flint_set_num_threads. About nlog⁡2n/FLINT_BITSn \log_2 n / \mathtt{FLINT\_BITS} primes are needed, so the residues cost O(n2log⁡n)O(n^2 \log n) bit operations.

Vectors#

The Bell triangle (Aitken's array) computes B0,…,Bn−1B_0, \ldots, B_{n-1} with n2/2n^2/2 additions: each row starts with the last entry of the previous row, and each further entry is the sum of its left neighbour and the entry above it; the rows start with the Bell numbers. Over Z\mathbb{Z} this costs O(n3log⁡n)O(n^3 \log n) bit operations and is used for n<5000n < 5000; for longer vectors arith_bell_number_vec_multi_mod computes the vector modulo word-size primes and reconstructs each entry with only as many primes as it needs.

Modulo mm, arith_bell_number_nmod_vec chooses between three methods: the triangle (O(n2)O(n^2) operations, any mm, used for n<300n < 300), the power series exp⁡(ex−1)\exp(e^x - 1) (O(M(n))O(M(n)) operations, requires (n−1)!(n-1)! to be invertible modulo mm, so in particular m≥nm \ge n for prime mm), and the ordinary generating function

∑n≥0Bnxn=∑k≥0xk(1−x)(1−2x)⋯(1−kx)\sum_{n \ge 0} B_n x^n = \sum_{k \ge 0} \frac{x^k}{(1 - x)(1 - 2x) \cdots (1 - kx)}

summed by binary splitting (O(M(n)log⁡n)O(M(n) \log n) operations, any mm).

Example#

The program prints the first Bell numbers, the size of B1000B_{1000}, and checks arith_bell_number_nmod against the residue of the exact value for the prime m=109+7m = 10^9 + 7 (where the series method applies) and for the modulus m=210=1024m = 2^{10} = 1024 (where it does not).

Examplearith_bell_basic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_vec.h>
#include <flint/nmod.h>
#include <flint/arith.h>

int main(void)
{
    fmpz * b;
    fmpz_t B;
    nmod_t mod;
    slong i;

    b = _fmpz_vec_init(10);
    arith_bell_number_vec(b, 10);
    flint_printf("B_0..B_9:");
    for (i = 0; i < 10; i++)
    {
        flint_printf(" ");
        fmpz_print(b + i);
    }
    flint_printf("\n");

    fmpz_init(B);
    arith_bell_number(B, 1000);
    flint_printf("B_1000 has %wu bits\n", fmpz_bits(B));

    nmod_init(&mod, 1000000007);
    flint_printf("mod 10^9+7: %wu %wu\n",
        arith_bell_number_nmod(1000, mod), fmpz_fdiv_ui(B, mod.n));
    nmod_init(&mod, 1024);
    flint_printf("mod 1024:   %wu %wu\n",
        arith_bell_number_nmod(1000, mod), fmpz_fdiv_ui(B, mod.n));

    fmpz_clear(B);
    _fmpz_vec_clear(b, 10);
    return 0;
}
Output
B_0..B_9: 1 1 2 5 15 52 203 877 4140 21147
B_1000 has 6403 bits
mod 10^9+7: 465231251 465231251
mod 1024:   443 443

References#

  • [Dob1877] G. Dobiński, "Summirung der Reihe ∑nm/n!\sum n^m/n! für m=1,2,3,4,5,…m = 1, 2, 3, 4, 5, \ldots", Archiv der Mathematik und Physik 61 (1877), 333–336.
  • [deB1958] N. G. de Bruijn, Asymptotic Methods in Analysis, North-Holland, 1958 (§6.2: Bell numbers).
  • [BerTas2010] D. Berend and T. Tassa : Improved bounds on Bell numbers and on moments of sums of random variables, Probability and Mathematical Statistics vol. 30 (2010) 185–205
  • [Comtet1974] L. Comtet, Advanced Combinatorics: The Art of Finite and Infinite Expansions, D. Reidel, 1974.
Cite this page

The FLINT team, “Bell numbers (arith.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/arith/bell.html (generated 2026-11-02).