Files
RedBear-OS/recipes/libs/libmpfr/source/src/bernoulli.c
T
vasilito ff4ff35918 feat: track all source trees in git — full fork offline-first model
Red Bear OS is a full fork. All sources must be available from git clone
with zero network access. Removed gitignore rules that excluded fetched
source trees under recipes/*/source/, local/recipes/kde/*/source/,
local/recipes/qt/*/source/, and vendor source trees.

Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded.

127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt
frameworks, mesa, wayland, DRM drivers, and every other recipe source.
2026-05-14 10:55:53 +01:00

255 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* bernoulli -- internal function to compute Bernoulli numbers.
Copyright 2005-2025 Free Software Foundation, Inc.
Contributed by the Pascaline and Caramba projects, INRIA.
This file is part of the GNU MPFR Library.
The GNU MPFR Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
The GNU MPFR Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNU MPFR Library; see the file COPYING.LESSER.
If not, see <https://www.gnu.org/licenses/>. */
#include "mpfr-impl.h"
/* assume p >= 5 and is odd */
static int
is_prime (unsigned long p)
{
unsigned long q;
MPFR_ASSERTD (p >= 5 && (p & 1) != 0);
for (q = 3; q * q <= p; q += 2)
if ((p % q) == 0)
return 0;
return 1;
}
/* Computes and stores B[2n]*(2n+1)! in b[n]
using Von StaudtClausen theorem, which says that the denominator of B[n]
divides the product of all primes p such that p-1 divides n.
Since B[n] = zeta(n) * 2*n!/(2pi)^n, we compute an approximation of
(2n+1)! * zeta(n) * 2*n!/(2pi)^n and round it to the nearest integer. */
static void
mpfr_bernoulli_internal (mpz_t *b, unsigned long n)
{
unsigned long p, err, zn;
mpz_t s, t, u, den;
mpz_ptr num;
mpfr_t y, z;
int ok;
/* Prec[n/2] is minimal precision so that result is correct for B[n] */
mpfr_prec_t prec;
mpfr_prec_t Prec[] = {0, 5, 5, 6, 6, 9, 16, 10, 19, 23, 25, 27, 35, 31,
42, 51, 51, 50, 73, 60, 76, 79, 83, 87, 101, 97,
108, 113, 119, 125, 149, 133, 146};
mpz_init (b[n]);
if (n == 0)
{
mpz_set_ui (b[0], 1);
return;
}
/* compute denominator */
num = b[n];
n = 2 * n;
mpz_init_set_ui (den, 6);
for (p = 5; p <= n+1; p += 2)
{
if ((n % (p-1)) == 0 && is_prime (p))
mpz_mul_ui (den, den, p);
}
if (n <= 64)
prec = Prec[n >> 1];
else
{
/* evaluate the needed precision: zeta(n)*2*den*n!/(2*pi)^n <=
3.3*den*(n/e/2/pi)^n*sqrt(2*pi*n) */
prec = __gmpfr_ceil_log2 (7.0 * (double) n); /* bound 2*pi by 7 */
prec = (prec + 1) >> 1; /* sqrt(2*pi*n) <= 2^prec */
mpfr_init2 (z, 53);
mpfr_set_ui_2exp (z, 251469612, -32, MPFR_RNDU); /* 1/e/2/pi <= z */
mpfr_mul_ui (z, z, n, MPFR_RNDU);
mpfr_log2 (z, z, MPFR_RNDU);
mpfr_mul_ui (z, z, n, MPFR_RNDU);
p = mpfr_get_ui (z, MPFR_RNDU); /* (n/e/2/pi)^n <= 2^p */
mpfr_clear (z);
MPFR_INC_PREC (prec, p + mpz_sizeinbase (den, 2));
/* the +2 term ensures no rounding failure up to n=10000 */
MPFR_INC_PREC (prec, __gmpfr_ceil_log2 (prec) + 2);
}
try_again:
mpz_init (s);
mpz_init (t);
mpz_init (u);
mpz_set_ui (u, 1);
mpz_mul_2exp (u, u, prec); /* u = 2^prec */
mpz_ui_pow_ui (t, 3, n);
mpz_fdiv_q (s, u, t); /* multiply all terms by 2^prec */
/* we compute a lower bound of the series, thus the final result cannot
be too large */
for (p = 4; mpz_cmp_ui (t, 0) > 0; p++)
{
mpz_ui_pow_ui (t, p, n);
mpz_fdiv_q (t, u, t);
/* 2^prec/p^n-1 < t <= 2^prec/p^n */
mpz_add (s, s, t);
}
/* sum(2^prec/q^n-1, q=3..p) < t <= sum(2^prec/q^n, q=3..p)
thus the error on the truncated series is at most p-2.
The neglected part of the series is R = sum(1/x^n, x=p+1..infinity)
with int(1/x^n, x=p+1..infinity) <= R <= int(1/x^n, x=p..infinity)
thus 1/(n-1)/(p+1)^(n-1) <= R <= 1/(n-1)/p^(n-1). The difference between
the lower and upper bound is bounded by p^(-n), which is bounded by
2^(-prec) since t=0 in the above loop */
mpz_ui_pow_ui (t, p, n - 1);
mpz_mul_ui (t, t, n - 1);
mpz_cdiv_q (t, u, t);
mpz_add (s, s, t);
/* now 2^prec * (zeta(n)-1-1/2^n) - p < s <= 2^prec * (zeta(n)-1-1/2^n) */
/* add 1 which is 2^prec */
mpz_add (s, s, u);
/* add 1/2^n which is 2^(prec-n) */
mpz_cdiv_q_2exp (u, u, n);
mpz_add (s, s, u);
/* now 2^prec * zeta(n) - p < s <= 2^prec * zeta(n) */
/* multiply by n! */
mpz_fac_ui (t, n);
mpz_mul (s, s, t);
/* multiply by 2*den */
mpz_mul (s, s, den);
mpz_mul_2exp (s, s, 1);
/* now convert to mpfr */
mpfr_init2 (z, prec);
mpfr_set_z (z, s, MPFR_RNDZ);
/* now (2^prec * zeta(n) - p) * 2*den*n! - ulp(z) < z <=
2^prec * zeta(n) * 2*den*n!.
Since z <= 2^prec * zeta(n) * 2*den*n!,
ulp(z) <= 2*zeta(n) * 2*den*n!, thus
(2^prec * zeta(n)-(p+1)) * 2*den*n! < z <= 2^prec * zeta(n) * 2*den*n! */
mpfr_div_2ui (z, z, prec, MPFR_RNDZ);
/* now (zeta(n) - (p+1)/2^prec) * 2*den*n! < z <= zeta(n) * 2*den*n! */
/* divide by (2pi)^n */
mpfr_init2 (y, prec);
mpfr_const_pi (y, MPFR_RNDU);
/* pi <= y <= pi * (1 + 2^(1-prec)) */
mpfr_mul_2ui (y, y, 1, MPFR_RNDU);
/* 2pi <= y <= 2pi * (1 + 2^(1-prec)) */
mpfr_pow_ui (y, y, n, MPFR_RNDU);
/* (2pi)^n <= y <= (2pi)^n * (1 + 2^(1-prec))^(n+1) */
mpfr_div (z, z, y, MPFR_RNDZ);
/* now (zeta(n) - (p+1)/2^prec) * 2*den*n! / (2pi)^n / (1+2^(1-prec))^(n+1)
<= z <= zeta(n) * 2*den*n! / (2pi)^n, and since zeta(n) >= 1:
den * B[n] * (1 - (p+1)/2^prec) / (1+2^(1-prec))^(n+1)
<= z <= den * B[n]
Since 1 / (1+2^(1-prec))^(n+1) >= (1 - 2^(1-prec))^(n+1) >=
1 - (n+1) * 2^(1-prec):
den * B[n] / (2pi)^n * (1 - (p+1)/2^prec) * (1-(n+1)*2^(1-prec))
<= z <= den * B[n] thus
den * B[n] * (1 - (2n+p+3)/2^prec) <= z <= den * B[n] */
/* the error is bounded by 2^(EXP(z)-prec) * (2n+p+3) */
for (err = 0, p = 2 * n + p + 3; p > 1; err++, p = (p + 1) >> 1);
zn = MPFR_LIMB_SIZE(z) * GMP_NUMB_BITS; /* total number of bits of z */
if (err >= prec)
ok = 0;
else
{
err = prec - err;
/* now the absolute error is bounded by 2^(EXP(z) - err):
den * B[n] - 2^(EXP(z) - err) <= z <= den * B[n]
thus if subtracting 2^(EXP(z) - err) does not change the rounding
(up) we are ok */
err = mpn_scan1 (MPFR_MANT(z), zn - err);
/* weight of this 1 bit is 2^(EXP(z) - zn + err) */
ok = MPFR_EXP(z) < zn - err;
}
mpfr_get_z (num, z, MPFR_RNDU);
if ((n & 2) == 0)
mpz_neg (num, num);
/* multiply by (n+1)! */
mpz_mul_ui (t, t, n + 1);
mpz_divexact (t, t, den); /* t was still n! */
mpz_mul (num, num, t);
mpfr_clear (y);
mpfr_clear (z);
mpz_clear (s);
mpz_clear (t);
mpz_clear (u);
if (!ok)
{
MPFR_INC_PREC (prec, prec / 10);
goto try_again;
}
mpz_clear (den);
}
static MPFR_THREAD_ATTR mpz_t *bernoulli_table = NULL;
static MPFR_THREAD_ATTR unsigned long bernoulli_size = 0;
static MPFR_THREAD_ATTR unsigned long bernoulli_alloc = 0;
mpz_srcptr
mpfr_bernoulli_cache (unsigned long n)
{
unsigned long i;
if (n >= bernoulli_size)
{
if (bernoulli_alloc == 0)
{
bernoulli_alloc = MAX(16, n + n/4);
bernoulli_table = (mpz_t *)
mpfr_allocate_func (bernoulli_alloc * sizeof (mpz_t));
bernoulli_size = 0;
}
else if (n >= bernoulli_alloc)
{
bernoulli_table = (mpz_t *) mpfr_reallocate_func
(bernoulli_table, bernoulli_alloc * sizeof (mpz_t),
(n + n/4) * sizeof (mpz_t));
bernoulli_alloc = n + n/4;
}
MPFR_ASSERTD (bernoulli_alloc > n);
MPFR_ASSERTD (bernoulli_size >= 0);
for (i = bernoulli_size; i <= n; i++)
mpfr_bernoulli_internal (bernoulli_table, i);
bernoulli_size = n+1;
}
MPFR_ASSERTD (bernoulli_size > n);
return bernoulli_table[n];
}
void
mpfr_bernoulli_freecache (void)
{
unsigned long i;
if (bernoulli_table != NULL)
{
for (i = 0; i < bernoulli_size; i++)
{
mpz_clear (bernoulli_table[i]);
}
mpfr_free_func (bernoulli_table, bernoulli_alloc * sizeof (mpz_t));
bernoulli_table = NULL;
bernoulli_alloc = 0;
bernoulli_size = 0;
}
}