Math-Prime-Util-GMP
view release on metacpan or search on metacpan
if (n < 46) {
_bernfrac_comb(num, den, n, t);
} else {
_bernfrac_zeta(num, den, n, t);
}
mpz_gcd(t, num, den);
mpz_divexact(num, num, t);
mpz_divexact(den, den, t);
mpz_clear(t);
}
/*************************** Lambert W ***************************/
static double _lambertw_approx(double x) {
double w, k1, k2, k3;
if (isinf(x) || isnan(x))
return 1000.0;
if (x < -0.312) {
/* Near the branch point. See Fukushima (2013) section 2.5. */
k2 = 2.0 * (1.0 + 2.71828182845904523536 * x);
if (k2 <= 0) return -1.0 + 1*DBL_EPSILON;
k1 = sqrt(k2);
/* Use Puiseux series, e.g. Verberic 2009, Boost, Johannson (2020). */
w = -1.0 + (1.0 + (-1.0/3.0 + (11.0/72.0 + (-43.0/540.0 + (769.0/17280.0 + (-221.0/8505.0 + (680863.0/43545600.0 + (-1963.0/204120.0 + 226287557.0/37623398400.0
* k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1;
} else if (x > -0.14 && x < 0.085) {
/* Around zero. See Fukushima (2013) section 2.6. */
w = (1.0 + (-1.0 + (3.0/2.0 + (-8.0/3.0 + (125.0/24.0 + (-54.0/5.0 + (16807.0/720.0 + (-16384.0/315.0 + 531441.0/4480.0
* x) * x) * x) * x) * x) * x) * x) * x) * x;
} else if (x < 1) {
/* This and the rest from Vazquez-Leal et al. (2019). */
k1 = sqrt(1.0 + 2.71828182845904523536 * x);
k2 = 0.33333333333333333333 + 0.7071067811865475244 / k1 - 0.058925565098880 * k1 +
(x + 0.36787944117144) * (0.050248489761611 + (0.11138904851051 + 0.040744556245195 * x) * x)
/
(1.0 + (2.7090878606183 + (1.5510922597820 + 0.095477712183841 * x) * x) * x);
w = -(k2-1)/k2;
} else if (x < 40) {
k1 = 1.0 + (5.950065500550155 + (13.96586471370701 + (10.52192021050505 + (3.065294254265870 + 0.1204576876518760 * x) * x) * x) * x) * x;
w = 0.1600049638651493 * log(k1);
} else if (x < 20000) {
k1 = 1.0 + (-3.16866642511229e11 + (3.420439800038598e10 +
(-1.501433652432257e9 + (3.44887729947585e7 + (-4.453783741137856e5 +
(3257.926478908996 + (-10.82545259305382 + (0.6898058947898353e-1 +
0.4703653406071575e-4 * x) * x) * x) * x) * x) * x) * x) * x) * x;
w = 0.9898045358731312e-1 * log(k1);
} else {
k1 = 1.0 / (1.0 + log(1.0 + x));
k2 = 1.0 / k1;
k3 = log(k2);
w = k2-1-k3+(1+k3+(-1/2+(1/2)*k3*k3 +(-1/6+(-1+(-1/2+
(1/3) * k3) * k3) * k3) * k1) * k1) * k1;
}
/* Improve the FP estimate using two simple Halley iterations. */
if (x >= -0.36728) {
if (w != 0) w = (w/(1.0+w)) * (1.0+log(x/w));
if (w != 0) w = (w/(1.0+w)) * (1.0+log(x/w));
if (isnan(w)) w = DBL_EPSILON;
}
/* Result is over 15 digits, 16 when x > 0 */
return w;
}
/* Iteration (5) from https://arxiv.org/pdf/2008.06122. */
static void _mpf_lambertw_approx(mpf_t w, mpf_t x) {
double dapprox;
mpf_t T1, T2;
const int apbits = 117; /* 35 digits */
int i, loops;
mpf_init2(T1, apbits);
mpf_init2(T2, apbits);
loops = 2;
dapprox = _lambertw_approx(mpf_get_d(x));
if (dapprox < 800.0) {
mpf_set_d(T1, dapprox);
} else {
/* Init using equation 21 */
mpf_log(T1, x);
mpf_log(T2, T1);
mpf_sub(T1, T1, T2); /* T1 = Beta0 = log(x)-log(log(x)) */
loops = 3;
}
for (i = 0; i < loops; i++) {
mpf_add_ui(T2, T1, 1);
mpf_div(T2, T1, T2); /* T2 = Bn/(1+Bn) */
mpf_div(T1, x, T1);
mpf_log(T1, T1);
mpf_add_ui(T1,T1,1); /* T1 = 1 + log(x/Bn) */
mpf_mul(T1, T1, T2); /* T1 = Beta_{n+1} */
}
mpf_set(w, T1);
mpf_clear(T2); mpf_clear(T1);
}
static void _lambertw(mpf_t r, mpf_t x, unsigned long prec)
{
int i;
unsigned long bits = 96 + DIGS2BITS(prec);
mpf_t w, t, tol, w1, zn, qn, en;
if (mpf_cmp_d(x, -0.36787944117145) < 0)
croak("Invalid input to LambertW: x must be >= -1/e");
if (mpf_sgn(x) == 0)
{ mpf_set(r, x); return; }
/* Use Fritsch rather than Halley. */
mpf_init2(w, bits);
mpf_init2(t, bits);
mpf_init2(tol, bits);
mpf_init2(w1, bits);
( run in 1.282 second using v1.01-cache-2.11-cpan-71847e10f99 )