/* REAL: erf(x) = 2x/sqrt(pi) * exp(-x^2) 1F1(1, 3/2, x^2) */ void acb_hypgeom_erf_1f1b(acb_t res, const acb_t z, slong prec) { acb_t a, b, t, w; acb_init(a); acb_init(b); acb_init(t); acb_init(w); acb_set_ui(b, 3); acb_mul_2exp_si(b, b, -1); acb_mul(w, z, z, prec); acb_hypgeom_pfq_direct(t, a, 0, b, 1, w, -1, prec); acb_neg(w, w); acb_exp(w, w, prec); acb_mul(t, t, w, prec); acb_mul(t, t, z, prec); arb_const_sqrt_pi(acb_realref(w), prec); acb_div_arb(t, t, acb_realref(w), prec); acb_mul_2exp_si(res, t, 1); acb_clear(a); acb_clear(b); acb_clear(t); acb_clear(w); }
void acb_hypgeom_bessel_k_asymp(acb_t res, const acb_t nu, const acb_t z, slong prec) { acb_t t, a, b, w; acb_init(t); acb_init(a); acb_init(b); acb_init(w); acb_one(a); acb_mul_2exp_si(a, a, -1); acb_add(a, a, nu, prec); acb_mul_2exp_si(b, nu, 1); acb_add_ui(b, b, 1, prec); acb_mul_2exp_si(w, z, 1); acb_hypgeom_u_asymp(t, a, b, w, -1, prec); acb_neg(w, z); acb_exp(w, w, prec); acb_mul(t, t, w, prec); acb_mul_2exp_si(w, z, 1); acb_rsqrt(w, w, prec); acb_mul(res, t, w, prec); arb_const_sqrt_pi(acb_realref(w), prec); acb_mul_arb(res, res, acb_realref(w), prec); acb_clear(t); acb_clear(a); acb_clear(b); acb_clear(w); }
void acb_hypgeom_erf_asymp(acb_t res, const acb_t z, int complementary, slong prec, slong prec2) { acb_t a, t, u; acb_init(a); acb_init(t); acb_init(u); if (!acb_is_exact(z) && (arf_cmpabs_ui(arb_midref(acb_realref(z)), prec) < 0) && (arf_cmpabs_ui(arb_midref(acb_imagref(z)), prec) < 0)) { 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))); acb_hypgeom_erf_asymp(res, zmid, complementary, prec, prec2); 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); return; } acb_one(a); acb_mul_2exp_si(a, a, -1); acb_mul(t, z, z, prec2); acb_hypgeom_u_asymp(u, a, a, t, -1, prec2); acb_neg(t, t); acb_exp(t, t, prec2); acb_mul(u, u, t, prec2); arb_const_sqrt_pi(acb_realref(t), prec2); arb_zero(acb_imagref(t)); acb_mul(t, t, z, prec2); acb_div(u, u, t, prec2); /* branch cut term: -1 or 1 */ acb_csgn(acb_realref(t), z); arb_zero(acb_imagref(t)); if (complementary) { /* erfc(z) = 1 - erf(z) = u - (sgn - 1) */ acb_sub_ui(t, t, 1, prec); acb_sub(t, u, t, prec); } else { /* erf(z) = sgn - u */ acb_sub(t, t, u, prec); } if (arb_is_zero(acb_imagref(z))) { arb_zero(acb_imagref(t)); } else if (arb_is_zero(acb_realref(z))) { if (complementary) arb_one(acb_realref(t)); else arb_zero(acb_realref(t)); } acb_set(res, t); acb_clear(a); acb_clear(t); acb_clear(u); }
void acb_hypgeom_legendre_q(acb_t res, const acb_t n, const acb_t m, const acb_t z, int type, slong prec) { if (type == 0) { /* http://functions.wolfram.com/07.11.26.0033.01 */ /* todo: simplify the gamma quotients and the sqrt pi factor... */ acb_t a, b, c, z2, mn, nm, t, u; acb_init(a); acb_init(b); acb_init(c); acb_init(z2); acb_init(mn); acb_init(nm); acb_init(t); acb_init(u); acb_add(mn, m, n, prec); /* mn = m + n */ acb_sub(nm, n, m, prec); /* nm = n - m */ acb_mul(z2, z, z, prec); /* z2 = z^2 */ /* t = 2F1((1-m-n)/2, (n-m)/2+1, 3/2, z^2) */ acb_sub_ui(a, mn, 1, prec); acb_neg(a, a); acb_mul_2exp_si(a, a, -1); acb_mul_2exp_si(b, nm, -1); acb_add_ui(b, b, 1, prec); acb_set_ui(c, 3); acb_mul_2exp_si(c, c, -1); acb_hypgeom_2f1(t, a, b, c, z2, 0, prec); /* u = 2F1(-(m+n)/2, (n-m+1)/2, 1/2, z^2) */ acb_neg(a, mn); acb_mul_2exp_si(a, a, -1); acb_add_ui(b, nm, 1, prec); acb_mul_2exp_si(b, b, -1); acb_one(c); acb_mul_2exp_si(c, c, -1); acb_hypgeom_2f1(u, a, b, c, z2, 0, prec); /* a = cospi((m+n)/2) gamma((m+n)/2+1) rgamma((n-m+1)/2) z */ /* b = sinpi((m+n)/2) gamma((m+n+1)/2) rgamma((n-m)/2+1) / 2 */ acb_mul_2exp_si(a, mn, -1); acb_sin_cos_pi(b, a, a, prec); acb_mul_2exp_si(c, mn, -1); acb_add_ui(c, c, 1, prec); acb_gamma(c, c, prec); acb_mul(a, a, c, prec); acb_add_ui(c, nm, 1, prec); acb_mul_2exp_si(c, c, -1); acb_rgamma(c, c, prec); acb_mul(a, a, c, prec); acb_mul(a, a, z, prec); acb_add_ui(c, mn, 1, prec); acb_mul_2exp_si(c, c, -1); acb_gamma(c, c, prec); acb_mul(b, b, c, prec); acb_mul_2exp_si(c, nm, -1); acb_add_ui(c, c, 1, prec); acb_rgamma(c, c, prec); acb_mul(b, b, c, prec); acb_mul_2exp_si(b, b, -1); /* at - bu */ acb_mul(t, t, a, prec); acb_mul(u, u, b, prec); acb_sub(t, t, u, prec); /* prefactor sqrt(pi) 2^m (1-z^2)^(-m/2) */ if (!acb_is_zero(m)) { acb_sub_ui(u, z2, 1, prec); acb_neg(u, u); acb_neg(c, m); acb_mul_2exp_si(c, c, -1); acb_pow(u, u, c, prec); acb_set_ui(c, 2); acb_pow(c, c, m, prec); acb_mul(u, u, c, prec); acb_mul(t, t, u, prec); } arb_const_sqrt_pi(acb_realref(u), prec); acb_mul_arb(t, t, acb_realref(u), prec); acb_set(res, t); acb_clear(a); acb_clear(b); acb_clear(c); acb_clear(z2); acb_clear(mn); acb_clear(nm); acb_clear(t); acb_clear(u); } else if (type == 1) { if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), -2) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), -2) < 0) || !_acb_hypgeom_legendre_q_single_valid(z)) { _acb_hypgeom_legendre_q_double(res, n, m, z, prec); } else { _acb_hypgeom_legendre_q_single(res, n, m, z, prec); } } else { flint_printf("unsupported 'type' %d for legendre q\n", type); abort(); } }
void _acb_hypgeom_legendre_q_single(acb_t res, const acb_t n, const acb_t m, const acb_t z, slong prec) { acb_t a, b, c, z2, t, u; acb_init(a); acb_init(b); acb_init(c); acb_init(z2); acb_init(t); acb_init(u); /* invalid in (-1,0) */ if (!_acb_hypgeom_legendre_q_single_valid(z)) { acb_indeterminate(res); return; } acb_pow_si(z2, z, -2, prec); /* z2 = 1/z^2 */ /* t = 2F1r((m+n+1)/2, (m+n)/2+1, n+3/2, 1/z^2) */ acb_add(b, m, n, prec); acb_add_ui(a, b, 1, prec); acb_mul_2exp_si(a, a, -1); acb_mul_2exp_si(b, b, -1); acb_add_ui(b, b, 1, prec); acb_set_ui(c, 3); acb_mul_2exp_si(c, c, -1); acb_add(c, c, n, prec); acb_hypgeom_2f1(t, a, b, c, z2, 1, prec); /* prefactor sqrt(pi) 2^-n (z+1)^(m/2) (z-1)^(m/2) exp(i pi m) */ /* (1/2) gamma(m+n+1) z^(-m-n-1) */ if (!acb_is_zero(m)) { acb_add_ui(z2, z, 1, prec); acb_mul_2exp_si(c, m, -1); acb_pow(z2, z2, c, prec); acb_mul(t, t, z2, prec); acb_sub_ui(z2, z, 1, prec); acb_mul_2exp_si(c, m, -1); acb_pow(z2, z2, c, prec); acb_mul(t, t, z2, prec); acb_exp_pi_i(z2, m, prec); acb_mul(t, t, z2, prec); } acb_set_ui(z2, 2); acb_neg(c, n); acb_pow(z2, z2, c, prec); acb_mul(t, t, z2, prec); acb_add(c, m, n, prec); acb_add_ui(c, c, 1, prec); acb_gamma(z2, c, prec); acb_mul(t, t, z2, prec); acb_neg(c, c); acb_pow(z2, z, c, prec); acb_mul(t, t, z2, prec); acb_mul_2exp_si(t, t, -1); arb_const_sqrt_pi(acb_realref(u), prec); acb_mul_arb(t, t, acb_realref(u), prec); acb_set(res, t); acb_clear(a); acb_clear(b); acb_clear(c); acb_clear(z2); acb_clear(t); acb_clear(u); }