void arb_sub_fmpz(arb_t z, const arb_t x, const fmpz_t y, slong prec) { int inexact; inexact = arf_sub_fmpz(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), arb_radref(x), arb_midref(z), prec); else mag_set(arb_radref(z), arb_radref(x)); }
void acb_lambertw_principal_d(acb_t res, const acb_t z) { double za, zb, wa, wb, ewa, ewb, t, u, q, r; int k, maxk = 15; za = arf_get_d(arb_midref(acb_realref(z)), ARF_RND_DOWN); zb = arf_get_d(arb_midref(acb_imagref(z)), ARF_RND_DOWN); /* make sure we end up on the right branch */ if (za < -0.367 && zb > -1e-20 && zb <= 0.0 && arf_sgn(arb_midref(acb_imagref(z))) < 0) zb = -1e-20; wa = za; wb = zb; if (fabs(wa) > 2.0 || fabs(wb) > 2.0) { t = atan2(wb, wa); wa = 0.5 * log(wa * wa + wb * wb); wb = t; } else if (fabs(wa) > 0.25 || fabs(wb) > 0.25) { /* We have W(z) ~= -1 + (2(ez+1))^(1/2) near the branch point. Changing the exponent to 1/4 gives a much worse local guess which however does the job on a larger domain. */ wa *= 5.43656365691809; wb *= 5.43656365691809; wa += 2.0; t = atan2(wb, wa); r = pow(wa * wa + wb * wb, 0.125); wa = r * cos(0.25 * t); wb = r * sin(0.25 * t); wa -= 1.0; } for (k = 0; k < maxk; k++) { t = exp(wa); ewa = t * cos(wb); ewb = t * sin(wb); t = (ewa * wa - ewb * wb); q = t + ewa; t -= za; u = (ewb * wa + ewa * wb); r = u + ewb; u -= zb; ewa = q * t + r * u; ewb = q * u - r * t; r = 1.0 / (q * q + r * r); ewa *= r; ewb *= r; if ((ewa*ewa + ewb*ewb) < (wa*wa + wb*wb) * 1e-12) maxk = FLINT_MIN(maxk, k + 2); wa -= ewa; wb -= ewb; } acb_set_d_d(res, wa, wb); }
void arb_addmul_arf(arb_t z, const arb_t x, const arf_t y, slong prec) { mag_t ym; int inexact; if (arb_is_exact(x)) { inexact = arf_addmul(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), arb_radref(z), arb_midref(z), prec); } else if (ARB_IS_LAGOM(x) && ARF_IS_LAGOM(y) && ARB_IS_LAGOM(z)) { mag_fast_init_set_arf(ym, y); mag_fast_addmul(arb_radref(z), ym, arb_radref(x)); inexact = arf_addmul(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_fast_add_ulp(arb_radref(z), arb_radref(z), arb_midref(z), prec); } else { mag_init_set_arf(ym, y); mag_addmul(arb_radref(z), ym, arb_radref(x)); inexact = arf_addmul(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), arb_radref(z), arb_midref(z), prec); mag_clear(ym); } }
void arb_set_round_fmpz(arb_t y, const fmpz_t x, slong prec) { int inexact; inexact = arf_set_round_fmpz(arb_midref(y), x, prec, ARB_RND); if (inexact) arf_mag_set_ulp(arb_radref(y), arb_midref(y), prec); else mag_zero(arb_radref(y)); }
void arb_sub(arb_t z, const arb_t x, const arb_t y, slong prec) { int inexact; inexact = arf_sub(arb_midref(z), arb_midref(x), arb_midref(y), prec, ARB_RND); mag_add(arb_radref(z), arb_radref(x), arb_radref(y)); if (inexact) arf_mag_add_ulp(arb_radref(z), arb_radref(z), arb_midref(z), prec); }
static void _arb_arf_div_rounded_den(arb_t res, const arf_t x, const arf_t y, int yinexact, slong prec) { int inexact = arf_div(arb_midref(res), x, y, prec, ARB_RND); if (yinexact && !arf_is_special(arb_midref(res))) arf_mag_set_ulp(arb_radref(res), arb_midref(res), prec - 1); else if (inexact) arf_mag_set_ulp(arb_radref(res), arb_midref(res), prec); else mag_zero(arb_radref(res)); }
void acb_hurwitz_zeta(acb_t z, const acb_t s, const acb_t a, slong prec) { if (acb_is_one(a) && acb_is_int(s) && arf_cmpabs_2exp_si(arb_midref(acb_realref(s)), FLINT_BITS - 1) < 0) { acb_zeta_si(z, arf_get_si(arb_midref(acb_realref(s)), ARF_RND_DOWN), prec); return; } _acb_poly_zeta_cpx_series(z, s, a, 0, 1, prec); }
void acb_cot(acb_t r, const acb_t z, slong prec) { if (arb_is_zero(acb_imagref(z))) { arb_cot(acb_realref(r), acb_realref(z), prec); arb_zero(acb_imagref(r)); } else if (arb_is_zero(acb_realref(z))) { arb_coth(acb_imagref(r), acb_imagref(z), prec); arb_neg(acb_imagref(r), acb_imagref(r)); arb_zero(acb_realref(r)); } else { acb_t t; acb_init(t); if (arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 0) < 0) { acb_sin_cos(r, t, z, prec + 4); acb_div(r, t, r, prec); } else { acb_mul_2exp_si(t, z, 1); if (arf_sgn(arb_midref(acb_imagref(z))) > 0) { acb_mul_onei(t, t); acb_exp(t, t, prec + 4); acb_sub_ui(r, t, 1, prec + 4); acb_div(r, t, r, prec + 4); acb_mul_2exp_si(r, r, 1); acb_sub_ui(r, r, 1, prec); acb_mul_onei(r, r); } else { acb_div_onei(t, t); acb_exp(t, t, prec + 4); acb_sub_ui(r, t, 1, prec + 4); acb_div(r, t, r, prec + 4); acb_mul_2exp_si(r, r, 1); acb_sub_ui(r, r, 1, prec); acb_div_onei(r, r); } } acb_clear(t); } }
void arb_fmpz_div_fmpz(arb_t z, const fmpz_t x, const fmpz_t y, long prec) { int inexact; inexact = arf_fmpz_div_fmpz(arb_midref(z), x, y, prec, ARB_RND); if (inexact) arf_mag_set_ulp(arb_radref(z), arb_midref(z), prec); else mag_zero(arb_radref(z)); }
void arb_sin_cos_pi(arb_t s, arb_t c, const arb_t x, long prec) { arb_t t; arb_t u; fmpz_t v; if (arf_cmpabs_2exp_si(arb_midref(x), FLINT_MAX(65536, (4*prec))) > 0) { arf_zero(arb_midref(s)); mag_one(arb_radref(s)); arf_zero(arb_midref(c)); mag_one(arb_radref(c)); return; } arb_init(t); arb_init(u); fmpz_init(v); arb_mul_2exp_si(t, x, 1); arf_get_fmpz(v, arb_midref(t), ARF_RND_NEAR); arb_sub_fmpz(t, t, v, prec); arb_const_pi(u, prec); arb_mul(t, t, u, prec); arb_mul_2exp_si(t, t, -1); switch (fmpz_fdiv_ui(v, 4)) { case 0: arb_sin_cos(s, c, t, prec); break; case 1: arb_sin_cos(c, s, t, prec); arb_neg(c, c); break; case 2: arb_sin_cos(s, c, t, prec); arb_neg(s, s); arb_neg(c, c); break; default: arb_sin_cos(c, s, t, prec); arb_neg(s, s); break; } fmpz_clear(v); arb_clear(t); arb_clear(u); }
/* note: the tmp variable t should have zero radius */ static void acb_approx_div(acb_t z, const acb_t x, const acb_t y, acb_t t, slong prec) { arf_set(arb_midref(acb_realref(t)), arb_midref(acb_realref(y))); arf_set(arb_midref(acb_imagref(t)), arb_midref(acb_imagref(y))); acb_inv(t, t, prec); mag_zero(arb_radref(acb_realref(t))); mag_zero(arb_radref(acb_imagref(t))); acb_approx_mul(z, x, t, prec); }
void arb_sinc(arb_t z, const arb_t x, slong prec) { mag_t c, r; mag_init(c); mag_init(r); mag_set_ui_2exp_si(c, 5, -1); arb_get_mag_lower(r, x); if (mag_cmp(c, r) < 0) { /* x is not near the origin */ _arb_sinc_direct(z, x, prec); } else if (mag_cmp_2exp_si(arb_radref(x), 1) < 0) { /* determine error magnitude using the derivative bound */ if (arb_is_exact(x)) { mag_zero(c); } else { _arb_sinc_derivative_bound(r, x); mag_mul(c, arb_radref(x), r); } /* evaluate sinc at the midpoint of x */ if (arf_is_zero(arb_midref(x))) { arb_one(z); } else { arb_get_mid_arb(z, x); _arb_sinc_direct(z, z, prec); } /* add the error */ mag_add(arb_radref(z), arb_radref(z), c); } else { /* x has a large radius and includes points near the origin */ arf_zero(arb_midref(z)); mag_one(arb_radref(z)); } mag_clear(c); mag_clear(r); }
/* this can be improved */ static int use_recurrence(const acb_t n, const acb_t m, slong prec) { if (!acb_is_int(n) || !arb_is_nonnegative(acb_realref(n))) return 0; if (arf_cmpabs_ui(arb_midref(acb_realref(n)), prec) > 0) return 0; if (arf_cmpabs(arb_midref(acb_realref(n)), arb_midref(acb_realref(m))) >= 0) return 0; return 1; }
void acb_hypgeom_erf_asymp(acb_t res, const acb_t z, slong prec, slong prec2) { acb_t a, t, u; acb_init(a); acb_init(t); acb_init(u); 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); acb_const_pi(t, prec2); acb_sqrt(t, t, prec2); acb_mul(t, t, z, prec2); acb_div(u, u, t, prec2); /* branch cut term: -1 or 1 */ if (arb_contains_zero(acb_realref(z))) { arb_zero(acb_imagref(t)); arf_zero(arb_midref(acb_realref(t))); mag_one(arb_radref(acb_realref(t))); } else { acb_set_si(t, arf_sgn(arb_midref(acb_realref(z)))); } 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))) arb_zero(acb_realref(t)); acb_set(res, t); acb_clear(a); acb_clear(t); acb_clear(u); }
int arb_calc_newton_step(arb_t xnew, arb_calc_func_t func, void * param, const arb_t x, const arb_t conv_region, const arf_t conv_factor, slong prec) { mag_t err, v; arb_t t; arb_struct u[2]; int result; mag_init(err); mag_init(v); arb_init(t); arb_init(u + 0); arb_init(u + 1); mag_mul(err, arb_radref(x), arb_radref(x)); arf_get_mag(v, conv_factor); mag_mul(err, err, v); arf_set(arb_midref(t), arb_midref(x)); mag_zero(arb_radref(t)); func(u, t, param, 2, prec); arb_div(u, u, u + 1, prec); arb_sub(u, t, u, prec); mag_add(arb_radref(u), arb_radref(u), err); if (arb_contains(conv_region, u) && (mag_cmp(arb_radref(u), arb_radref(x)) < 0)) { arb_swap(xnew, u); result = ARB_CALC_SUCCESS; } else { arb_set(xnew, x); result = ARB_CALC_NO_CONVERGENCE; } arb_clear(t); arb_clear(u); arb_clear(u + 1); mag_clear(err); mag_clear(v); return result; }
void arb_root_ui_algebraic(arb_t res, const arb_t x, ulong k, slong prec) { mag_t r, msubr, m1k, t; if (arb_is_exact(x)) { arb_root_arf(res, arb_midref(x), k, prec); return; } if (!arb_is_nonnegative(x)) { arb_indeterminate(res); return; } mag_init(r); mag_init(msubr); mag_init(m1k); mag_init(t); /* x = [m-r, m+r] */ mag_set(r, arb_radref(x)); /* m - r */ arb_get_mag_lower(msubr, x); /* m^(1/k) */ arb_root_arf(res, arb_midref(x), k, prec); /* bound for m^(1/k) */ arb_get_mag(m1k, res); /* C = min(1, log(1+r/(m-r))/k) */ mag_div(t, r, msubr); mag_log1p(t, t); mag_div_ui(t, t, k); if (mag_cmp_2exp_si(t, 0) > 0) mag_one(t); /* C m^(1/k) */ mag_mul(t, m1k, t); mag_add(arb_radref(res), arb_radref(res), t); mag_clear(r); mag_clear(msubr); mag_clear(m1k); mag_clear(t); }
void arb_pow(arb_t z, const arb_t x, const arb_t y, long prec) { if (arb_is_zero(y)) { arb_one(z); return; } if (arb_is_exact(y) && !arf_is_special(arb_midref(x))) { const arf_struct * ymid = arb_midref(y); /* small half-integer or integer */ if (arf_cmpabs_2exp_si(ymid, BINEXP_LIMIT) < 0 && arf_is_int_2exp_si(ymid, -1)) { fmpz_t e; fmpz_init(e); if (arf_is_int(ymid)) { arf_get_fmpz_fixed_si(e, ymid, 0); arb_pow_fmpz_binexp(z, x, e, prec); } else { arf_get_fmpz_fixed_si(e, ymid, -1); arb_sqrt(z, x, prec + fmpz_bits(e)); arb_pow_fmpz_binexp(z, z, e, prec); } fmpz_clear(e); return; } else if (arf_is_int(ymid) && arf_sgn(arb_midref(x)) < 0) { /* use (-x)^n = (-1)^n * x^n to avoid NaNs at least at high enough precision */ int odd = !arf_is_int_2exp_si(ymid, 1); _arb_pow_exp(z, x, 1, y, prec); if (odd) arb_neg(z, z); return; } } _arb_pow_exp(z, x, 0, y, prec); }
/* this can be improved */ static int use_recurrence(const acb_t n, const acb_t a, const acb_t b, slong prec) { if (!acb_is_int(n) || !arb_is_nonnegative(acb_realref(n))) return 0; if (arf_cmpabs_ui(arb_midref(acb_realref(n)), prec) > 0) return 0; if (arb_is_nonnegative(acb_realref(a)) || arf_get_d(arb_midref(acb_realref(a)), ARF_RND_DOWN) > -0.9) return 0; return 1; }
int _arb_poly_newton_step(arb_t xnew, arb_srcptr poly, long len, const arb_t x, const arb_t convergence_interval, const arf_t convergence_factor, long prec) { arf_t err; arb_t t, u, v; int result; arf_init(err); arb_init(t); arb_init(u); arb_init(v); arf_set_mag(err, arb_radref(x)); arf_mul(err, err, err, MAG_BITS, ARF_RND_UP); arf_mul(err, err, convergence_factor, MAG_BITS, ARF_RND_UP); arf_set(arb_midref(t), arb_midref(x)); mag_zero(arb_radref(t)); _arb_poly_evaluate2(u, v, poly, len, t, prec); arb_div(u, u, v, prec); arb_sub(u, t, u, prec); arb_add_error_arf(u, err); if (arb_contains(convergence_interval, u) && (mag_cmp(arb_radref(u), arb_radref(x)) < 0)) { arb_swap(xnew, u); result = 1; } else { arb_set(xnew, x); result = 0; } arb_clear(t); arb_clear(u); arb_clear(v); arf_clear(err); return result; }
void arb_fprint(FILE * file, const arb_t x) { arf_fprint(file, arb_midref(x)); flint_fprintf(file, " +/- "); mag_fprint(file, arb_radref(x)); }
void acb_hypgeom_laguerre_l(acb_t res, const acb_t n, const acb_t m, const acb_t z, slong prec) { acb_t t, u, v; if (use_recurrence(n, m, prec)) { acb_hypgeom_laguerre_l_ui_recurrence(res, arf_get_si(arb_midref(acb_realref(n)), ARF_RND_DOWN), m, z, prec); return; } /* todo: should be a test of whether n contains any negative integer */ if (acb_contains_int(n) && !arb_is_nonnegative(acb_realref(n))) { acb_indeterminate(res); return; } acb_init(t); acb_init(u); acb_init(v); acb_neg(t, n); acb_add_ui(u, m, 1, prec); acb_hypgeom_m(t, t, u, z, 1, prec); acb_add_ui(u, n, 1, prec); acb_rising(u, u, m, prec); acb_mul(res, t, u, prec); acb_clear(t); acb_clear(u); acb_clear(v); }
void arb_fprintd(FILE * file, const arb_t x, slong digits) { arf_fprintd(file, arb_midref(x), FLINT_MAX(digits, 1)); flint_fprintf(file, " +/- "); mag_fprintd(file, arb_radref(x), 5); }
void arb_log1p(arb_t r, const arb_t z, slong prec) { slong magz; if (arb_is_zero(z)) { arb_zero(r); return; } magz = arf_abs_bound_lt_2exp_si(arb_midref(z)); if (magz < -prec) { arb_log1p_tiny(r, z, prec); } else { if (magz < 0) arb_add_ui(r, z, 1, prec + (-magz) + 4); else arb_add_ui(r, z, 1, prec + 4); arb_log(r, r, prec); } }
void arb_sqrt1pm1(arb_t r, const arb_t z, slong prec) { slong magz, wp; if (arb_is_zero(z)) { arb_zero(r); return; } magz = arf_abs_bound_lt_2exp_si(arb_midref(z)); if (magz < -prec) { arb_sqrt1pm1_tiny(r, z, prec); } else { if (magz < 0) wp = prec + (-magz) + 4; else wp = prec + 4; arb_add_ui(r, z, 1, wp); arb_sqrt(r, r, wp); arb_sub_ui(r, r, 1, wp); } }
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_polygamma(acb_t res, const acb_t s, const acb_t z, long prec) { if (acb_is_zero(s)) { acb_digamma(res, z, prec); } else if (acb_is_int(s) && arb_is_positive(acb_realref(s))) { acb_t t, u; acb_init(t); acb_init(u); acb_add_ui(t, s, 1, prec); acb_gamma(u, t, prec); acb_hurwitz_zeta(t, t, z, prec); if (arf_is_int_2exp_si(arb_midref(acb_realref(s)), 1)) acb_neg(t, t); acb_mul(res, t, u, prec); acb_clear(t); acb_clear(u); } else { acb_t t, u; acb_struct v[2]; acb_init(t); acb_init(u); acb_init(v); acb_init(v + 1); /* u = psi(-s) + gamma */ acb_neg(t, s); acb_digamma(u, t, prec); arb_const_euler(acb_realref(v), prec); arb_add(acb_realref(u), acb_realref(u), acb_realref(v), prec); acb_add_ui(t, s, 1, prec); _acb_poly_zeta_cpx_series(v, t, z, 0, 2, prec); acb_addmul(v + 1, v, u, prec); acb_neg(t, s); acb_rgamma(u, t, prec); acb_mul(res, v + 1, u, prec); acb_clear(v); acb_clear(v + 1); acb_clear(t); acb_clear(u); } }
static void arb_supremum(arf_t res, const arb_t x) { if (arf_is_nan(arb_midref(x))) { arf_nan(res); } else if (mag_is_inf(arb_radref(x))) { arf_pos_inf(res); } else { arf_set_mag(res, arb_radref(x)); arf_add(res, res, arb_midref(x), ARF_PREC_EXACT, ARF_RND_CEIL); } }
void arb_get_lbound_arf(arf_t u, const arb_t x, long prec) { arf_t t; arf_init_set_mag_shallow(t, arb_radref(x)); arf_sub(u, arb_midref(x), t, prec, ARF_RND_FLOOR); }
static void arb_infimum(arf_t res, const arb_t x) { if (arf_is_nan(arb_midref(x))) { arf_nan(res); } else if (mag_is_inf(arb_radref(x))) { arf_neg_inf(res); } else { arf_set_mag(res, arb_radref(x)); arf_sub(res, arb_midref(x), res, ARF_PREC_EXACT, ARF_RND_FLOOR); } }
static __inline__ void arb_nonnegative_part(arb_t z, const arb_t x, long prec) { if (arb_contains_negative(x)) { arf_t t; arf_init(t); arf_set_mag(t, arb_radref(x)); arf_add(arb_midref(z), arb_midref(x), t, MAG_BITS, ARF_RND_CEIL); if (arf_sgn(arb_midref(z)) <= 0) { mag_zero(arb_radref(z)); } else { arf_mul_2exp_si(arb_midref(z), arb_midref(z), -1); arf_get_mag(arb_radref(z), arb_midref(z)); /* XXX: needed since arf_get_mag is inexact */ arf_set_mag(arb_midref(z), arb_radref(z)); } arf_clear(t); } else { arb_set(z, x); } }