void acb_real_min(acb_t res, const acb_t x, const acb_t y, int analytic, slong prec) { arb_t t; if (!acb_is_finite(x) || !acb_is_finite(y)) { acb_indeterminate(res); return; } arb_init(t); arb_sub(t, acb_realref(x), acb_realref(y), prec); if (arb_is_positive(t)) acb_set_round(res, y, prec); else if (arb_is_negative(t)) acb_set_round(res, x, prec); else if (!analytic) acb_union(res, x, y, prec); else acb_indeterminate(res); arb_clear(t); }
void _acb_poly_zeta_cpx_series(acb_ptr z, const acb_t s, const acb_t a, int deflate, long d, long prec) { ulong M, N; long i; arf_t bound; arb_ptr vb; if (d < 1) return; if (!acb_is_finite(s) || !acb_is_finite(a)) { _acb_vec_indeterminate(z, d); return; } arf_init(bound); vb = _arb_vec_init(d); _acb_poly_zeta_em_choose_param(bound, &N, &M, s, a, FLINT_MIN(d, 2), prec, MAG_BITS); _acb_poly_zeta_em_bound(vb, s, a, N, M, d, MAG_BITS); _acb_poly_zeta_em_sum(z, s, a, deflate, N, M, d, prec); for (i = 0; i < d; i++) { arb_get_abs_ubound_arf(bound, vb + i, MAG_BITS); arb_add_error_arf(acb_realref(z + i), bound); arb_add_error_arf(acb_imagref(z + i), bound); } arf_clear(bound); _arb_vec_clear(vb, d); }
void _acb_poly_zeta_cpx_series(acb_ptr z, const acb_t s, const acb_t a, int deflate, slong d, slong prec) { ulong M, N; slong i; mag_t bound; arb_ptr vb; int is_real, const_is_real; if (d < 1) return; if (!acb_is_finite(s) || !acb_is_finite(a)) { _acb_vec_indeterminate(z, d); return; } is_real = const_is_real = 0; if (acb_is_real(s) && acb_is_real(a)) { if (arb_is_positive(acb_realref(a))) { is_real = const_is_real = 1; } else if (arb_is_int(acb_realref(a)) && arb_is_int(acb_realref(s)) && arb_is_nonpositive(acb_realref(s))) { const_is_real = 1; } } mag_init(bound); vb = _arb_vec_init(d); _acb_poly_zeta_em_choose_param(bound, &N, &M, s, a, FLINT_MIN(d, 2), prec, MAG_BITS); _acb_poly_zeta_em_bound(vb, s, a, N, M, d, MAG_BITS); _acb_poly_zeta_em_sum(z, s, a, deflate, N, M, d, prec); for (i = 0; i < d; i++) { arb_get_mag(bound, vb + i); arb_add_error_mag(acb_realref(z + i), bound); if (!is_real && !(i == 0 && const_is_real)) arb_add_error_mag(acb_imagref(z + i), bound); } mag_clear(bound); _arb_vec_clear(vb, d); }
/* f(z) = |z^4 + 10z^3 + 19z^2 - 6z - 6| exp(z) (for real z) -- Helfgott's integral on MathOverflow */ int f_helfgott(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ acb_add_si(res, z, 10, prec); acb_mul(res, res, z, prec); acb_add_si(res, res, 19, prec); acb_mul(res, res, z, prec); acb_add_si(res, res, -6, prec); acb_mul(res, res, z, prec); acb_add_si(res, res, -6, prec); acb_real_abs(res, res, order != 0, prec); if (acb_is_finite(res)) { acb_t t; acb_init(t); acb_exp(t, z, prec); acb_mul(res, res, t, prec); acb_clear(t); } return 0; }
void acb_log_sin_pi(acb_t res, const acb_t z, slong prec) { if (!acb_is_finite(z)) { acb_indeterminate(res); return; } if (arb_is_positive(acb_imagref(z)) || (arb_is_zero(acb_imagref(z)) && arb_is_negative(acb_realref(z)))) { acb_log_sin_pi_half(res, z, prec, 1); } else if (arb_is_negative(acb_imagref(z)) || (arb_is_zero(acb_imagref(z)) && arb_is_positive(acb_realref(z)))) { acb_log_sin_pi_half(res, z, prec, 0); } else { acb_t t; acb_init(t); acb_log_sin_pi_half(t, z, prec, 1); acb_log_sin_pi_half(res, z, prec, 0); arb_union(acb_realref(res), acb_realref(res), acb_realref(t), prec); arb_union(acb_imagref(res), acb_imagref(res), acb_imagref(t), prec); acb_clear(t); } }
int f_monster(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_exp(t, z, prec); acb_real_floor(res, t, order != 0, prec); if (acb_is_finite(res)) { acb_sub(res, t, res, prec); acb_add(t, t, z, prec); acb_sin(t, t, prec); acb_mul(res, res, t, prec); } acb_clear(t); return 0; }
int f_horror(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { acb_t s, t; if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ acb_init(s); acb_init(t); acb_real_floor(res, z, order != 0, prec); if (acb_is_finite(res)) { acb_sub(res, z, res, prec); acb_set_d(t, 0.5); acb_sub(res, res, t, prec); acb_sin_cos(s, t, z, prec); acb_real_max(s, s, t, order != 0, prec); acb_mul(res, res, s, prec); } acb_clear(s); acb_clear(t); return 0; }
void acb_hypgeom_erf(acb_t res, const acb_t z, slong prec) { double x, y, absz2, logz; slong prec2; if (!acb_is_finite(z)) { acb_indeterminate(res); return; } if (acb_is_zero(z)) { acb_zero(res); return; } if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 0) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 0) < 0)) { acb_hypgeom_erf_1f1a(res, z, prec); return; } if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 64) > 0 || arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 64) > 0)) { acb_hypgeom_erf_asymp(res, z, prec, 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); absz2 = x * x + y * y; logz = 0.5 * log(absz2); if (logz - absz2 < -(prec + 8) * 0.69314718055994530942) { /* If the asymptotic term is small, we can compute with reduced precision */ prec2 = FLINT_MIN(prec + 4 + (y*y - x*x - logz) * 1.4426950408889634074, (double) prec); prec2 = FLINT_MAX(8, prec2); prec2 = FLINT_MIN(prec2, prec); acb_hypgeom_erf_asymp(res, z, prec, prec2); } else if (arf_cmpabs(arb_midref(acb_imagref(z)), arb_midref(acb_realref(z))) > 0) { acb_hypgeom_erf_1f1a(res, z, prec); } else { acb_hypgeom_erf_1f1b(res, z, prec); } }
void acb_hypgeom_fresnel(acb_t res1, acb_t res2, const acb_t z, int normalized, slong prec) { slong wp; acb_t w; arb_t c; if (!acb_is_finite(z)) { if (res1 != NULL) acb_indeterminate(res1); if (res2 != NULL) acb_indeterminate(res2); return; } acb_init(w); arb_init(c); wp = prec + 8; if (normalized) { arb_const_pi(c, wp); arb_sqrt(c, c, wp); arb_mul_2exp_si(c, c, -1); acb_mul_arb(w, z, c, wp); acb_hypgeom_fresnel_erf_error(res1, res2, w, wp); } else { arb_sqrt_ui(c, 2, wp); arb_mul_2exp_si(c, c, -1); acb_mul_arb(w, z, c, wp); acb_hypgeom_fresnel_erf_error(res1, res2, w, wp); arb_const_pi(c, wp); arb_mul_2exp_si(c, c, -1); arb_sqrt(c, c, wp); if (res1 != NULL) acb_mul_arb(res1, res1, c, wp); if (res2 != NULL) acb_mul_arb(res2, res2, c, wp); } if (res1 != NULL) { acb_mul_2exp_si(res1, res1, -2); acb_set_round(res1, res1, prec); } if (res2 != NULL) { acb_mul_2exp_si(res2, res2, -2); acb_set_round(res2, res2, prec); } acb_clear(w); arb_clear(c); }
void arb_hypgeom_bessel_jy(arb_t res1, arb_t res2, const arb_t nu, const arb_t z, slong prec) { acb_t t, u; acb_init(t); acb_init(u); arb_set(acb_realref(t), nu); arb_set(acb_realref(u), z); acb_hypgeom_bessel_jy(t, u, t, u, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res1, acb_realref(t)); else arb_indeterminate(res1); if (acb_is_finite(u) && acb_is_real(u)) arb_swap(res2, acb_realref(u)); else arb_indeterminate(res2); acb_clear(t); acb_clear(u); }
void acb_lambertw(acb_t res, const acb_t z, const fmpz_t k, int flags, slong prec) { acb_t ez1; if (!acb_is_finite(z)) { acb_indeterminate(res); return; } if (flags == ACB_LAMBERTW_LEFT) { acb_lambertw_left(res, z, k, prec); return; } if (flags == ACB_LAMBERTW_MIDDLE) { acb_lambertw_middle(res, z, prec); return; } if (acb_contains_zero(z) && !fmpz_is_zero(k)) { acb_indeterminate(res); return; } acb_init(ez1); /* precompute z*e + 1 */ arb_const_e(acb_realref(ez1), prec); acb_mul(ez1, ez1, z, prec); acb_add_ui(ez1, ez1, 1, prec); /* Compute standard branches */ /* use real code when possible */ if (acb_is_real(z) && arb_is_positive(acb_realref(ez1)) && (fmpz_is_zero(k) || (fmpz_equal_si(k, -1) && arb_is_negative(acb_realref(z))))) { arb_lambertw(acb_realref(res), acb_realref(z), !fmpz_is_zero(k), prec); arb_zero(acb_imagref(res)); } else { _acb_lambertw(res, z, ez1, k, flags, prec); } acb_clear(ez1); }
void arb_hypgeom_gamma_upper(arb_t res, const arb_t s, const arb_t z, int regularized, slong prec) { acb_t t, u; acb_init(t); acb_init(u); arb_set(acb_realref(t), s); arb_set(acb_realref(u), z); acb_hypgeom_gamma_upper(t, t, u, regularized, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); acb_clear(t); acb_clear(u); }
void arb_hypgeom_hermite_h(arb_t res, const arb_t nu, const arb_t z, slong prec) { acb_t t, u; acb_init(t); acb_init(u); arb_set(acb_realref(t), nu); arb_set(acb_realref(u), z); acb_hypgeom_hermite_h(t, t, u, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); acb_clear(t); acb_clear(u); }
void arb_hypgeom_pfq(arb_t res, arb_srcptr a, slong p, arb_srcptr b, slong q, const arb_t z, int regularized, slong prec) { acb_ptr t; slong i; t = _acb_vec_init(p + q + 1); for (i = 0; i < p; i++) arb_set(acb_realref(t + i), a + i); for (i = 0; i < q; i++) arb_set(acb_realref(t + p + i), b + i); arb_set(acb_realref(t + p + q), z); acb_hypgeom_pfq(t, t, p, t + p, q, t + p + q, regularized, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); _acb_vec_clear(t, p + q + 1); }
void arb_hypgeom_beta_lower(arb_t res, const arb_t a, const arb_t b, const arb_t z, int regularized, slong prec) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); arb_set(acb_realref(t), a); arb_set(acb_realref(u), b); arb_set(acb_realref(v), z); acb_hypgeom_beta_lower(t, t, u, v, regularized, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); acb_clear(t); acb_clear(u); acb_clear(v); }
void arb_hypgeom_legendre_q(arb_t res, const arb_t n, const arb_t m, const arb_t z, int type, slong prec) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); arb_set(acb_realref(t), n); arb_set(acb_realref(u), m); arb_set(acb_realref(v), z); acb_hypgeom_legendre_q(t, t, u, v, type, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); acb_clear(t); acb_clear(u); acb_clear(v); }
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 arb_hypgeom_jacobi_p(arb_t res, const arb_t n, const arb_t a, const arb_t b, const arb_t z, slong prec) { acb_t t, u, v, w; acb_init(t); acb_init(u); acb_init(v); acb_init(w); arb_set(acb_realref(t), n); arb_set(acb_realref(u), a); arb_set(acb_realref(v), b); arb_set(acb_realref(w), z); acb_hypgeom_jacobi_p(t, t, u, v, w, prec); if (acb_is_finite(t) && acb_is_real(t)) arb_swap(res, acb_realref(t)); else arb_indeterminate(res); acb_clear(t); acb_clear(u); acb_clear(v); acb_clear(w); }
void acb_hypgeom_bessel_i_asymp(acb_t res, const acb_t nu, const acb_t z, long prec) { acb_t A1, A2, C, U1, U2, s, t, u; int is_real, is_imag; acb_init(A1); acb_init(A2); acb_init(C); acb_init(U1); acb_init(U2); acb_init(s); acb_init(t); acb_init(u); is_imag = 0; is_real = acb_is_real(nu) && acb_is_real(z) && (acb_is_int(nu) || arb_is_positive(acb_realref(z))); if (!is_real && arb_is_zero(acb_realref(z)) && acb_is_int(nu)) { acb_mul_2exp_si(t, nu, -1); if (acb_is_int(t)) is_real = 1; else is_imag = 1; } acb_hypgeom_bessel_i_asymp_prefactors(A1, A2, C, nu, z, prec); /* todo: if Ap ~ 2^a and Am = 2^b and U1 ~ U2 ~ 1, change precision? */ if (!acb_is_finite(A1) || !acb_is_finite(A2) || !acb_is_finite(C)) { acb_indeterminate(res); } else { /* s = 1/2 + nu */ acb_one(s); acb_mul_2exp_si(s, s, -1); acb_add(s, s, nu, prec); /* t = 1 + 2 nu */ acb_mul_2exp_si(t, nu, 1); acb_add_ui(t, t, 1, prec); acb_mul_2exp_si(u, z, 1); acb_hypgeom_u_asymp(U1, s, t, u, -1, prec); acb_neg(u, u); acb_hypgeom_u_asymp(U2, s, t, u, -1, prec); acb_mul(res, A1, U1, prec); acb_addmul(res, A2, U2, prec); acb_mul(res, res, C, prec); if (is_real) arb_zero(acb_imagref(res)); if (is_imag) arb_zero(acb_realref(res)); } acb_clear(A1); acb_clear(A2); acb_clear(C); acb_clear(U1); acb_clear(U2); acb_clear(s); acb_clear(t); acb_clear(u); }
void _acb_poly_digamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec) { int reflect; slong i, r, n, rflen, wp; acb_t zr; acb_ptr t, u, v; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { acb_digamma(res, h, prec); if (acb_is_finite(res)) _acb_vec_zero(res + 1, len - 1); else _acb_vec_indeterminate(res + 1, len - 1); return; } /* use real code for real input */ if (_acb_vec_is_real(h, hlen)) { arb_ptr tmp = _arb_vec_init(len); for (i = 0; i < hlen; i++) arb_set(tmp + i, acb_realref(h + i)); _arb_poly_digamma_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 + 1); u = _acb_vec_init(len + 1); v = _acb_vec_init(len + 1); acb_init(zr); /* use Stirling series */ acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 1, wp); /* psi(x) = psi((1-x)+r) - h(1-x,r) - pi*cot(pi*x) */ if (reflect) { if (r != 0) /* otherwise t = 0 */ { acb_sub_ui(v, h, 1, wp); acb_neg(v, v); acb_one(v + 1); rflen = FLINT_MIN(len + 1, r + 1); _acb_poly_rising_ui_series(u, v, 2, r, rflen, wp); _acb_poly_derivative(v, u, rflen, wp); _acb_poly_div_series(t, v, rflen - 1, u, rflen, len, wp); for (i = 1; i < len; i += 2) acb_neg(t + i, t + i); } acb_sub_ui(zr, h, r + 1, wp); acb_neg(zr, zr); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, wp); for (i = 1; i < len; i += 2) acb_neg(u + i, u + i); _acb_vec_sub(u, u, t, len, wp); acb_set(t, h); acb_one(t + 1); _acb_poly_cot_pi_series(t, t, 2, len, wp); acb_const_pi(v, wp); _acb_vec_scalar_mul(t, t, len, v, wp); _acb_vec_sub(u, u, t, len, wp); } else { if (r == 0) { acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, wp); } else { acb_set(v, h); acb_one(v + 1); rflen = FLINT_MIN(len + 1, r + 1); _acb_poly_rising_ui_series(u, v, 2, r, rflen, wp); _acb_poly_derivative(v, u, rflen, wp); _acb_poly_div_series(t, v, rflen - 1, u, rflen, len, wp); acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, 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 + 1); _acb_vec_clear(u, len + 1); _acb_vec_clear(v, len + 1); }
void acb_dirichlet_zeta_rs_mid(acb_t res, const acb_t s, slong K, slong prec) { acb_t R1, R2, X, t; slong wp; if (arf_sgn(arb_midref(acb_imagref(s))) < 0) { acb_init(t); acb_conj(t, s); acb_dirichlet_zeta_rs(res, t, K, prec); acb_conj(res, res); acb_clear(t); return; } acb_init(R1); acb_init(R2); acb_init(X); acb_init(t); /* rs_r increases the precision internally */ wp = prec; acb_dirichlet_zeta_rs_r(R1, s, K, wp); if (arb_is_exact(acb_realref(s)) && (arf_cmp_2exp_si(arb_midref(acb_realref(s)), -1) == 0)) { acb_conj(R2, R1); } else { /* conj(R(conj(1-s))) */ arb_sub_ui(acb_realref(t), acb_realref(s), 1, 10 * wp); arb_neg(acb_realref(t), acb_realref(t)); arb_set(acb_imagref(t), acb_imagref(s)); acb_dirichlet_zeta_rs_r(R2, t, K, wp); acb_conj(R2, R2); } if (acb_is_finite(R1) && acb_is_finite(R2)) { wp += 10 + arf_abs_bound_lt_2exp_si(arb_midref(acb_imagref(s))); wp = FLINT_MAX(wp, 10); /* X = pi^(s-1/2) gamma((1-s)/2) rgamma(s/2) = (2 pi)^s rgamma(s) / (2 cos(pi s / 2)) */ acb_rgamma(X, s, wp); acb_const_pi(t, wp); acb_mul_2exp_si(t, t, 1); acb_pow(t, t, s, wp); acb_mul(X, X, t, wp); acb_mul_2exp_si(t, s, -1); acb_cos_pi(t, t, wp); acb_mul_2exp_si(t, t, 1); acb_div(X, X, t, wp); acb_mul(R2, R2, X, wp); } /* R1 + X * R2 */ acb_add(res, R1, R2, prec); acb_clear(R1); acb_clear(R2); acb_clear(X); acb_clear(t); }
void acb_dirichlet_l(acb_t res, const acb_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec) { if (!acb_is_finite(s)) { acb_indeterminate(res); } else if (G == NULL || G->q == 1) { acb_dirichlet_zeta(res, s, prec); } else if (dirichlet_char_is_primitive(G, chi) && (arf_cmp_d(arb_midref(acb_realref(s)), -0.5) < 0 || (G->q != 1 && dirichlet_parity_char(G, chi) == 0 && arf_cmpabs_d(arb_midref(acb_imagref(s)), 0.125) < 0 && arf_cmp_d(arb_midref(acb_realref(s)), 0.125) < 0))) { /* use functional equation */ acb_t t, u, v; int parity; ulong q; parity = dirichlet_parity_char(G, chi); q = G->q; acb_init(t); acb_init(u); acb_init(v); /* gamma((1-s+p)/2) / gamma((s+p)/2) */ acb_add_ui(t, s, parity, prec); acb_mul_2exp_si(t, t, -1); acb_rgamma(t, t, prec); if (!acb_is_zero(t)) /* assumes q != 1 when s = 0 */ { acb_neg(u, s); acb_add_ui(u, u, 1 + parity, prec); acb_mul_2exp_si(u, u, -1); acb_gamma(u, u, prec); acb_mul(t, t, u, prec); /* epsilon */ acb_dirichlet_root_number(u, G, chi, prec); acb_mul(t, t, u, prec); /* (pi/q)^(s-1/2) */ acb_const_pi(u, prec); acb_div_ui(u, u, q, prec); acb_set_d(v, -0.5); acb_add(v, v, s, prec); acb_pow(u, u, v, prec); acb_mul(t, t, u, prec); acb_sub_ui(u, s, 1, prec); acb_neg(u, u); acb_conj(u, u); acb_dirichlet_l_general(u, u, G, chi, prec); acb_conj(u, u); acb_mul(t, t, u, prec); if (dirichlet_char_is_real(G, chi) && acb_is_real(s)) arb_zero(acb_imagref(t)); } acb_set(res, t); acb_clear(t); acb_clear(u); acb_clear(v); } else { acb_dirichlet_l_general(res, s, G, chi, prec); } }
void acb_hypgeom_2f1(acb_t res, const acb_t a, const acb_t b, const acb_t c, const acb_t z, int flags, slong prec) { int algorithm, regularized; regularized = flags & ACB_HYPGEOM_2F1_REGULARIZED; if (!acb_is_finite(a) || !acb_is_finite(b) || !acb_is_finite(c) || !acb_is_finite(z)) { acb_indeterminate(res); return; } if (acb_is_zero(z)) { if (regularized) acb_rgamma(res, c, prec); else acb_one(res); return; } if (regularized && acb_is_int(c) && arb_is_nonpositive(acb_realref(c))) { if ((acb_is_int(a) && arb_is_nonpositive(acb_realref(a)) && arf_cmp(arb_midref(acb_realref(a)), arb_midref(acb_realref(c))) >= 0) || (acb_is_int(b) && arb_is_nonpositive(acb_realref(b)) && arf_cmp(arb_midref(acb_realref(b)), arb_midref(acb_realref(c))) >= 0)) { acb_zero(res); return; } } if (regularized && acb_eq(a, c)) { _acb_hypgeom_2f1r_reduced(res, b, c, z, prec); return; } if (regularized && acb_eq(b, c)) { _acb_hypgeom_2f1r_reduced(res, a, c, z, prec); return; } /* polynomial */ if (acb_is_int(a) && arf_sgn(arb_midref(acb_realref(a))) <= 0 && arf_cmpabs_ui(arb_midref(acb_realref(a)), prec) < 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); return; } /* polynomial */ if (acb_is_int(b) && arf_sgn(arb_midref(acb_realref(b))) <= 0 && arf_cmpabs_ui(arb_midref(acb_realref(b)), prec) < 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); return; } /* Try to reduce to a polynomial case using the Pfaff transformation */ /* TODO: look at flags for integer c-b, c-a here, even when c is nonexact */ if (acb_is_exact(c)) { acb_t t; acb_init(t); acb_sub(t, c, b, prec); if (acb_is_int(t) && arb_is_nonpositive(acb_realref(t))) { acb_hypgeom_2f1_transform(res, a, b, c, z, flags, 1, prec); acb_clear(t); return; } acb_sub(t, c, a, prec); if (acb_is_int(t) && arb_is_nonpositive(acb_realref(t))) { int f1, f2; /* When swapping a, b, also swap the flags. */ f1 = flags & ACB_HYPGEOM_2F1_AC; f2 = flags & ACB_HYPGEOM_2F1_BC; flags &= ~ACB_HYPGEOM_2F1_AC; flags &= ~ACB_HYPGEOM_2F1_BC; if (f1) flags |= ACB_HYPGEOM_2F1_BC; if (f2) flags |= ACB_HYPGEOM_2F1_AC; acb_hypgeom_2f1_transform(res, b, a, c, z, flags, 1, prec); acb_clear(t); return; } acb_clear(t); } /* special value at z = 1 */ if (acb_is_one(z)) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); acb_sub(t, c, a, prec); acb_sub(u, c, b, prec); acb_sub(v, t, b, prec); if (arb_is_positive(acb_realref(v))) { acb_rgamma(t, t, prec); acb_rgamma(u, u, prec); acb_mul(t, t, u, prec); acb_gamma(v, v, prec); acb_mul(t, t, v, prec); if (!regularized) { acb_gamma(v, c, prec); acb_mul(t, t, v, prec); } acb_set(res, t); } else { acb_indeterminate(res); } acb_clear(t); acb_clear(u); acb_clear(v); return; } algorithm = acb_hypgeom_2f1_choose(z); if (algorithm == 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); } else if (algorithm >= 1 && algorithm <= 5) { acb_hypgeom_2f1_transform(res, a, b, c, z, flags, algorithm, prec); } else { acb_hypgeom_2f1_corner(res, a, b, c, z, regularized, prec); } }
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); }
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("laguerre_l...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 2000 * arb_test_multiplier(); iter++) { acb_t n, m, n1, m1, z, res1, res2, res3, s; slong prec; acb_init(n); acb_init(m); acb_init(n1); acb_init(m1); acb_init(z); acb_init(res1); acb_init(res2); acb_init(res3); acb_init(s); prec = 2 + n_randint(state, 200); if (n_randint(state, 2)) { acb_set_si(n, n_randint(state, 20) - 10); acb_set_si(m, n_randint(state, 20) - 10); } else { acb_randtest_param(n, state, 1 + n_randint(state, 400), 10); acb_randtest_param(m, state, 1 + n_randint(state, 400), 10); } acb_randtest_param(z, state, 1 + n_randint(state, 400), 10); acb_sub_ui(n1, n, 1, prec); acb_sub_ui(m1, m, 1, prec); acb_hypgeom_laguerre_l(res1, n, m, z, prec); acb_hypgeom_laguerre_l(res2, n1, m, z, 2 + n_randint(state, 200)); acb_hypgeom_laguerre_l(res3, n, m1, z, 2 + n_randint(state, 200)); acb_add(s, res2, res3, prec); if (acb_is_finite(res1) && acb_is_finite(s) && !acb_overlaps(res1, s)) { flint_printf("FAIL: consistency\n\n"); flint_printf("iter = %wd\n\n", iter); flint_printf("n = "); acb_printd(n, 30); flint_printf("\n\n"); flint_printf("m = "); acb_printd(m, 30); flint_printf("\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("res1 = "); acb_printd(res1, 30); flint_printf("\n\n"); flint_printf("res2 = "); acb_printd(res2, 30); flint_printf("\n\n"); flint_printf("res3 = "); acb_printd(res3, 30); flint_printf("\n\n"); flint_printf("s = "); acb_printd(s, 30); flint_printf("\n\n"); abort(); } acb_clear(n); acb_clear(m); acb_clear(n1); acb_clear(m1); acb_clear(z); acb_clear(res1); acb_clear(res2); acb_clear(res3); acb_clear(s); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void acb_hypgeom_erf(acb_t res, const acb_t z, slong prec) { double x, y, abs_z2, log_z, log_erf_z_asymp; slong prec2, wp; int more_imaginary; if (!acb_is_finite(z)) { acb_indeterminate(res); return; } if (acb_is_zero(z)) { acb_zero(res); return; } if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), -64) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), -64) < 0)) { acb_hypgeom_erf_1f1(res, z, prec, prec, 1); return; } if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 64) > 0 || arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 64) > 0)) { acb_hypgeom_erf_asymp(res, z, 0, prec, 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); abs_z2 = x * x + y * y; log_z = 0.5 * log(abs_z2); /* estimate of log(erf(z)), disregarding csgn term */ log_erf_z_asymp = y*y - x*x - log_z; if (log_z - abs_z2 < -(prec + 8) * 0.69314718055994530942) { /* If the asymptotic term is small, we can compute with reduced precision. */ prec2 = FLINT_MIN(prec + 4 + log_erf_z_asymp * 1.4426950408889634074, (double) prec); prec2 = FLINT_MAX(8, prec2); prec2 = FLINT_MIN(prec2, prec); acb_hypgeom_erf_asymp(res, z, 0, prec, prec2); } else { more_imaginary = arf_cmpabs(arb_midref(acb_imagref(z)), arb_midref(acb_realref(z))) > 0; /* Worst case: exp(|x|^2), computed: exp(x^2). (x^2+y^2) - (x^2-y^2) = 2y^2, etc. */ if (more_imaginary) wp = prec + FLINT_MAX(2 * x * x, 0.0) * 1.4426950408889634074 + 5; else wp = prec + FLINT_MAX(2 * y * y, 0.0) * 1.4426950408889634074 + 5; acb_hypgeom_erf_1f1(res, z, prec, wp, more_imaginary); } }
void acb_inv(acb_t res, const acb_t z, slong prec) { mag_t am, bm; slong hprec; #define a arb_midref(acb_realref(z)) #define b arb_midref(acb_imagref(z)) #define x arb_radref(acb_realref(z)) #define y arb_radref(acb_imagref(z)) /* choose precision for the floating-point approximation of a^2+b^2 so that the double rounding result in less than 2 ulp error; also use at least MAG_BITS bits since the value will be recycled for error bounds */ hprec = FLINT_MAX(prec + 3, MAG_BITS); if (arb_is_zero(acb_imagref(z))) { arb_inv(acb_realref(res), acb_realref(z), prec); arb_zero(acb_imagref(res)); return; } if (arb_is_zero(acb_realref(z))) { arb_inv(acb_imagref(res), acb_imagref(z), prec); arb_neg(acb_imagref(res), acb_imagref(res)); arb_zero(acb_realref(res)); return; } if (!acb_is_finite(z)) { acb_indeterminate(res); return; } if (mag_is_zero(x) && mag_is_zero(y)) { int inexact; arf_t a2b2; arf_init(a2b2); inexact = arf_sosq(a2b2, a, b, hprec, ARF_RND_DOWN); if (arf_is_special(a2b2)) { acb_indeterminate(res); } else { _arb_arf_div_rounded_den(acb_realref(res), a, a2b2, inexact, prec); _arb_arf_div_rounded_den(acb_imagref(res), b, a2b2, inexact, prec); arf_neg(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(res))); } arf_clear(a2b2); return; } mag_init(am); mag_init(bm); /* first bound |a|-x, |b|-y */ arb_get_mag_lower(am, acb_realref(z)); arb_get_mag_lower(bm, acb_imagref(z)); if ((mag_is_zero(am) && mag_is_zero(bm))) { acb_indeterminate(res); } else { /* The propagated error in the real part is given exactly by (a+x')/((a+x')^2+(b+y'))^2 - a/(a^2+b^2) = P / Q, P = [(b^2-a^2) x' - a (x'^2+y'^2 + 2y'b)] Q = [(a^2+b^2)((a+x')^2+(b+y')^2)] where |x'| <= x and |y'| <= y, and analogously for the imaginary part. */ mag_t t, u, v, w; arf_t a2b2; int inexact; mag_init(t); mag_init(u); mag_init(v); mag_init(w); arf_init(a2b2); inexact = arf_sosq(a2b2, a, b, hprec, ARF_RND_DOWN); /* compute denominator */ /* t = (|a|-x)^2 + (|b|-x)^2 (lower bound) */ mag_mul_lower(t, am, am); mag_mul_lower(u, bm, bm); mag_add_lower(t, t, u); /* u = a^2 + b^2 (lower bound) */ arf_get_mag_lower(u, a2b2); /* t = ((|a|-x)^2 + (|b|-x)^2)(a^2 + b^2) (lower bound) */ mag_mul_lower(t, t, u); /* compute numerator */ /* real: |a^2-b^2| x + |a| ((x^2 + y^2) + 2 |b| y)) */ /* imag: |a^2-b^2| y + |b| ((x^2 + y^2) + 2 |a| x)) */ /* am, bm = upper bounds for a, b */ arf_get_mag(am, a); arf_get_mag(bm, b); /* v = x^2 + y^2 */ mag_mul(v, x, x); mag_addmul(v, y, y); /* u = |a| ((x^2 + y^2) + 2 |b| y) */ mag_mul_2exp_si(u, bm, 1); mag_mul(u, u, y); mag_add(u, u, v); mag_mul(u, u, am); /* v = |b| ((x^2 + y^2) + 2 |a| x) */ mag_mul_2exp_si(w, am, 1); mag_addmul(v, w, x); mag_mul(v, v, bm); /* w = |b^2 - a^2| (upper bound) */ if (arf_cmpabs(a, b) >= 0) mag_mul(w, am, am); else mag_mul(w, bm, bm); mag_addmul(u, w, x); mag_addmul(v, w, y); mag_div(arb_radref(acb_realref(res)), u, t); mag_div(arb_radref(acb_imagref(res)), v, t); _arb_arf_div_rounded_den_add_err(acb_realref(res), a, a2b2, inexact, prec); _arb_arf_div_rounded_den_add_err(acb_imagref(res), b, a2b2, inexact, prec); arf_neg(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(res))); mag_clear(t); mag_clear(u); mag_clear(v); mag_clear(w); arf_clear(a2b2); } mag_clear(am); mag_clear(bm); #undef a #undef b #undef x #undef y }
void acb_hypgeom_airy(acb_t ai, acb_t aip, acb_t bi, acb_t bip, const acb_t z, slong prec) { arf_srcptr re, im; double x, y, t, zmag, z15, term_est, airy_est, abstol; slong n, wp; if (!acb_is_finite(z)) { if (ai != NULL) acb_indeterminate(ai); if (aip != NULL) acb_indeterminate(aip); if (bi != NULL) acb_indeterminate(bi); if (bip != NULL) acb_indeterminate(bip); return; } re = arb_midref(acb_realref(z)); im = arb_midref(acb_imagref(z)); wp = prec * 1.03 + 15; /* tiny input -- use direct method and pick n without underflowing */ if (arf_cmpabs_2exp_si(re, -64) < 0 && arf_cmpabs_2exp_si(im, -64) < 0) { if (arf_cmpabs_2exp_si(re, -wp) < 0 && arf_cmpabs_2exp_si(im, -wp) < 0) { n = 1; /* very tiny input */ } else { if (arf_cmpabs(re, im) > 0) zmag = fmpz_get_d(ARF_EXPREF(re)); else zmag = fmpz_get_d(ARF_EXPREF(im)); zmag = (zmag + 1) * (1.0 / LOG2); n = wp / (-zmag) + 1; } acb_hypgeom_airy_direct(ai, aip, bi, bip, z, n, wp); } /* huge input -- use asymptotics and pick n without overflowing */ else if ((arf_cmpabs_2exp_si(re, 64) > 0 || arf_cmpabs_2exp_si(im, 64) > 0)) { if (arf_cmpabs_2exp_si(re, prec) > 0 || arf_cmpabs_2exp_si(im, prec) > 0) { n = 1; /* very huge input */ } else { x = fmpz_get_d(ARF_EXPREF(re)); y = fmpz_get_d(ARF_EXPREF(im)); zmag = (FLINT_MAX(x, y) - 2) * (1.0 / LOG2); n = asymp_pick_terms(wp, zmag); n = FLINT_MAX(n, 1); } acb_hypgeom_airy_asymp(ai, aip, bi, bip, z, n, wp); } else /* moderate input */ { x = arf_get_d(re, ARF_RND_DOWN); y = arf_get_d(im, ARF_RND_DOWN); zmag = sqrt(x * x + y * y); z15 = zmag * sqrt(zmag); if (zmag >= 4.0 && (n = asymp_pick_terms(wp, log(zmag))) != -1) { acb_hypgeom_airy_asymp(ai, aip, bi, bip, z, n, wp); } else if (zmag <= 1.5) { t = 3 * (wp * LOG2) / (2 * z15 * EXP1); t = (wp * LOG2) / (2 * d_lambertw(t)); n = FLINT_MAX(t + 1, 2); acb_hypgeom_airy_direct(ai, aip, bi, bip, z, n, wp); } else { /* estimate largest term: log2(exp(2(z^3/9)^(1/2))) */ term_est = 0.96179669392597560491 * z15; /* estimate the smaller of Ai and Bi */ airy_est = estimate_airy(x, y, (ai != NULL || aip != NULL)); /* estimate absolute tolerance and necessary working precision */ abstol = airy_est - wp; wp = wp + term_est - airy_est; wp = FLINT_MAX(wp, 10); t = 3 * (-abstol * LOG2) / (2 * z15 * EXP1); t = (-abstol * LOG2) / (2 * d_lambertw(t)); n = FLINT_MAX(t + 1, 2); if (acb_is_exact(z)) acb_hypgeom_airy_direct(ai, aip, bi, bip, z, n, wp); else acb_hypgeom_airy_direct_prop(ai, aip, bi, bip, z, n, wp); } } if (ai != NULL) acb_set_round(ai, ai, prec); if (aip != NULL) acb_set_round(aip, aip, prec); if (bi != NULL) acb_set_round(bi, bi, prec); if (bip != NULL) acb_set_round(bip, bip, prec); }
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; }