static void acb_log1p_tiny(acb_t r, const acb_t z, slong prec) { mag_t b, c; acb_t t; int real; mag_init(b); mag_init(c); acb_init(t); real = acb_is_real(z); /* if |z| < 1, then |log(1+z) - [z - z^2/2]| <= |z|^3/(1-|z|) */ acb_get_mag(b, z); mag_one(c); mag_sub_lower(c, c, b); mag_pow_ui(b, b, 3); mag_div(b, b, c); acb_mul(t, z, z, prec); acb_mul_2exp_si(t, t, -1); acb_sub(r, z, t, prec); if (real && mag_is_finite(b)) arb_add_error_mag(acb_realref(r), b); else acb_add_error_mag(r, b); mag_clear(b); mag_clear(c); acb_clear(t); }
/* assumes no aliasing of w and p */ void acb_lambertw_branchpoint_series(acb_t w, const acb_t t, int bound, slong prec) { slong i; static const int coeffs[] = {-130636800,130636800,-43545600,19958400, -10402560,5813640,-3394560,2042589,-1256320}; acb_zero(w); for (i = 8; i >= 0; i--) { acb_mul(w, w, t, prec); acb_add_si(w, w, coeffs[i], prec); } acb_div_si(w, w, -coeffs[0], prec); if (bound) { mag_t err; mag_init(err); acb_get_mag(err, t); mag_geom_series(err, err, 9); if (acb_is_real(t)) arb_add_error_mag(acb_realref(w), err); else acb_add_error_mag(w, err); mag_clear(err); } }
int main() { slong iter; flint_rand_t state; flint_printf("get_mag...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) { acb_t a; arf_t m2, x, y, s; mag_t m; acb_init(a); mag_init(m); arf_init(m2); arf_init(x); arf_init(y); arf_init(s); acb_randtest_special(a, state, 200, 10); acb_get_mag(m, a); MAG_CHECK_BITS(m) /* check m^2 >= x^2 + y^2 */ arf_set_mag(m2, m); arf_mul(m2, m2, m2, ARF_PREC_EXACT, ARF_RND_DOWN); arb_get_abs_ubound_arf(x, acb_realref(a), ARF_PREC_EXACT); arb_get_abs_ubound_arf(y, acb_imagref(a), ARF_PREC_EXACT); arf_sosq(s, x, y, ARF_PREC_EXACT, ARF_RND_DOWN); if (arf_cmp(m2, s) < 0) { flint_printf("FAIL:\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("m = "); mag_print(m); flint_printf("\n\n"); flint_abort(); } acb_clear(a); mag_clear(m); arf_clear(m2); arf_clear(x); arf_clear(y); arf_clear(s); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
/* Differential equation for F(a,b,c,y+z): (y+z)(y-1+z) F''(z) + ((y+z)(a+b+1) - c) F'(z) + a b F(z) = 0 Coefficients in the Taylor series are bounded by A * binomial(N+k, k) * nu^k using the Cauchy-Kovalevskaya majorant method. See J. van der Hoeven, "Fast evaluation of holonomic functions near and in regular singularities" */ static void bound(mag_t A, mag_t nu, mag_t N, const acb_t a, const acb_t b, const acb_t c, const acb_t y, const acb_t f0, const acb_t f1) { mag_t M0, M1, t, u; acb_t d; acb_init(d); mag_init(M0); mag_init(M1); mag_init(t); mag_init(u); /* nu = max(1/|y-1|, 1/|y|) = 1/min(|y-1|, |y|) */ acb_get_mag_lower(t, y); acb_sub_ui(d, y, 1, MAG_BITS); acb_get_mag_lower(u, d); mag_min(t, t, u); mag_one(u); mag_div(nu, u, t); /* M0 = 2 nu |ab| */ acb_get_mag(t, a); acb_get_mag(u, b); mag_mul(M0, t, u); mag_mul(M0, M0, nu); mag_mul_2exp_si(M0, M0, 1); /* M1 = 2 nu |(a+b+1)y-c| + 2|a+b+1| */ acb_add(d, a, b, MAG_BITS); acb_add_ui(d, d, 1, MAG_BITS); acb_get_mag(t, d); acb_mul(d, d, y, MAG_BITS); acb_sub(d, d, c, MAG_BITS); acb_get_mag(u, d); mag_mul(u, u, nu); mag_add(M1, t, u); mag_mul_2exp_si(M1, M1, 1); /* N = max(sqrt(2 M0), 2 M1) / nu */ mag_mul_2exp_si(M0, M0, 1); mag_sqrt(M0, M0); mag_mul_2exp_si(M1, M1, 1); mag_max(N, M0, M1); mag_div(N, N, nu); /* A = max(|f0|, |f1| / (nu (N+1)) */ acb_get_mag(t, f0); acb_get_mag(u, f1); mag_div(u, u, nu); mag_div(u, u, N); /* upper bound for dividing by N+1 */ mag_max(A, t, u); acb_clear(d); mag_clear(M0); mag_clear(M1); mag_clear(t); mag_clear(u); }
void acb_hypgeom_bessel_k(acb_t res, const acb_t nu, const acb_t z, slong prec) { mag_t zmag; mag_init(zmag); acb_get_mag(zmag, z); if (mag_cmp_2exp_si(zmag, 4) < 0 || (mag_cmp_2exp_si(zmag, 64) < 0 && 2 * mag_get_d(zmag) < prec)) acb_hypgeom_bessel_k_0f1(res, nu, z, prec); else acb_hypgeom_bessel_k_asymp(res, nu, z, prec); mag_clear(zmag); }
void acb_modular_theta_const_sum(acb_t theta2, acb_t theta3, acb_t theta4, const acb_t q, long prec) { mag_t qmag, err; double log2q_approx; int is_real, is_real_or_imag; long N; mag_init(qmag); mag_init(err); acb_get_mag(qmag, q); log2q_approx = mag_get_log2_d_approx(qmag); is_real = arb_is_zero(acb_imagref(q)); is_real_or_imag = is_real || arb_is_zero(acb_realref(q)); if (log2q_approx >= 0.0) { N = 1; mag_inf(err); } else { N = 0; while (0.05 * N * N < prec) { if (log2q_approx * ((N+2)*(N+2)/4) < -prec - 2) break; N++; } N = (N+2)*(N+2)/4; mag_geom_series(err, qmag, N); mag_mul_2exp_si(err, err, 1); /* each term is taken twice */ if (mag_is_inf(err)) N = 1; } if (N < 1800) acb_modular_theta_const_sum_basecase(theta2, theta3, theta4, q, N, prec); else acb_modular_theta_const_sum_rs(theta2, theta3, theta4, q, N, prec); if (is_real_or_imag) arb_add_error_mag(acb_realref(theta2), err); else acb_add_error_mag(theta2, err); if (is_real) { arb_add_error_mag(acb_realref(theta3), err); arb_add_error_mag(acb_realref(theta4), err); } else { acb_add_error_mag(theta3, err); acb_add_error_mag(theta4, err); } mag_clear(qmag); mag_clear(err); }
void acb_modular_theta_const_sum_basecase(acb_t theta2, acb_t theta3, acb_t theta4, const acb_t q, slong N, slong prec) { slong * tab; slong k, term_prec; double log2q_approx, log2term_approx; mag_t qmag; acb_ptr qpow; acb_t s1, s2, s3, t1, t2; if (N < 2) { acb_set_ui(theta2, 2 * (N > 0)); acb_set_ui(theta3, N > 0); acb_set(theta4, theta3); return; } if (N < 25) { acb_t q1, q2, q4, q8, q16; acb_init(q1); acb_init(q2); acb_init(q4); acb_init(q8); acb_init(q16); acb_set_round(q1, q, prec); if (N > 2) acb_mul(q2, q1, q1, prec); if (N > 4) acb_mul(q4, q2, q2, prec); if (N > 9) acb_mul(q8, q4, q4, prec); if (N > 16) acb_mul(q16, q8, q8, prec); /* theta2 = 2 + 2q^2 + 2q^4 [2q^2 + 2q^8 + 2q^16] */ if (N > 6) { if (N > 12) { acb_add(theta2, q2, q8, prec); if (N > 20) acb_add(theta2, theta2, q16, prec); acb_mul(theta2, theta2, q4, prec); } else { acb_mul(theta2, q2, q4, prec); } acb_add(theta2, theta2, q2, prec); acb_add_ui(theta2, theta2, 1, prec); } else if (N > 2) acb_add_ui(theta2, q2, 1, prec); else acb_one(theta2); acb_mul_2exp_si(theta2, theta2, 1); /* theta3 = [1 + 2q^4 + 2q^16] + [2q + 2q^9] */ /* theta4 = [1 + 2q^4 + 2q^16] - [2q + 2q^9] */ if (N > 4) { if (N > 16) acb_add(q4, q4, q16, prec); acb_mul_2exp_si(q4, q4, 1); acb_add_ui(q4, q4, 1, prec); if (N > 9) acb_addmul(q1, q1, q8, prec); acb_mul_2exp_si(q1, q1, 1); acb_add(theta3, q4, q1, prec); acb_sub(theta4, q4, q1, prec); } else { acb_mul_2exp_si(q1, q1, 1); acb_add_ui(theta3, q1, 1, prec); acb_sub_ui(theta4, q1, 1, prec); acb_neg(theta4, theta4); } acb_clear(q1); acb_clear(q2); acb_clear(q4); acb_clear(q8); acb_clear(q16); return; } mag_init(qmag); acb_init(s1); acb_init(s2); acb_init(s3); acb_init(t1); acb_init(t2); tab = flint_calloc(N, sizeof(slong)); qpow = _acb_vec_init(N); for (k = 0; k*(k+1) < N; k++) tab[k*(k+1)] = -1; for (k = 0; 4*k*k < N; k++) tab[4*k*k] = -1; for (k = 0; 4*k*(k+1) + 1 < N; k++) tab[4*k*(k+1)] = -1; if (N > 0) tab[0] = 0; if (N > 1) tab[1] = 1; acb_modular_fill_addseq(tab, N); acb_get_mag(qmag, q); log2q_approx = mag_get_log2_d_approx(qmag); for (k = 0; k < N; k++) { if (k == 0) { acb_one(qpow + k); } else if (k == 1) { acb_set_round(qpow + k, q, prec); } else if (tab[k] != 0) { log2term_approx = k * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); acb_mul_approx(qpow + k, t1, t2, qpow + tab[k], qpow + k - tab[k], term_prec, prec); } } for (k = 0; k*(k+1) < N; k++) acb_add(s1, s1, qpow + k*(k+1), prec); for (k = 1; 4*k*k < N; k++) acb_add(s2, s2, qpow + 4*k*k, prec); for (k = 0; 4*k*(k+1) + 1 < N; k++) acb_add(s3, s3, qpow + 4*k*(k+1), prec); /* theta2 = 2 + 2q^2 + 2q^6 + 2q^12 + 2q^20 + 2q^30 + ... theta3 = 1 + 2 (q^4 + q^16 + ...) + 2q (1 + q^8 + q^24 + ...) theta4 = 1 + 2 (q^4 + q^16 + ...) - 2q (1 + q^8 + q^24 + ...) */ acb_mul(s3, s3, q, prec); acb_mul_2exp_si(s3, s3, 1); acb_mul_2exp_si(s2, s2, 1); acb_add(theta3, s2, s3, prec); acb_sub(theta4, s2, s3, prec); acb_add_ui(theta3, theta3, 1, prec); acb_add_ui(theta4, theta4, 1, prec); acb_mul_2exp_si(theta2, s1, 1); _acb_vec_clear(qpow, N); flint_free(tab); acb_clear(s1); acb_clear(s2); acb_clear(s3); acb_clear(t1); acb_clear(t2); mag_clear(qmag); }
void acb_modular_theta_const_sum_rs(acb_t theta2, acb_t theta3, acb_t theta4, const acb_t q, long N, long prec) { long * tab; long k, term_prec, i, e, eprev; long M, m2, m3, num_square, num_trigonal; double log2q_approx, log2term_approx; acb_ptr qpow; acb_t tmp1, tmp2; mag_t qmag; mag_init(qmag); acb_get_mag(qmag, q); log2q_approx = mag_get_log2_d_approx(qmag); mag_clear(qmag); acb_init(tmp1); acb_init(tmp2); /* choose rectangular splitting parameters */ m2 = acb_modular_rs_optimal_m(trigonal_best_m, trigonal_best_m_residues, N); m3 = acb_modular_rs_optimal_m(square_best_m, square_best_m_residues, N); M = FLINT_MAX(m2, m3) + 1; /* build addition sequence */ tab = flint_calloc(M, sizeof(long)); for (k = 0; k*(k+1) < N; k++) tab[(k*(k+1)) % m2] = -1; num_trigonal = k; for (k = 0; k*k < N; k++) tab[(k*k) % m3] = -1; num_square = k; tab[m2] = -1; tab[m3] = -1; /* compute powers in addition sequence */ qpow = _acb_vec_init(M); acb_modular_fill_addseq(tab, M); for (k = 0; k < M; k++) { if (k == 0) { acb_one(qpow + k); } else if (k == 1) { acb_set_round(qpow + k, q, prec); } else if (tab[k] != 0) { log2term_approx = k * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); acb_mul_approx(qpow + k, tmp1, tmp2, qpow + tab[k], qpow + k - tab[k], term_prec, prec); } } /* compute theta2 */ acb_zero(theta2); term_prec = prec; for (k = num_trigonal - 1; k >= 0; k--) { e = k * (k + 1); /* exponent */ eprev = (k + 1) * (k + 2); log2term_approx = e * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); /* giant steps */ for (i = e / m2; i < eprev / m2; i++) { if (!acb_is_zero(theta2)) acb_mul_approx(theta2, tmp1, tmp2, theta2, qpow + m2, term_prec, prec); } acb_add(theta2, theta2, qpow + (e % m2), prec); } acb_mul_2exp_si(theta2, theta2, 1); /* compute theta3, theta4 */ acb_zero(theta3); acb_zero(theta4); term_prec = prec; for (k = num_square - 1; k >= 0; k--) { e = k * k; /* exponent */ eprev = (k + 1) * (k + 1); log2term_approx = e * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); /* giant steps */ for (i = e / m3; i < eprev / m3; i++) { if (!acb_is_zero(theta3)) acb_mul_approx(theta3, tmp1, tmp2, theta3, qpow + m3, term_prec, prec); if (!acb_is_zero(theta4)) acb_mul_approx(theta4, tmp1, tmp2, theta4, qpow + m3, term_prec, prec); } if (k == 0) { acb_mul_2exp_si(theta3, theta3, 1); acb_mul_2exp_si(theta4, theta4, 1); } acb_add(theta3, theta3, qpow + (e % m3), prec); if (k % 2 == 0) acb_add(theta4, theta4, qpow + (e % m3), prec); else acb_sub(theta4, theta4, qpow + (e % m3), prec); } acb_clear(tmp1); acb_clear(tmp2); _acb_vec_clear(qpow, M); flint_free(tab); }
void acb_hypgeom_pfq_sum_rs(acb_t res, acb_t term, acb_srcptr a, slong p, acb_srcptr b, slong q, const acb_t z, slong n, slong prec) { acb_ptr zpow; acb_t s, t, u; slong i, j, k, m; mag_t B, C; if (n == 0) { acb_zero(res); acb_one(term); return; } if (n < 0) abort(); m = n_sqrt(n); m = FLINT_MIN(m, 150); mag_init(B); mag_init(C); acb_init(s); acb_init(t); acb_init(u); zpow = _acb_vec_init(m + 1); _acb_vec_set_powers(zpow, z, m + 1, prec); mag_one(B); for (k = n; k >= 0; k--) { j = k % m; if (k < n) acb_add(s, s, zpow + j, prec); if (k > 0) { if (p > 0) { acb_add_ui(u, a, k - 1, prec); for (i = 1; i < p; i++) { acb_add_ui(t, a + i, k - 1, prec); acb_mul(u, u, t, prec); } if (k < n) acb_mul(s, s, u, prec); acb_get_mag(C, u); mag_mul(B, B, C); } if (q > 0) { acb_add_ui(u, b, k - 1, prec); for (i = 1; i < q; i++) { acb_add_ui(t, b + i, k - 1, prec); acb_mul(u, u, t, prec); } if (k < n) acb_div(s, s, u, prec); acb_get_mag_lower(C, u); mag_div(B, B, C); } if (j == 0 && k < n) { acb_mul(s, s, zpow + m, prec); } } } acb_get_mag(C, z); mag_pow_ui(C, C, n); mag_mul(B, B, C); acb_zero(term); if (_acb_vec_is_real(a, p) && _acb_vec_is_real(b, q) && acb_is_real(z)) arb_add_error_mag(acb_realref(term), B); else acb_add_error_mag(term, B); acb_set(res, s); mag_clear(B); mag_clear(C); acb_clear(s); acb_clear(t); acb_clear(u); _acb_vec_clear(zpow, m + 1); }
void acb_hypgeom_2f1_continuation(acb_t res, acb_t res1, const acb_t a, const acb_t b, const acb_t c, const acb_t y, const acb_t z, const acb_t f0, const acb_t f1, long prec) { mag_t A, nu, N, w, err, err1, R, T, goal; acb_t x; long j, k; mag_init(A); mag_init(nu); mag_init(N); mag_init(err); mag_init(err1); mag_init(w); mag_init(R); mag_init(T); mag_init(goal); acb_init(x); bound(A, nu, N, a, b, c, y, f0, f1); acb_sub(x, z, y, prec); /* |T(k)| <= A * binomial(N+k, k) * nu^k * |x|^k */ acb_get_mag(w, x); mag_mul(w, w, nu); /* w = nu |x| */ mag_mul_2exp_si(goal, A, -prec-2); /* bound for T(0) */ mag_set(T, A); mag_inf(R); for (k = 1; k < 100 * prec; k++) { /* T(k) = T(k) * R(k), R(k) = (N+k)/k * w = (1 + N/k) w */ mag_div_ui(R, N, k); mag_add_ui(R, R, 1); mag_mul(R, R, w); /* T(k) */ mag_mul(T, T, R); if (mag_cmp(T, goal) <= 0 && mag_cmp_2exp_si(R, 0) < 0) break; } /* T(k) [1 + R + R^2 + R^3 + ...] */ mag_geom_series(err, R, 0); mag_mul(err, T, err); /* Now compute T, R for the derivative */ /* Coefficients are A * (k+1) * binomial(N+k+1, k+1) */ mag_add_ui(T, N, 1); mag_mul(T, T, A); mag_inf(R); for (j = 1; j <= k; j++) { mag_add_ui(R, N, k + 1); mag_div_ui(R, R, k); mag_mul(R, R, w); mag_mul(T, T, R); } mag_geom_series(err1, R, 0); mag_mul(err1, T, err1); if (mag_is_inf(err)) { acb_indeterminate(res); acb_indeterminate(res1); } else { evaluate_sum(res, res1, a, b, c, y, x, f0, f1, k, prec); acb_add_error_mag(res, err); acb_add_error_mag(res1, err1); } mag_clear(A); mag_clear(nu); mag_clear(N); mag_clear(err); mag_clear(err1); mag_clear(w); mag_clear(R); mag_clear(T); mag_clear(goal); acb_clear(x); }
/* computes the factors that are independent of n (all are upper bounds) */ void acb_hypgeom_u_asymp_bound_factors(int * R, mag_t alpha, mag_t nu, mag_t sigma, mag_t rho, mag_t zinv, const acb_t a, const acb_t b, const acb_t z) { mag_t r, u, zre, zim, zlo, sigma_prime; acb_t t; mag_init(r); mag_init(u); mag_init(zre); mag_init(zim); mag_init(zlo); mag_init(sigma_prime); acb_init(t); /* lower bounds for |re(z)|, |im(z)|, |z| */ arb_get_mag_lower(zre, acb_realref(z)); arb_get_mag_lower(zim, acb_imagref(z)); acb_get_mag_lower(zlo, z); /* todo: hypot */ /* upper bound for 1/|z| */ mag_one(u); mag_div(zinv, u, zlo); /* upper bound for r = |b - 2a| */ acb_mul_2exp_si(t, a, 1); acb_sub(t, b, t, MAG_BITS); acb_get_mag(r, t); /* determine region */ *R = 0; if (mag_cmp(zlo, r) >= 0) { int znonneg = arb_is_nonnegative(acb_realref(z)); if (znonneg && mag_cmp(zre, r) >= 0) { *R = 1; } else if (mag_cmp(zim, r) >= 0 || znonneg) { *R = 2; } else { mag_mul_2exp_si(u, r, 1); if (mag_cmp(zlo, u) >= 0) *R = 3; } } if (R == 0) { mag_inf(alpha); mag_inf(nu); mag_inf(sigma); mag_inf(rho); } else { /* sigma = |(b-2a)/z| */ mag_mul(sigma, r, zinv); /* nu = (1/2 + 1/2 sqrt(1-4 sigma^2))^(-1/2) <= 1 + 2 sigma^2 */ if (mag_cmp_2exp_si(sigma, -1) <= 0) { mag_mul(nu, sigma, sigma); mag_mul_2exp_si(nu, nu, 1); mag_one(u); mag_add(nu, nu, u); } else { mag_inf(nu); } /* modified sigma for alpha, beta, rho when in R3 */ if (*R == 3) mag_mul(sigma_prime, sigma, nu); else mag_set(sigma_prime, sigma); /* alpha = 1/(1-sigma') */ mag_one(alpha); mag_sub_lower(alpha, alpha, sigma_prime); mag_one(u); mag_div(alpha, u, alpha); /* rho = |2a^2-2ab+b|/2 + sigma'*(1+sigma'/4)/(1-sigma')^2 */ mag_mul_2exp_si(rho, sigma_prime, -2); mag_one(u); mag_add(rho, rho, u); mag_mul(rho, rho, sigma_prime); mag_mul(rho, rho, alpha); mag_mul(rho, rho, alpha); acb_sub(t, a, b, MAG_BITS); acb_mul(t, t, a, MAG_BITS); acb_mul_2exp_si(t, t, 1); acb_add(t, t, b, MAG_BITS); acb_get_mag(u, t); mag_mul_2exp_si(u, u, -1); mag_add(rho, rho, u); } mag_clear(r); mag_clear(u); mag_clear(zre); mag_clear(zim); mag_clear(zlo); mag_clear(sigma_prime); acb_clear(t); }
int main() { long iter; flint_rand_t state; printf("root_bound_fujiwara...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000; iter++) { acb_poly_t a; acb_ptr roots; acb_t t; mag_t mag1, mag2; long i, deg, prec; prec = 10 + n_randint(state, 400); deg = n_randint(state, 10); acb_init(t); acb_poly_init(a); mag_init(mag1); mag_init(mag2); roots = _acb_vec_init(deg); for (i = 0; i < deg; i++) acb_randtest(roots + i, state, prec, 1 + n_randint(state, 20)); acb_poly_product_roots(a, roots, deg, prec); acb_randtest(t, state, prec, 1 + n_randint(state, 20)); _acb_vec_scalar_mul(a->coeffs, a->coeffs, a->length, t, prec); acb_poly_root_bound_fujiwara(mag1, a); for (i = 0; i < deg; i++) { acb_get_mag(mag2, roots + i); /* acb_get_mag gives an upper bound which due to rounding could be larger than mag1, so we pick a slightly smaller number */ mag_mul_ui(mag2, mag2, 10000); mag_div_ui(mag2, mag2, 10001); if (mag_cmp(mag2, mag1) > 0) { printf("FAIL\n"); printf("a = "); acb_poly_printd(a, 15); printf("\n\n"); printf("root = "); acb_printd(roots + i, 15); printf("\n\n"); printf("mag1 = "); mag_printd(mag1, 10); printf("\n\n"); printf("mag2 = "); mag_printd(mag2, 10); printf("\n\n"); abort(); } } _acb_vec_clear(roots, deg); acb_clear(t); acb_poly_clear(a); mag_clear(mag1); mag_clear(mag2); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
void _acb_lambertw(acb_t res, const acb_t z, const acb_t ez1, const fmpz_t k, int flags, slong prec) { slong goal, ebits, ebits2, ls, lt; const fmpz * expo; /* Estimated accuracy goal. */ /* todo: account for exponent bits and bits in k. */ goal = acb_rel_accuracy_bits(z); goal = FLINT_MAX(goal, 10); goal = FLINT_MIN(goal, prec); /* Handle tiny z directly. For k >= 2, |c_k| <= 4^k / 16. */ if (fmpz_is_zero(k) && arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), -goal / 2) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), -goal / 2) < 0) { mag_t err; mag_init(err); acb_get_mag(err, z); mag_mul_2exp_si(err, err, 2); acb_set(res, z); acb_submul(res, res, res, prec); mag_geom_series(err, err, 3); mag_mul_2exp_si(err, err, -4); acb_add_error_mag(res, err); mag_clear(err); return; } if (arf_cmpabs(arb_midref(acb_realref(z)), arb_midref(acb_imagref(z))) >= 0) expo = ARF_EXPREF(arb_midref(acb_realref(z))); else expo = ARF_EXPREF(arb_midref(acb_imagref(z))); ebits = fmpz_bits(expo); /* ebits ~= log2(|log(z) + 2 pi i k|) */ /* ebits2 ~= log2(log(log(z))) */ ebits = FLINT_MAX(ebits, fmpz_bits(k)); ebits = FLINT_MAX(ebits, 1) - 1; ebits2 = FLINT_BIT_COUNT(ebits); ebits2 = FLINT_MAX(ebits2, 1) - 1; /* We gain accuracy from the exponent when W ~ log - log log */ if (fmpz_sgn(expo) > 0 || (fmpz_sgn(expo) < 0 && !fmpz_is_zero(k))) { goal += ebits - ebits2; goal = FLINT_MAX(goal, 10); goal = FLINT_MIN(goal, prec); /* The asymptotic series with truncation L, M gives us about t - max(2+lt+L*(2+ls), M*(2+lt)) bits of accuracy where ls = -ebits, lt = ebits2 - ebits. */ ls = 2 - ebits; lt = 2 + ebits2 - ebits; if (ebits - FLINT_MAX(lt + 1*ls, 1*lt) > goal) { acb_lambertw_asymp(res, z, k, 1, 1, goal); acb_set_round(res, res, prec); return; } else if (ebits - FLINT_MAX(lt + 3*ls, 5*lt) > goal) { acb_lambertw_asymp(res, z, k, 3, 5, goal); acb_set_round(res, res, prec); return; } } /* Extremely close to the branch point at -1/e, use the series expansion directly. */ if (acb_lambertw_try_near_branch_point(res, z, ez1, k, flags, goal)) { acb_set_round(res, res, prec); return; } /* compute union of both sides */ if (acb_lambertw_branch_crossing(z, ez1, k)) { acb_t za, zb, eza1, ezb1; fmpz_t kk; acb_init(za); acb_init(zb); acb_init(eza1); acb_init(ezb1); fmpz_init(kk); fmpz_neg(kk, k); acb_set(za, z); acb_conj(zb, z); arb_nonnegative_part(acb_imagref(za), acb_imagref(za)); arb_nonnegative_part(acb_imagref(zb), acb_imagref(zb)); acb_set(eza1, ez1); acb_conj(ezb1, ez1); arb_nonnegative_part(acb_imagref(eza1), acb_imagref(eza1)); arb_nonnegative_part(acb_imagref(ezb1), acb_imagref(ezb1)); /* Check series expansion again, because now there is no crossing. */ if (!acb_lambertw_try_near_branch_point(res, za, eza1, k, flags, goal)) acb_lambertw_cleared_cut_fix_small(za, za, eza1, k, flags, goal); if (!acb_lambertw_try_near_branch_point(res, zb, ezb1, kk, flags, goal)) acb_lambertw_cleared_cut_fix_small(zb, zb, ezb1, kk, flags, goal); acb_conj(zb, zb); acb_union(res, za, zb, prec); acb_clear(za); acb_clear(zb); acb_clear(eza1); acb_clear(ezb1); fmpz_clear(kk); } else { acb_lambertw_cleared_cut_fix_small(res, z, ez1, k, flags, goal); acb_set_round(res, res, prec); } }
/* note: z should be exact here */ void acb_lambertw_main(acb_t res, const acb_t z, const acb_t ez1, const fmpz_t k, int flags, slong prec) { acb_t w, t, oldw, ew; mag_t err; slong i, wp, accuracy, ebits, kbits, mbits, wp_initial, extraprec; int have_ew; acb_init(t); acb_init(w); acb_init(oldw); acb_init(ew); mag_init(err); /* We need higher precision for large k, large exponents, or very close to the branch point at -1/e. todo: we should be recomputing ez1 to higher precision when close... */ acb_get_mag(err, z); if (fmpz_is_zero(k) && mag_cmp_2exp_si(err, 0) < 0) ebits = 0; else ebits = fmpz_bits(MAG_EXPREF(err)); if (fmpz_is_zero(k) || (fmpz_is_one(k) && arb_is_negative(acb_imagref(z))) || (fmpz_equal_si(k, -1) && arb_is_nonnegative(acb_imagref(z)))) { acb_get_mag(err, ez1); mbits = -MAG_EXP(err); mbits = FLINT_MAX(mbits, 0); mbits = FLINT_MIN(mbits, prec); } else { mbits = 0; } kbits = fmpz_bits(k); extraprec = FLINT_MAX(ebits, kbits); extraprec = FLINT_MAX(extraprec, mbits); wp = wp_initial = 40 + extraprec; accuracy = acb_lambertw_initial(w, z, ez1, k, wp_initial); mag_zero(arb_radref(acb_realref(w))); mag_zero(arb_radref(acb_imagref(w))); /* We should be able to compute e^w for the final certification during the Halley iteration. */ have_ew = 0; for (i = 0; i < 5 + FLINT_BIT_COUNT(prec + extraprec); i++) { /* todo: should we restart? */ if (!acb_is_finite(w)) break; wp = FLINT_MIN(3 * accuracy, 1.1 * prec + 10); wp = FLINT_MAX(wp, 40); wp += extraprec; acb_set(oldw, w); acb_lambertw_halley_step(t, ew, z, w, wp); /* estimate the error (conservatively) */ acb_sub(w, w, t, wp); acb_get_mag(err, w); acb_set(w, t); acb_add_error_mag(t, err); accuracy = acb_rel_accuracy_bits(t); if (accuracy > 2 * extraprec) accuracy *= 2.9; /* less conservatively */ accuracy = FLINT_MIN(accuracy, wp); accuracy = FLINT_MAX(accuracy, 0); if (accuracy > prec + extraprec) { /* e^w = e^oldw * e^(w-oldw) */ acb_sub(t, w, oldw, wp); acb_exp(t, t, wp); acb_mul(ew, ew, t, wp); have_ew = 1; break; } mag_zero(arb_radref(acb_realref(w))); mag_zero(arb_radref(acb_imagref(w))); } wp = FLINT_MIN(3 * accuracy, 1.1 * prec + 10); wp = FLINT_MAX(wp, 40); wp += extraprec; if (acb_lambertw_check_branch(w, k, wp)) { acb_t u, r, eu1; mag_t err, rad; acb_init(u); acb_init(r); acb_init(eu1); mag_init(err); mag_init(rad); if (have_ew) acb_set(t, ew); else acb_exp(t, w, wp); /* t = w e^w */ acb_mul(t, t, w, wp); acb_sub(r, t, z, wp); /* Bound W' on the straight line path between t and z */ acb_union(u, t, z, wp); arb_const_e(acb_realref(eu1), wp); arb_zero(acb_imagref(eu1)); acb_mul(eu1, eu1, u, wp); acb_add_ui(eu1, eu1, 1, wp); if (acb_lambertw_branch_crossing(u, eu1, k)) { mag_inf(err); } else { acb_lambertw_bound_deriv(err, u, eu1, k); acb_get_mag(rad, r); mag_mul(err, err, rad); } acb_add_error_mag(w, err); acb_set(res, w); acb_clear(u); acb_clear(r); acb_clear(eu1); mag_clear(err); mag_clear(rad); } else { acb_indeterminate(res); } acb_clear(t); acb_clear(w); acb_clear(oldw); acb_clear(ew); mag_clear(err); }
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); }
/* error propagation based on derivatives */ void acb_hypgeom_airy_direct_prop(acb_t ai, acb_t aip, acb_t bi, acb_t bip, const acb_t z, slong n, slong prec) { mag_t aib, aipb, bib, bipb, zb, rad; acb_t zz; int real; mag_init(aib); mag_init(aipb); mag_init(bib); mag_init(bipb); mag_init(zb); mag_init(rad); acb_init(zz); real = acb_is_real(z); arf_set(arb_midref(acb_realref(zz)), arb_midref(acb_realref(z))); arf_set(arb_midref(acb_imagref(zz)), arb_midref(acb_imagref(z))); mag_hypot(rad, arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); acb_get_mag(zb, z); acb_hypgeom_airy_bound(aib, aipb, bib, bipb, z); acb_hypgeom_airy_direct(ai, aip, bi, bip, zz, n, prec); if (ai != NULL) { mag_mul(aipb, aipb, rad); if (real) arb_add_error_mag(acb_realref(ai), aipb); else acb_add_error_mag(ai, aipb); } if (aip != NULL) { mag_mul(aib, aib, rad); mag_mul(aib, aib, zb); /* |Ai''(z)| = |z Ai(z)| */ if (real) arb_add_error_mag(acb_realref(aip), aib); else acb_add_error_mag(aip, aib); } if (bi != NULL) { mag_mul(bipb, bipb, rad); if (real) arb_add_error_mag(acb_realref(bi), bipb); else acb_add_error_mag(bi, bipb); } if (bip != NULL) { mag_mul(bib, bib, rad); mag_mul(bib, bib, zb); /* |Bi''(z)| = |z Bi(z)| */ if (real) arb_add_error_mag(acb_realref(bip), bib); else acb_add_error_mag(bip, bib); } mag_clear(aib); mag_clear(aipb); mag_clear(bib); mag_clear(bipb); mag_clear(zb); mag_clear(rad); acb_clear(zz); }
/* 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); }
void acb_hypgeom_u_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, slong n, slong prec) { acb_struct aa[3]; acb_t s, t, w, winv; int R, p, q, is_real, is_terminating; slong n_terminating; if (!acb_is_finite(a) || !acb_is_finite(b) || !acb_is_finite(z)) { acb_indeterminate(res); return; } acb_init(aa); acb_init(aa + 1); acb_init(aa + 2); acb_init(s); acb_init(t); acb_init(w); acb_init(winv); is_terminating = 0; n_terminating = WORD_MAX; /* special case, for incomplete gamma [todo: also when they happen to be exact and with difference 1...] */ if (a == b) { acb_set(aa, a); p = 1; q = 0; } else { acb_set(aa, a); acb_sub(aa + 1, a, b, prec); acb_add_ui(aa + 1, aa + 1, 1, prec); acb_one(aa + 2); p = 2; q = 1; } if (acb_is_nonpositive_int(aa)) { is_terminating = 1; if (arf_cmpabs_ui(arb_midref(acb_realref(aa)), prec) < 0) n_terminating = 1 - arf_get_si(arb_midref(acb_realref(aa)), ARF_RND_DOWN); } if (p == 2 && acb_is_nonpositive_int(aa + 1)) { is_terminating = 1; if (arf_cmpabs_ui(arb_midref(acb_realref(aa + 1)), n_terminating) < 0) n_terminating = 1 - arf_get_si(arb_midref(acb_realref(aa + 1)), ARF_RND_DOWN); } acb_neg(w, z); acb_inv(w, w, prec); acb_neg(winv, z); /* low degree polynomial -- no need to try to terminate sooner */ if (is_terminating && n_terminating < 8) { acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n_terminating, prec); acb_set(res, s); } else { mag_t C1, Cn, alpha, nu, sigma, rho, zinv, tmp, err; mag_init(C1); mag_init(Cn); mag_init(alpha); mag_init(nu); mag_init(sigma); mag_init(rho); mag_init(zinv); mag_init(tmp); mag_init(err); acb_hypgeom_u_asymp_bound_factors(&R, alpha, nu, sigma, rho, zinv, a, b, z); is_real = acb_is_real(a) && acb_is_real(b) && acb_is_real(z) && (is_terminating || arb_is_positive(acb_realref(z))); if (R == 0) { /* if R == 0, the error bound is infinite unless terminating */ if (is_terminating && n_terminating < prec) { acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n_terminating, prec); acb_set(res, s); } else { acb_indeterminate(res); } } else { /* C1 */ acb_hypgeom_mag_Cn(C1, R, nu, sigma, 1); /* err = 2 * alpha * exp(...) */ mag_mul(tmp, C1, rho); mag_mul(tmp, tmp, alpha); mag_mul(tmp, tmp, zinv); mag_mul_2exp_si(tmp, tmp, 1); mag_exp(err, tmp); mag_mul(err, err, alpha); mag_mul_2exp_si(err, err, 1); /* choose n automatically */ if (n < 0) { slong moreprec; /* take err into account when finding truncation point */ /* we should take Cn into account as well, but this depends on n which is to be determined; it's easier to look only at exp(...) which should be larger anyway */ if (mag_cmp_2exp_si(err, 10 * prec) > 0) moreprec = 10 * prec; else if (mag_cmp_2exp_si(err, 0) < 0) moreprec = 0; else moreprec = MAG_EXP(err); n = acb_hypgeom_pfq_choose_n_max(aa, p, aa + p, q, w, prec + moreprec, FLINT_MIN(WORD_MAX / 2, 50 + 10.0 * prec)); } acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n, prec); /* add error bound, if not terminating */ if (!(is_terminating && n == n_terminating)) { acb_hypgeom_mag_Cn(Cn, R, nu, sigma, n); mag_mul(err, err, Cn); /* nth term * factor */ acb_get_mag(tmp, t); mag_mul(err, err, tmp); if (is_real) arb_add_error_mag(acb_realref(s), err); else acb_add_error_mag(s, err); } acb_set(res, s); } mag_clear(C1); mag_clear(Cn); mag_clear(alpha); mag_clear(nu); mag_clear(sigma); mag_clear(rho); mag_clear(zinv); mag_clear(tmp); mag_clear(err); } acb_clear(aa); acb_clear(aa + 1); acb_clear(aa + 2); acb_clear(s); acb_clear(t); acb_clear(w); acb_clear(winv); }
int main() { slong iter; flint_rand_t state; flint_printf("2f1_continuation...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * arb_test_multiplier(); iter++) { acb_t a, b, c, z1, z2, f1, f2, g1, g2, h1, h2, aa, bb, cc; mag_t d0, d1, dt; slong prec; int regularized, ebits; acb_init(a); acb_init(b); acb_init(c); acb_init(aa); acb_init(bb); acb_init(cc); acb_init(z1); acb_init(z2); acb_init(f1); acb_init(f2); acb_init(g1); acb_init(g2); acb_init(h1); acb_init(h2); mag_init(d0); mag_init(d1); mag_init(dt); prec = 2 + n_randint(state, 300); ebits = 10; regularized = n_randint(state, 2); acb_randtest_param(a, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits / 2)); acb_randtest_param(b, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits / 2)); acb_randtest_param(c, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits / 2)); acb_randtest(h1, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits)); acb_randtest(h2, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits)); do { int left, upper, lower; acb_randtest_param(z1, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits)); acb_randtest_param(z2, state, 1 + n_randint(state, 400), 1 + n_randint(state, ebits)); /* we test both convergent and non-convergent cases, but try to be more efficient by generating more convergent cases */ if (n_randint(state, 2)) { acb_sub_ui(aa, z1, 1, prec); acb_get_mag(d0, z1); acb_get_mag(d1, aa); acb_get_mag(dt, z2); if (mag_cmp(dt, d0) >= 0 || mag_cmp(dt, d1) >= 0) continue; } acb_add(z2, z1, z2, prec); /* for the test, don't cross the branch cut */ acb_sub_ui(aa, z1, 1, prec); acb_sub_ui(bb, z2, 1, prec); left = arb_is_negative(acb_realref(aa)) && arb_is_negative(acb_realref(bb)); upper = arb_is_positive(acb_imagref(aa)) && arb_is_positive(acb_imagref(bb)); lower = arb_is_nonpositive(acb_imagref(aa)) && arb_is_nonpositive(acb_imagref(bb)); if (left || upper || lower) break; } while (1); acb_add_ui(aa, a, 1, prec); acb_add_ui(bb, b, 1, prec); acb_add_ui(cc, c, 1, prec); acb_hypgeom_2f1(f1, a, b, c, z1, regularized, prec); acb_hypgeom_2f1(f2, aa, bb, cc, z1, regularized, prec); acb_mul(f2, f2, a, prec); acb_mul(f2, f2, b, prec); if (!regularized) acb_div(f2, f2, c, prec); acb_hypgeom_2f1_continuation(h1, h2, a, b, c, z1, z2, f1, f2, prec); if (acb_is_finite(h1) || acb_is_finite(h2)) { acb_hypgeom_2f1(g1, a, b, c, z2, regularized, prec); acb_hypgeom_2f1(g2, aa, bb, cc, z2, regularized, prec); acb_mul(g2, g2, a, prec); acb_mul(g2, g2, b, prec); if (!regularized) acb_div(g2, g2, c, prec); if (!acb_overlaps(g1, h1) || !acb_overlaps(g2, h2)) { flint_printf("FAIL: consistency\n\n"); flint_printf("regularized = %d, prec = %wd\n\n", regularized, prec); flint_printf("a = "); acb_printd(a, 30); flint_printf("\n\n"); flint_printf("b = "); acb_printd(b, 30); flint_printf("\n\n"); flint_printf("c = "); acb_printd(c, 30); flint_printf("\n\n"); flint_printf("z1 = "); acb_printd(z1, 30); flint_printf("\n\n"); flint_printf("z2 = "); acb_printd(z2, 30); flint_printf("\n\n"); flint_printf("F(a,b,c,z1) and F'(a,b,c,z1):\n"); flint_printf("f1 = "); acb_printd(f1, 30); flint_printf("\n\n"); flint_printf("f2 = "); acb_printd(f2, 30); flint_printf("\n\n"); flint_printf("F(a,b,c,z2) and F'(a,b,c,z2):\n"); flint_printf("g1 = "); acb_printd(g1, 30); flint_printf("\n\n"); flint_printf("g2 = "); acb_printd(g2, 30); flint_printf("\n\n"); flint_printf("Computed F and F':\n"); flint_printf("h1 = "); acb_printd(h1, 30); flint_printf("\n\n"); flint_printf("h2 = "); acb_printd(h2, 30); flint_printf("\n\n"); flint_abort(); } } acb_clear(a); acb_clear(b); acb_clear(c); acb_clear(aa); acb_clear(bb); acb_clear(cc); acb_clear(z1); acb_clear(z2); acb_clear(f1); acb_clear(f2); acb_clear(g1); acb_clear(g2); acb_clear(h1); acb_clear(h2); mag_clear(d0); mag_clear(d1); mag_clear(dt); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void acb_rising_ui_get_mag(mag_t bound, const acb_t s, ulong n) { if (n == 0) { mag_one(bound); return; } if (n == 1) { acb_get_mag(bound, s); return; } if (!acb_is_finite(s)) { mag_inf(bound); return; } if (arf_sgn(arb_midref(acb_realref(s))) >= 0) { acb_rising_get_mag2_right(bound, acb_realref(s), acb_imagref(s), n); } else { arb_t a; long k; mag_t bound2, t, u; arb_init(a); mag_init(bound2); mag_init(t); mag_init(u); arb_get_mag(u, acb_imagref(s)); mag_mul(u, u, u); mag_one(bound); for (k = 0; k < n; k++) { arb_add_ui(a, acb_realref(s), k, MAG_BITS); if (arf_sgn(arb_midref(a)) >= 0) { acb_rising_get_mag2_right(bound2, a, acb_imagref(s), n - k); mag_mul(bound, bound, bound2); break; } else { arb_get_mag(t, a); mag_mul(t, t, t); mag_add(t, t, u); mag_mul(bound, bound, t); } } arb_clear(a); mag_clear(bound2); mag_clear(t); mag_clear(u); } mag_sqrt(bound, bound); }