void acb_hypgeom_airy_asymp2(acb_t ai, acb_t aip, acb_t bi, acb_t bip, const acb_t z, slong n, slong prec) { /* avoid singularity in asymptotic expansion near 0 */ if (acb_rel_accuracy_bits(z) > 3) acb_hypgeom_airy_asymp(ai, aip, bi, bip, z, n, prec); else acb_hypgeom_airy_prop(ai, aip, bi, bip, z, n, 1, prec); }
void acb_dirichlet_zeta_rs(acb_t res, const acb_t s, slong K, slong prec) { if (acb_is_exact(s)) { acb_dirichlet_zeta_rs_mid(res, s, K, prec); } else { acb_t t; mag_t rad, err, err2; slong acc; acc = acb_rel_accuracy_bits(s); acc = FLINT_MAX(acc, 0); acc = FLINT_MIN(acc, prec); prec = FLINT_MIN(prec, acc + 20); acb_init(t); mag_init(rad); mag_init(err); mag_init(err2); /* rad = rad(s) */ mag_hypot(rad, arb_radref(acb_realref(s)), arb_radref(acb_imagref(s))); /* bound |zeta'(s)| */ acb_dirichlet_zeta_deriv_bound(err, err2, s); /* error <= |zeta'(s)| * rad(s) */ mag_mul(err, err, rad); /* evaluate at midpoint */ acb_get_mid(t, s); acb_dirichlet_zeta_rs_mid(res, t, K, prec); acb_add_error_mag(res, err); acb_clear(t); mag_clear(rad); mag_clear(err); mag_clear(err2); } }
int f_lambertw(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); prec = FLINT_MIN(prec, acb_rel_accuracy_bits(z) + 10); if (order != 0) { /* check for branch cut */ arb_const_e(acb_realref(t), prec); acb_inv(t, t, prec); acb_add(t, t, z, prec); if (arb_contains_zero(acb_imagref(t)) && arb_contains_nonpositive(acb_realref(t))) { acb_indeterminate(t); } } if (acb_is_finite(t)) { fmpz_t k; fmpz_init(k); acb_lambertw(res, z, k, 0, prec); fmpz_clear(k); } else { acb_indeterminate(res); } acb_clear(t); return 0; }
void acb_hypgeom_erf_1f1(acb_t res, const acb_t z, slong prec, slong wp, int more_imaginary) { if (acb_rel_accuracy_bits(z) >= wp) { if (more_imaginary) acb_hypgeom_erf_1f1a(res, z, wp); else acb_hypgeom_erf_1f1b(res, z, wp); } else { acb_t zmid; mag_t re_err, im_err; acb_init(zmid); mag_init(re_err); mag_init(im_err); acb_hypgeom_erf_propagated_error(re_err, im_err, z); arf_set(arb_midref(acb_realref(zmid)), arb_midref(acb_realref(z))); arf_set(arb_midref(acb_imagref(zmid)), arb_midref(acb_imagref(z))); if (more_imaginary) acb_hypgeom_erf_1f1a(res, zmid, wp); else acb_hypgeom_erf_1f1b(res, zmid, wp); arb_add_error_mag(acb_realref(res), re_err); arb_add_error_mag(acb_imagref(res), im_err); acb_clear(zmid); mag_clear(re_err); mag_clear(im_err); } acb_set_round(res, res, prec); }
int main() { slong iter; flint_rand_t state; flint_printf("rel_accuracy_bits...."); fflush(stdout); flint_randinit(state); /* test aliasing of c and a */ for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) { arb_t x; acb_t z; slong a1, a2; arb_init(x); acb_init(z); arb_randtest_special(x, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); acb_set_arb(z, x); a1 = arb_rel_accuracy_bits(x); a2 = acb_rel_accuracy_bits(z); if (a1 != a2) { flint_printf("FAIL: acb != arb\n\n"); flint_printf("x = "); arb_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } acb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); a1 = acb_rel_accuracy_bits(z); if (n_randint(state, 2)) arf_swap(arb_midref(acb_realref(z)), arb_midref(acb_imagref(z))); if (n_randint(state, 2)) mag_swap(arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); a2 = acb_rel_accuracy_bits(z); if (a1 != a2) { flint_printf("FAIL: swapping\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } acb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); if (arf_cmpabs(arb_midref(acb_realref(z)), arb_midref(acb_imagref(z))) >= 0) arf_set(arb_midref(x), arb_midref(acb_realref(z))); else arf_set(arb_midref(x), arb_midref(acb_imagref(z))); if (mag_cmp(arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))) >= 0) mag_set(arb_radref(x), arb_radref(acb_realref(z))); else mag_set(arb_radref(x), arb_radref(acb_imagref(z))); a1 = acb_rel_accuracy_bits(z); a2 = arb_rel_accuracy_bits(x); if (a1 != a2) { flint_printf("FAIL: acb != arb (2)\n\n"); flint_printf("x = "); arb_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } arb_clear(x); acb_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { int function, i, numtests; slong prec, goal; double t, total, logtotal; acb_t a, b, c, z, r, s; acb_init(a); acb_init(b); acb_init(c); acb_init(z); acb_init(r); acb_init(s); /* J(0,pi x) I(0,pi x) K(0,pi x) */ for (function = 0; function < 3; function++) { total = 0.0; logtotal = 0.0; if (function < 2) numtests = 40; else numtests = 30; for (i = 0; i < numtests; i++) { // printf("%2d ", i + 1); fflush(stdout); TIMEIT_START prec = 96; for (;;) { if (function == 0) { acb_set_d_d(a, input_1f1[i][0], input_1f1[i][1]); acb_set_d_d(b, input_1f1[i][2], input_1f1[i][3]); acb_set_d_d(z, input_1f1[i][4], input_1f1[i][5]); acb_hypgeom_m(r, a, b, z, 0, prec); } else if (function == 1) { acb_set_d_d(a, input_1f1[i][0], input_1f1[i][1]); acb_set_d_d(b, input_1f1[i][2], input_1f1[i][3]); acb_set_d_d(z, input_1f1[i][4], input_1f1[i][5]); acb_hypgeom_u(r, a, b, z, prec); } else if (function == 2) { acb_set_d_d(a, input_2f1[i][0], input_2f1[i][1]); acb_set_d_d(b, input_2f1[i][2], input_2f1[i][3]); acb_set_d_d(c, input_2f1[i][4], input_2f1[i][5]); acb_set_d_d(z, input_2f1[i][6], input_2f1[i][7]); acb_hypgeom_2f1(r, a, b, c, z, 0, prec); } else { acb_set_d_d(a, input_2f1[i][0], input_2f1[i][1]); acb_set_d_d(b, input_2f1[i][2], input_2f1[i][3]); acb_set_d_d(c, input_2f1[i][4], input_2f1[i][5]); acb_set_d_d(z, input_2f1[i][6], input_2f1[i][7]); acb_mul_2exp_si(z, z, 1); acb_sub_ui(z, z, 1, prec); acb_neg(z, z); acb_hypgeom_legendre_q(r, a, c, z, 0, prec); } if (function == 3) { if (acb_rel_accuracy_bits(r) >= goal) break; } else { if (arb_can_round_arf(acb_realref(r), goal, ARF_RND_NEAR) && arb_can_round_arf(acb_imagref(r), goal, ARF_RND_NEAR)) break; } prec *= 2; } TIMEIT_STOP_VAL(t) total += t; logtotal += log(t); #if 1 printf("%8g, ", t); #else printf("%8ld %8g ", prec, t); _acb_print(r, 25); printf("\n"); #endif } printf("---------------------------------------------------------------\n"); printf("Mean %g s; geometric mean %g\n", total, exp(logtotal / numtests)); printf("---------------------------------------------------------------\n"); } acb_clear(a); acb_clear(b); acb_clear(c); acb_clear(z); acb_clear(r); acb_clear(s); }
void acb_hypgeom_m_choose(int * asymp, int * kummer, slong * wp, const acb_t a, const acb_t b, const acb_t z, int regularized, slong prec) { double x, y, t, cancellation; double input_accuracy, direct_accuracy, asymp_accuracy; slong m = WORD_MAX; slong n = WORD_MAX; if (acb_is_int(a) && arf_cmpabs_2exp_si(arb_midref(acb_realref(a)), 30) < 0) { m = arf_get_si(arb_midref(acb_realref(a)), ARF_RND_DOWN); } if (acb_is_int(b) && arf_cmpabs_2exp_si(arb_midref(acb_realref(b)), 30) < 0) { n = arf_get_si(arb_midref(acb_realref(b)), ARF_RND_DOWN); } *asymp = 0; *kummer = 0; *wp = prec; /* The 1F1 series terminates. */ /* TODO: for large m, estimate extra precision here. */ if (m <= 0 && m < n && m > -10 * prec && (n > 0 || !regularized)) { *asymp = 0; return; } /* The 1F1 series terminates with the Kummer transform. */ /* TODO: for large m, estimate extra precision here. */ if (m >= 1 && n >= 1 && m < 0.1 * prec && n < 0.1 * prec && n <= m) { *asymp = 0; *kummer = 1; return; } input_accuracy = acb_rel_accuracy_bits(z); t = acb_rel_accuracy_bits(a); input_accuracy = FLINT_MIN(input_accuracy, t); t = acb_rel_accuracy_bits(b); input_accuracy = FLINT_MIN(input_accuracy, t); input_accuracy = FLINT_MAX(input_accuracy, 0.0); /* From here we ignore the values of a, b. Taking them into account is a possible future improvement... */ /* Tiny |z|. */ if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 2) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 2) < 0)) { *asymp = 0; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } /* Huge |z|. */ if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 64) > 0 || arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 64) > 0)) { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } x = arf_get_d(arb_midref(acb_realref(z)), ARF_RND_DOWN); y = arf_get_d(arb_midref(acb_imagref(z)), ARF_RND_DOWN); asymp_accuracy = sqrt(x * x + y * y) * 1.44269504088896 - 5.0; /* The Kummer transformation gives less cancellation with the 1F1 series. */ if (x < 0.0) { *kummer = 1; x = -x; } if (asymp_accuracy >= prec) { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } cancellation = hypotmx(x, y) * 1.44269504088896; direct_accuracy = input_accuracy - cancellation; if (direct_accuracy > asymp_accuracy) { *asymp = 0; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec + cancellation)); } else { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); } }
int main() { slong iter; flint_rand_t state; flint_printf("quadratic_roots_fmpz...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) { acb_t r1, r2, x, y; fmpz_t a, b, c; slong prec; fmpz_init(a); fmpz_init(b); fmpz_init(c); acb_init(r1); acb_init(r2); acb_init(x); acb_init(y); prec = 2 + n_randint(state, 1000); fmpz_randtest_not_zero(a, state, 1 + n_randint(state, 1000)); fmpz_randtest(b, state, 1 + n_randint(state, 1000)); fmpz_randtest(c, state, 1 + n_randint(state, 1000)); acb_randtest(r1, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_randtest(r2, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_quadratic_roots_fmpz(r1, r2, a, b, c, prec); acb_mul(x, r1, r1, prec); acb_mul_fmpz(x, x, a, prec); acb_addmul_fmpz(x, r1, b, prec); acb_add_fmpz(x, x, c, prec); acb_mul(y, r2, r2, prec); acb_mul_fmpz(y, y, a, prec); acb_addmul_fmpz(y, r2, b, prec); acb_add_fmpz(y, y, c, prec); if (!acb_contains_zero(x) || !acb_contains_zero(y) || acb_rel_accuracy_bits(r1) < prec - 4 || acb_rel_accuracy_bits(r2) < prec - 4) { flint_printf("FAIL: containment / accuracy\n\n"); flint_printf("prec = %wd\n", prec); flint_printf("a = "); fmpz_print(a); flint_printf("\n\n"); flint_printf("b = "); fmpz_print(b); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_printf("r1 = "); acb_printd(r1, 30); flint_printf("\n\n"); flint_printf("r2 = "); acb_printd(r2, 30); flint_printf("\n\n"); abort(); } fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); acb_clear(r1); acb_clear(r2); acb_clear(x); acb_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
int main() { slong iter; flint_rand_t state; flint_printf("lgamma_series...."); fflush(stdout); flint_randinit(state); /* special accuracy test case */ { acb_poly_t a; acb_t c; acb_init(c); acb_poly_init(a); arb_set_str(acb_realref(c), "-20.25", 53); arb_set_str(acb_imagref(c), "1e1000", 53); acb_poly_set_coeff_acb(a, 0, c); acb_poly_set_coeff_si(a, 1, 1); acb_poly_lgamma_series(a, a, 3, 53); if (acb_rel_accuracy_bits(a->coeffs) < 40 || acb_rel_accuracy_bits(a->coeffs + 1) < 40 || acb_rel_accuracy_bits(a->coeffs + 2) < 40) { flint_printf("FAIL: accuracy (reflection formula)\n\n"); acb_poly_printd(a, 15); flint_printf("\n\n"); abort(); } acb_poly_clear(a); acb_clear(c); } for (iter = 0; iter < 500 * arb_test_multiplier(); iter++) { slong m, n1, n2, rbits1, rbits2, rbits3; acb_poly_t a, b, c, d; rbits1 = 2 + n_randint(state, 200); rbits2 = 2 + n_randint(state, 200); rbits3 = 2 + n_randint(state, 200); m = 1 + n_randint(state, 30); n1 = 1 + n_randint(state, 30); n2 = 1 + n_randint(state, 30); acb_poly_init(a); acb_poly_init(b); acb_poly_init(c); acb_poly_init(d); acb_poly_randtest(a, state, m, rbits1, 10); acb_poly_randtest(b, state, m, rbits1, 10); acb_poly_randtest(c, state, m, rbits1, 10); acb_poly_lgamma_series(b, a, n1, rbits2); acb_poly_lgamma_series(c, a, n2, rbits3); acb_poly_set(d, b); acb_poly_truncate(d, FLINT_MIN(n1, n2)); acb_poly_truncate(c, FLINT_MIN(n1, n2)); if (!acb_poly_overlaps(c, d)) { flint_printf("FAIL\n\n"); flint_printf("n1 = %wd, n2 = %wd, bits2 = %wd, bits3 = %wd\n", n1, n2, rbits2, rbits3); flint_printf("a = "); acb_poly_printd(a, 15); flint_printf("\n\n"); flint_printf("b = "); acb_poly_printd(b, 15); flint_printf("\n\n"); flint_printf("c = "); acb_poly_printd(c, 15); flint_printf("\n\n"); abort(); } /* check loggamma(a) + log(a) = loggamma(a+1) */ acb_poly_log_series(c, a, n1, rbits2); acb_poly_add(c, b, c, rbits2); acb_poly_set(d, a); acb_add_ui(d->coeffs, d->coeffs, 1, rbits2); acb_poly_lgamma_series(d, d, n1, rbits2); if (!acb_poly_overlaps(c, d)) { flint_printf("FAIL (functional equation)\n\n"); flint_printf("a = "); acb_poly_printd(a, 15); flint_printf("\n\n"); flint_printf("b = "); acb_poly_printd(b, 15); flint_printf("\n\n"); flint_printf("c = "); acb_poly_printd(c, 15); flint_printf("\n\n"); flint_printf("d = "); acb_poly_printd(d, 15); flint_printf("\n\n"); abort(); } acb_poly_lgamma_series(a, a, n1, rbits2); if (!acb_poly_overlaps(a, b)) { flint_printf("FAIL (aliasing)\n\n"); abort(); } acb_poly_clear(a); acb_poly_clear(b); acb_poly_clear(c); acb_poly_clear(d); } flint_randclear(state); flint_cleanup(); flint_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); }