void acb_lambertw_initial_asymp(acb_t w, const acb_t z, const fmpz_t k, slong prec) { acb_t L1, L2, t; acb_init(L1); acb_init(L2); acb_init(t); acb_const_pi(L2, prec); acb_mul_2exp_si(L2, L2, 1); acb_mul_fmpz(L2, L2, k, prec); acb_mul_onei(L2, L2); acb_log(L1, z, prec); acb_add(L1, L1, L2, prec); acb_log(L2, L1, prec); /* L1 - L2 + L2/L1 + L2(L2-2)/(2 L1^2) */ acb_inv(t, L1, prec); acb_mul_2exp_si(w, L2, 1); acb_submul(w, L2, L2, prec); acb_neg(w, w); acb_mul(w, w, t, prec); acb_mul_2exp_si(w, w, -1); acb_add(w, w, L2, prec); acb_mul(w, w, t, prec); acb_sub(w, w, L2, prec); acb_add(w, w, L1, prec); acb_clear(L1); acb_clear(L2); acb_clear(t); }
void acb_log1p(acb_t r, const acb_t z, slong prec) { slong magz, magx, magy; if (acb_is_zero(z)) { acb_zero(r); return; } magx = arf_abs_bound_lt_2exp_si(arb_midref(acb_realref(z))); magy = arf_abs_bound_lt_2exp_si(arb_midref(acb_imagref(z))); magz = FLINT_MAX(magx, magy); if (magz < -prec) { acb_log1p_tiny(r, z, prec); } else { if (magz < 0) acb_add_ui(r, z, 1, prec + (-magz) + 4); else acb_add_ui(r, z, 1, prec + 4); acb_log(r, r, prec); } }
void acb_lgamma(acb_t y, const acb_t x, long prec) { int reflect; long r, n, wp; acb_t t, u; wp = prec + FLINT_BIT_COUNT(prec); acb_gamma_stirling_choose_param(&reflect, &r, &n, x, 0, 0, wp); /* log(gamma(x)) = log(gamma(x+r)) - log(rf(x,r)) */ acb_init(t); acb_init(u); acb_add_ui(t, x, r, wp); acb_gamma_stirling_eval(u, t, n, 0, wp); acb_rising_ui_rec(t, x, r, prec); acb_log(t, t, prec); _acb_log_rising_correct_branch(t, t, x, r, wp); acb_sub(y, u, t, prec); acb_clear(t); acb_clear(u); }
void _acb_pow_arb_exp(acb_t z, const acb_t x, const arb_t y, long prec) { acb_t t; acb_init(t); acb_log(t, x, prec); acb_mul_arb(t, t, y, prec); acb_exp(z, t, prec); acb_clear(t); }
static void _acb_hypgeom_li(acb_t res, const acb_t z, long prec) { if (acb_is_zero(z)) { acb_zero(res); } else { acb_log(res, z, prec); acb_hypgeom_ei(res, res, prec); } }
void acb_acosh(acb_t res, const acb_t z, slong prec) { if (acb_is_one(z)) { acb_zero(res); } else { acb_t t, u; acb_init(t); acb_init(u); acb_add_ui(t, z, 1, prec); acb_sub_ui(u, z, 1, prec); acb_sqrt(t, t, prec); acb_sqrt(u, u, prec); acb_mul(t, t, u, prec); acb_add(t, t, z, prec); if (!arb_is_zero(acb_imagref(z))) { acb_log(res, t, prec); } else { /* pure imaginary on (-1,1) */ arb_abs(acb_realref(u), acb_realref(z)); arb_one(acb_imagref(u)); acb_log(res, t, prec); if (arb_lt(acb_realref(u), acb_imagref(u))) arb_zero(acb_realref(res)); } acb_clear(t); acb_clear(u); } }
/* f(z) = -log(z) / (1 + z) */ int f_log_div1p(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { acb_t t; if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ acb_init(t); acb_add_ui(t, z, 1, prec); acb_log(res, z, prec); acb_div(res, res, t, prec); acb_neg(res, res); acb_clear(t); return 0; }
void acb_hypgeom_ci_2f3(acb_t res, const acb_t z, slong prec) { acb_t a, t, u; acb_struct b[3]; acb_init(a); acb_init(b); acb_init(b + 1); acb_init(b + 2); acb_init(t); acb_init(u); acb_one(a); acb_set_ui(b, 2); acb_set(b + 1, b); acb_set_ui(b + 2, 3); acb_mul_2exp_si(b + 2, b + 2, -1); acb_mul(t, z, z, prec); acb_mul_2exp_si(t, t, -2); acb_neg(t, t); acb_hypgeom_pfq_direct(u, a, 1, b, 3, t, -1, prec); acb_mul(u, u, t, prec); acb_log(t, z, prec); acb_add(u, u, t, prec); arb_const_euler(acb_realref(t), prec); arb_add(acb_realref(u), acb_realref(u), acb_realref(t), prec); acb_swap(res, u); acb_clear(a); acb_clear(b); acb_clear(b + 1); acb_clear(b + 2); acb_clear(t); acb_clear(u); }
/* todo: use log(1-z) when this is better? would also need to adjust strategy in the main function */ void acb_hypgeom_dilog_bernoulli(acb_t res, const acb_t z, slong prec) { acb_t s, w, w2; slong n, k; fmpz_t c, d; mag_t m, err; double lm; int real; acb_init(s); acb_init(w); acb_init(w2); fmpz_init(c); fmpz_init(d); mag_init(m); mag_init(err); real = 0; if (acb_is_real(z)) { arb_sub_ui(acb_realref(w), acb_realref(z), 1, 30); real = arb_is_nonpositive(acb_realref(w)); } acb_log(w, z, prec); acb_get_mag(m, w); /* for k >= 4, the terms are bounded by (|w| / (2 pi))^k */ mag_set_ui_2exp_si(err, 2670177, -24); /* upper bound for 1/(2pi) */ mag_mul(err, err, m); lm = mag_get_d_log2_approx(err); if (lm < -0.25) { n = prec / (-lm) + 1; n = FLINT_MAX(n, 4); mag_geom_series(err, err, n); BERNOULLI_ENSURE_CACHED(n) acb_mul(w2, w, w, prec); for (k = n - (n % 2 == 0); k >= 3; k -= 2) { fmpz_mul_ui(c, fmpq_denref(bernoulli_cache + k - 1), k - 1); fmpz_mul_ui(d, c, (k + 1) * (k + 2)); acb_mul(s, s, w2, prec); acb_mul_fmpz(s, s, c, prec); fmpz_mul_ui(c, fmpq_numref(bernoulli_cache + k - 1), (k + 1) * (k + 2)); acb_sub_fmpz(s, s, c, prec); acb_div_fmpz(s, s, d, prec); } acb_mul(s, s, w, prec); acb_mul_2exp_si(s, s, 1); acb_sub_ui(s, s, 3, prec); acb_mul(s, s, w2, prec); acb_mul_2exp_si(s, s, -1); acb_const_pi(w2, prec); acb_addmul(s, w2, w2, prec); acb_div_ui(s, s, 6, prec); acb_neg(w2, w); acb_log(w2, w2, prec); acb_submul(s, w2, w, prec); acb_add(res, s, w, prec); acb_add_error_mag(res, err); if (real) arb_zero(acb_imagref(res)); } else { acb_indeterminate(res); } acb_clear(s); acb_clear(w); acb_clear(w2); fmpz_clear(c); fmpz_clear(d); mag_clear(m); mag_clear(err); }
int main() { long iter; flint_rand_t state; printf("log...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000; iter++) { acb_t x, a, b; long prec1, prec2; prec1 = 2 + n_randint(state, 1000); prec2 = prec1 + 30; acb_init(x); acb_init(a); acb_init(b); acb_randtest_special(x, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_randtest_special(a, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_randtest_special(b, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_log(a, x, prec1); acb_log(b, x, prec2); /* check consistency */ if (!acb_overlaps(a, b)) { printf("FAIL: overlap\n\n"); printf("x = "); acb_printd(x, 15); printf("\n\n"); printf("a = "); acb_printd(a, 15); printf("\n\n"); printf("b = "); acb_printd(b, 15); printf("\n\n"); abort(); } /* check exp(log(x)) = x */ acb_exp(b, b, prec1); if (!acb_contains(b, x)) { printf("FAIL: functional equation\n\n"); printf("x = "); acb_printd(x, 15); printf("\n\n"); printf("b = "); acb_printd(b, 15); printf("\n\n"); abort(); } acb_log(x, x, prec1); if (!acb_overlaps(a, x)) { printf("FAIL: aliasing\n\n"); printf("a = "); acb_printd(a, 15); printf("\n\n"); printf("x = "); acb_printd(x, 15); printf("\n\n"); abort(); } acb_clear(x); acb_clear(a); acb_clear(b); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
void _acb_poly_lgamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec) { int reflect; slong i, r, n, wp; acb_t zr; acb_ptr t, u; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { acb_lgamma(res, h, prec); if (acb_is_finite(res)) _acb_vec_zero(res + 1, len - 1); else _acb_vec_indeterminate(res + 1, len - 1); return; } if (len == 2) { acb_t v; acb_init(v); acb_set(v, h + 1); acb_digamma(res + 1, h, prec); acb_lgamma(res, h, prec); acb_mul(res + 1, res + 1, v, prec); acb_clear(v); return; } /* use real code for real input and output */ if (_acb_vec_is_real(h, hlen) && arb_is_positive(acb_realref(h))) { arb_ptr tmp = _arb_vec_init(len); for (i = 0; i < hlen; i++) arb_set(tmp + i, acb_realref(h + i)); _arb_poly_lgamma_series(tmp, tmp, hlen, len, prec); for (i = 0; i < len; i++) acb_set_arb(res + i, tmp + i); _arb_vec_clear(tmp, len); return; } wp = prec + FLINT_BIT_COUNT(prec); t = _acb_vec_init(len); u = _acb_vec_init(len); acb_init(zr); /* use Stirling series */ acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 0, wp); if (reflect) { /* log gamma(h+x) = log rf(1-(h+x), r) - log gamma(1-(h+x)+r) - log sin(pi (h+x)) + log(pi) */ if (r != 0) /* otherwise t = 0 */ { acb_sub_ui(u, h, 1, wp); acb_neg(u, u); _log_rising_ui_series(t, u, r, len, wp); for (i = 1; i < len; i += 2) acb_neg(t + i, t + i); } acb_sub_ui(u, h, 1, wp); acb_neg(u, u); acb_add_ui(zr, u, r, wp); _acb_poly_gamma_stirling_eval(u, zr, n, len, wp); for (i = 1; i < len; i += 2) acb_neg(u + i, u + i); _acb_vec_sub(t, t, u, len, wp); /* log(sin) is unstable with large imaginary parts; cot_pi is implemented in a numerically stable way */ acb_set(u, h); acb_one(u + 1); _acb_poly_cot_pi_series(u, u, 2, len - 1, wp); _acb_poly_integral(u, u, len, wp); acb_const_pi(u, wp); _acb_vec_scalar_mul(u + 1, u + 1, len - 1, u, wp); acb_log_sin_pi(u, h, wp); _acb_vec_sub(u, t, u, len, wp); acb_const_pi(t, wp); /* todo: constant for log pi */ acb_log(t, t, wp); acb_add(u, u, t, wp); } else { /* log gamma(x) = log gamma(x+r) - log rf(x,r) */ acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval(u, zr, n, len, wp); if (r != 0) { _log_rising_ui_series(t, h, r, len, wp); _acb_vec_sub(u, u, t, len, wp); } } /* compose with nonconstant part */ acb_zero(t); _acb_vec_set(t + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, u, len, t, hlen, len, prec); acb_clear(zr); _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
int main() { slong iter; flint_rand_t state; flint_printf("log1p...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000; iter++) { acb_t x, a, b; slong prec1, prec2; prec1 = 2 + n_randint(state, 1000); prec2 = 2 + n_randint(state, 1000); acb_init(x); acb_init(a); acb_init(b); acb_randtest_special(x, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_randtest_special(a, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_randtest_special(b, state, 1 + n_randint(state, 1000), 2 + n_randint(state, 100)); acb_log1p(a, x, prec1); acb_log1p(b, x, prec2); /* check consistency */ if (!acb_overlaps(a, b)) { flint_printf("FAIL: overlap\n\n"); flint_printf("x = "); acb_printd(x, 15); flint_printf("\n\n"); flint_printf("a = "); acb_printd(a, 15); flint_printf("\n\n"); flint_printf("b = "); acb_printd(b, 15); flint_printf("\n\n"); abort(); } /* check log1p(x) = log(1+x) */ acb_add_ui(b, x, 1, prec2); acb_log(b, b, prec2); if (!acb_overlaps(a, b)) { flint_printf("FAIL: log1p vs log\n\n"); flint_printf("x = "); acb_printd(x, 15); flint_printf("\n\n"); flint_printf("a = "); acb_printd(a, 15); flint_printf("\n\n"); flint_printf("b = "); acb_printd(b, 15); flint_printf("\n\n"); abort(); } acb_log1p(x, x, prec1); if (!acb_overlaps(a, x)) { flint_printf("FAIL: aliasing\n\n"); flint_printf("a = "); acb_printd(a, 15); flint_printf("\n\n"); flint_printf("x = "); acb_printd(x, 15); flint_printf("\n\n"); abort(); } acb_clear(x); acb_clear(a); acb_clear(b); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
int main() { long iter; flint_rand_t state; printf("lgamma...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000; iter++) { acb_t a, b, c; long prec1, prec2; prec1 = 2 + n_randint(state, 500); prec2 = prec1 + 30; acb_init(a); acb_init(b); acb_init(c); arb_randtest_precise(acb_realref(a), state, 1 + n_randint(state, 1000), 1 + n_randint(state, 10)); arb_randtest_precise(acb_imagref(a), state, 1 + n_randint(state, 1000), 1 + n_randint(state, 10)); acb_lgamma(b, a, prec1); if (n_randint(state, 4) == 0) { acb_randtest(c, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 10)); acb_add(a, a, c, prec1); acb_sub(a, a, c, prec1); } acb_lgamma(c, a, prec2); if (!acb_overlaps(b, c)) { printf("FAIL: overlap\n\n"); printf("a = "); acb_print(a); printf("\n\n"); printf("b = "); acb_print(b); printf("\n\n"); printf("c = "); acb_print(c); printf("\n\n"); abort(); } /* check lgamma(z+1) = lgamma(z) + log(z) */ acb_log(c, a, prec1); acb_add(b, b, c, prec1); acb_add_ui(c, a, 1, prec1); acb_lgamma(c, c, prec1); if (!acb_overlaps(b, c)) { printf("FAIL: functional equation\n\n"); printf("a = "); acb_print(a); printf("\n\n"); printf("b = "); acb_print(b); printf("\n\n"); printf("c = "); acb_print(c); printf("\n\n"); abort(); } acb_clear(a); acb_clear(b); acb_clear(c); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
void acb_gamma_stirling_eval(acb_t s, const acb_t z, long nterms, int digamma, long prec) { acb_t t, logz, zinv, zinv2; arb_t b; mag_t err; long k, term_prec; double z_mag, term_mag; acb_init(t); acb_init(logz); acb_init(zinv); acb_init(zinv2); arb_init(b); acb_log(logz, z, prec); acb_inv(zinv, z, prec); nterms = FLINT_MAX(nterms, 1); acb_zero(s); if (nterms > 1) { acb_mul(zinv2, zinv, zinv, prec); z_mag = arf_get_d(arb_midref(acb_realref(logz)), ARF_RND_UP) * 1.44269504088896; for (k = nterms - 1; k >= 1; k--) { term_mag = bernoulli_bound_2exp_si(2 * k); term_mag -= (2 * k - 1) * z_mag; term_prec = prec + term_mag; term_prec = FLINT_MIN(term_prec, prec); term_prec = FLINT_MAX(term_prec, 10); arb_gamma_stirling_coeff(b, k, digamma, term_prec); if (prec > 2000) { acb_set_round(t, zinv2, term_prec); acb_mul(s, s, t, term_prec); } else acb_mul(s, s, zinv2, term_prec); arb_add(acb_realref(s), acb_realref(s), b, term_prec); } if (digamma) acb_mul(s, s, zinv2, prec); else acb_mul(s, s, zinv, prec); } /* remainder bound */ mag_init(err); acb_gamma_stirling_bound(err, z, digamma ? 1 : 0, 1, nterms); mag_add(arb_radref(acb_realref(s)), arb_radref(acb_realref(s)), err); mag_add(arb_radref(acb_imagref(s)), arb_radref(acb_imagref(s)), err); mag_clear(err); if (digamma) { acb_neg(s, s); acb_mul_2exp_si(zinv, zinv, -1); acb_sub(s, s, zinv, prec); acb_add(s, s, logz, prec); } else { /* (z-0.5)*log(z) - z + log(2*pi)/2 */ arb_one(b); arb_mul_2exp_si(b, b, -1); arb_set(acb_imagref(t), acb_imagref(z)); arb_sub(acb_realref(t), acb_realref(z), b, prec); acb_mul(t, logz, t, prec); acb_add(s, s, t, prec); acb_sub(s, s, z, prec); arb_const_log_sqrt2pi(b, prec); arb_add(acb_realref(s), acb_realref(s), b, prec); } acb_clear(t); acb_clear(logz); acb_clear(zinv); acb_clear(zinv2); arb_clear(b); }
static void acb_log_sin_pi_half(acb_t res, const acb_t z, slong prec, int upper) { acb_t t, u, zmid; arf_t n; arb_t pi; acb_init(t); acb_init(u); acb_init(zmid); arf_init(n); arb_init(pi); arf_set(arb_midref(acb_realref(zmid)), arb_midref(acb_realref(z))); arf_set(arb_midref(acb_imagref(zmid)), arb_midref(acb_imagref(z))); arf_floor(n, arb_midref(acb_realref(zmid))); arb_sub_arf(acb_realref(zmid), acb_realref(zmid), n, prec); arb_const_pi(pi, prec); if (arf_cmpabs_2exp_si(arb_midref(acb_imagref(zmid)), 2) < 1) { acb_sin_pi(t, zmid, prec); acb_log(t, t, prec); } else /* i*pi*(z-0.5) + log((1-exp(-2i*pi*z))/2) */ { acb_mul_2exp_si(t, zmid, 1); acb_neg(t, t); if (upper) acb_conj(t, t); acb_exp_pi_i(t, t, prec); acb_sub_ui(t, t, 1, prec); acb_neg(t, t); acb_mul_2exp_si(t, t, -1); acb_log(t, t, prec); acb_one(u); acb_mul_2exp_si(u, u, -1); acb_sub(u, zmid, u, prec); if (upper) acb_conj(u, u); acb_mul_onei(u, u); acb_addmul_arb(t, u, pi, prec); if (upper) acb_conj(t, t); } if (upper) arb_submul_arf(acb_imagref(t), pi, n, prec); else arb_addmul_arf(acb_imagref(t), pi, n, prec); /* propagated error bound from the derivative pi cot(pi z) */ if (!acb_is_exact(z)) { mag_t zm, um; mag_init(zm); mag_init(um); acb_cot_pi(u, z, prec); acb_mul_arb(u, u, pi, prec); mag_hypot(zm, arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); acb_get_mag(um, u); mag_mul(um, um, zm); acb_add_error_mag(t, um); mag_clear(zm); mag_clear(um); } acb_set(res, t); acb_clear(t); acb_clear(u); acb_clear(zmid); arf_clear(n); arb_clear(pi); }