Isolated Bernoulli numbers
#include <flint/bernoulli.h>Set the result to 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 and use _bernoulli_fmpq_ui_zeta, and larger even use _bernoulli_fmpq_ui_multi_mod with the default tuning.
Set num and den to the numerator and denominator of in lowest terms, by two methods.
The zeta version computes the denominator with arith_bernoulli_number_denom (von Staudt–Clausen), approximates with arb_bernoulli_ui_zeta from at a precision slightly above the size of , and rounds to the unique integer in the resulting ball, increasing the precision if needed.
The multi_mod version computes the numerator modulo the product of the primes with (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 where is the residue and the unique integer in a ball for . The parameter balances the two parts; a negative value selects the default, 0 for , for and above. For or odd the zeta version is called.
Returns for a prime ( on 64-bit machines), computed with Harvey's algorithm [Har2010] in time , independent of . If divides the denominator of (that is, even with , or and ), returns UWORD_MAX.
A return value of 0 means that divides the numerator of ; for even, and this happens if and only if is irregular with an index , or . The function reduces modulo by Kummer's congruence and computes for .
bernoulli_fmpq_ui is the function to use for a single Bernoulli number . 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 modulo a prime, bernoulli_mod_p_harvey avoids computing at all.
How is computed#
The denominator of is known in advance: by the theorem of von Staudt and Clausen it is the product of the primes with (arith_bernoulli_number_denom). It has few bits, about in the worst case, so the work is in the numerator, which has about bits: . Two methods find it.
The zeta function. For even ,
and converges so fast that about bits of precision need only 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_zetadoes this witharb_bernoulli_ui_zeta; the cost is bit operations.- Multimodular. Harvey's algorithm computes in time , independent of . With primes up to about this gives the numerator modulo a number larger than itself in total time [Har2010], with a better constant and trivial parallelism.
_bernoulli_fmpq_ui_multi_modcomputes only the low bits this way, a fractionalphaof 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 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 for a prime . It reduces modulo with Kummer's congruence for , then evaluates a sum of terms whose inner loop is a table lookup on the binary expansion of . When divides , divides the denominator of and the function returns UWORD_MAX. A result of 0 means that divides the numerator, as for and ; primes with this property for some are the irregular primes.
Example#
#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;
}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
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-11-02).
@misc{flint-doc-bernoulli-isolated,
author = {{The FLINT team}},
title = {{Isolated Bernoulli numbers (bernoulli.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/bernoulli/isolated.html},
note = {Generated 2026-11-02}
}