FLINT3.7.0-dev

Isolated Bernoulli numbers

Synopsis#include <flint/bernoulli.h>
void bernoulli_fmpq_ui(fmpq_t b, ulong n)source
void _bernoulli_fmpq_ui(fmpz_t num, fmpz_t den, ulong n)source

Set the result to B_n in lowest terms with a positive denominator. The value is copied from the cache if it is there; the cache is not extended. Otherwise odd n and n < 18000 use _bernoulli_fmpq_ui_zeta, and larger even n use _bernoulli_fmpq_ui_multi_mod with the default tuning.

void _bernoulli_fmpq_ui_zeta(fmpz_t num, fmpz_t den, ulong n)source
void _bernoulli_fmpq_ui_multi_mod(fmpz_t num, fmpz_t den, ulong n, double alpha)source

Set num and den to the numerator and denominator of B_n in lowest terms, by two methods.

The zeta version computes the denominator d with arith_bernoulli_number_denom (von Staudt–Clausen), approximates B_n with arb_bernoulli_ui_zeta from |B_n| = 2\, n!\, \zeta(n)/(2\pi)^n at a precision slightly above the size of d B_n, and rounds d B_n to the unique integer in the resulting ball, increasing the precision if needed.

The multi_mod version computes the numerator modulo the product M of the primes 5 \le p with (p - 1) \nmid n (residues by bernoulli_mod_p_harvey, in parallel with the threads of flint_set_num_threads) up to a fraction alpha of the bits of the numerator, and the remaining high bits from the zeta function: the numerator is r + tM where r is the residue and t the unique integer in a ball for (d B_n - r)/M. The parameter 0 \le \alpha \le 1 balances the two parts; a negative value selects the default, 0 for n < 18000, 0.005 + 3.6 \cdot 10^{-6} n for n < 60000 and \min(0.18 + 0.5 \cdot 10^{-6} n, 0.28) above. For n < 10 or odd n the zeta version is called.

ulong bernoulli_mod_p_harvey(ulong n, ulong p)source

Returns B_n \bmod p for a prime p < 2^{\mathtt{FLINT\_D\_BITS}} (2^{53} on 64-bit machines), computed with Harvey's algorithm [Har2010] in time O(p \log^{O(1)} p), independent of n. If p divides the denominator of B_n (that is, n \ge 2 even with (p - 1) \mid n, or n = 1 and p = 2), returns UWORD_MAX.

A return value of 0 means that p divides the numerator of B_n; for n even, p \ge 5 and (p-1) \nmid n this happens if and only if p is irregular with an index \equiv n \pmod{p-1}, or p \mid n. The function reduces n modulo p - 1 by Kummer's congruence and computes B_m/m \bmod p for m = n \bmod (p-1).

bernoulli_fmpq_ui is the function to use for a single Bernoulli number B_n. For a range of consecutive values, bernoulli_fmpq_vec_no_cache or the cache (bernoulli_cache_compute) is much faster than repeated calls, and for the residue of B_n modulo a prime, bernoulli_mod_p_harvey avoids computing B_n at all.

AlgorithmBernoulli numbersComputes exact Bernoulli numbers from the zeta function (numerically, with the denominator from von Staudt–Clausen), from Harvey's multimodular algorithm, by a reverse zeta iterator with a table of powers for ranges, and by Ramanujan's recursion or power series modulo primes for short vectors.

How B_n is computed#

The denominator of B_n is known in advance: by the theorem of von Staudt and Clausen it is the product of the primes p with (p - 1) \mid n (arith_bernoulli_number_denom). It has few bits, about O(\log n \cdot n^{\epsilon}) in the worst case, so the work is in the numerator, which has about n \log_2 n bits: \log_2 |B_n| \approx n \log_2(n / (2 \pi e)). Two methods find it.

  • The zeta function. For even n \ge 2,

    B_n = (-1)^{n/2+1} \frac{2\, n!}{(2\pi)^n} \zeta(n),

    and \zeta(n) = 1 + 2^{-n} + 3^{-n} + \cdots converges so fast that about n^{1 + o(1)} bits of precision need only O(n / \log n) terms of the series, or an Euler product. Multiplying the approximation by the denominator gives a ball containing one integer, the numerator. _bernoulli_fmpq_ui_zeta does this with arb_bernoulli_ui_zeta; the cost is O(n^2 \log^{O(1)} n) bit operations.

  • Multimodular. Harvey's algorithm computes B_n \bmod p in time O(p \log^{O(1)} p), independent of n. With primes up to about n \log n this gives the numerator modulo a number larger than itself in total time O(n^2 \log^{O(1)} n) [Har2010], with a better constant and trivial parallelism. _bernoulli_fmpq_ui_multi_mod computes only the low bits this way, a fraction alpha of the total, and the high bits from the zeta function, which is the cheapest combination in practice.

bernoulli_fmpq_ui first looks in the cache, then uses the zeta method for n < 18000 and the combined method above, where most of the time is spent on the residues, which run in parallel with flint_set_num_threads.

Residues modulo primes#

bernoulli_mod_p_harvey returns B_n \bmod p for a prime p < 2^{53}. It reduces n modulo p - 1 with Kummer's congruence B_n/n \equiv B_m/m \pmod p for n \equiv m \not\equiv 0 \pmod{p-1}, then evaluates a sum of O(p) terms whose inner loop is a table lookup on the binary expansion of 1/p. When p - 1 divides n, p divides the denominator of B_n and the function returns UWORD_MAX. A result of 0 means that p divides the numerator, as for p = 691 and B_{12} = -691/2730; primes with this property for some n < p - 1 are the irregular primes.

Example#

Examplebernoulli_isolated.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpq.h>
#include <flint/bernoulli.h>

int main(void)
{
    fmpq_t b;
    fmpz_t p, r;

    fmpq_init(b);
    fmpz_init(p);
    fmpz_init(r);

    bernoulli_fmpq_ui(b, 20);
    flint_printf("B_20 = ");
    fmpq_print(b);
    flint_printf("\n");

    bernoulli_fmpq_ui(b, 10000);
    flint_printf("B_10000: numerator of %wu bits, denominator ",
        fmpz_bits(fmpq_numref(b)));
    fmpz_print(fmpq_denref(b));
    flint_printf("\n");

    /* compare with Harvey's algorithm modulo p = 1000003 */
    fmpz_set_ui(p, 1000003);
    fmpq_mod_fmpz(r, b, p);
    flint_printf("B_10000 mod p: %wu (Harvey), ",
        bernoulli_mod_p_harvey(10000, 1000003));
    fmpz_print(r);
    flint_printf(" (exact)\n");

    flint_printf("B_12 mod 691 = %wu\n", bernoulli_mod_p_harvey(12, 691));
    flint_printf("B_12 mod 13 is undefined: %d\n",
        bernoulli_mod_p_harvey(12, 13) == UWORD_MAX);

    fmpq_clear(b);
    fmpz_clear(p);
    fmpz_clear(r);
    return 0;
}
Output
B_20 = -174611/330
B_10000: numerator of 91986 bits, denominator 2338224387510
B_10000 mod p: 932435 (Harvey), 932435 (exact)
B_12 mod 691 = 0
B_12 mod 13 is undefined: 1

References#

  • [Har2010] D. Harvey, "A multimodular algorithm for computing Bernoulli numbers" (2010), Mathematics of Computation 79.272: 2361-2370
Cite this page

The FLINT team, “Isolated Bernoulli numbers (bernoulli.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/bernoulli/isolated.html (generated 2026-10-20).