void mag_exp_tail(mag_t z, const mag_t x, ulong N) { if (N == 0 || mag_is_inf(x)) { mag_exp(z, x); } else if (mag_is_zero(x)) { mag_zero(z); } else { mag_t t; mag_init(t); mag_set_ui_2exp_si(t, N, -1); /* bound by geometric series when N >= 2*x <=> N/2 >= x */ if (mag_cmp(t, x) >= 0) { /* 2 c^N / N! */ mag_pow_ui(t, x, N); mag_rfac_ui(z, N); mag_mul(z, z, t); mag_mul_2exp_si(z, z, 1); } else { mag_exp(z, x); } mag_clear(t); } }
void mag_geom_series(mag_t res, const mag_t x, ulong n) { if (mag_is_zero(x)) { if (n == 0) mag_one(res); else mag_zero(res); } else if (mag_is_inf(x)) { mag_inf(res); } else { mag_t t; mag_init(t); mag_one(t); mag_sub_lower(t, t, x); if (mag_is_zero(t)) { mag_inf(res); } else { mag_pow_ui(res, x, n); mag_div(res, res, t); } mag_clear(t); } }
void arb_div(arb_t z, const arb_t x, const arb_t y, long prec) { mag_t zr, xm, ym, yl, yw; int inexact; if (arb_is_exact(y)) { arb_div_arf(z, x, arb_midref(y), prec); } else if (mag_is_inf(arb_radref(x)) || mag_is_inf(arb_radref(y))) { arf_div(arb_midref(z), arb_midref(x), arb_midref(y), prec, ARB_RND); mag_inf(arb_radref(z)); } else { mag_init_set_arf(xm, arb_midref(x)); mag_init_set_arf(ym, arb_midref(y)); mag_init(zr); mag_init(yl); mag_init(yw); /* (|x|*yrad + |y|*xrad)/(y*(|y|-yrad)) */ mag_mul(zr, xm, arb_radref(y)); mag_addmul(zr, ym, arb_radref(x)); arb_get_mag_lower(yw, y); arf_get_mag_lower(yl, arb_midref(y)); mag_mul_lower(yl, yl, yw); mag_div(zr, zr, yl); inexact = arf_div(arb_midref(z), arb_midref(x), arb_midref(y), prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), zr, arb_midref(z), prec); else mag_swap(arb_radref(z), zr); mag_clear(xm); mag_clear(ym); mag_clear(zr); mag_clear(yl); mag_clear(yw); } }
void mag_expinv(mag_t res, const mag_t x) { if (mag_is_zero(x)) { mag_one(res); } else if (mag_is_inf(x)) { mag_zero(res); } else if (fmpz_sgn(MAG_EXPREF(x)) <= 0) { mag_one(res); } else if (fmpz_cmp_ui(MAG_EXPREF(x), 2 * MAG_BITS) > 0) { fmpz_t t; fmpz_init(t); /* If x > 2^60, exp(-x) < 2^(-2^60 / log(2)) */ /* -1/log(2) < -369/256 */ fmpz_set_si(t, -369); fmpz_mul_2exp(t, t, 2 * MAG_BITS - 8); mag_one(res); mag_mul_2exp_fmpz(res, res, t); fmpz_clear(t); } else { fmpz_t t; slong e = MAG_EXP(x); fmpz_init(t); fmpz_set_ui(t, MAG_MAN(x)); if (e >= MAG_BITS) fmpz_mul_2exp(t, t, e - MAG_BITS); else fmpz_tdiv_q_2exp(t, t, MAG_BITS - e); /* upper bound for 1/e */ mag_set_ui_2exp_si(res, 395007543, -30); mag_pow_fmpz(res, res, t); fmpz_clear(t); } }
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 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_div_arf(arb_t z, const arb_t x, const arf_t y, long prec) { mag_t zr, ym; int inexact; if (arf_is_zero(y)) { arb_zero_pm_inf(z); } else if (arb_is_exact(x)) { inexact = arf_div(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_set_ulp(arb_radref(z), arb_midref(z), prec); else mag_zero(arb_radref(z)); } else if (mag_is_inf(arb_radref(x))) { arf_div(arb_midref(z), arb_midref(x), y, prec, ARB_RND); mag_inf(arb_radref(z)); } else { mag_init(ym); mag_init(zr); arf_get_mag_lower(ym, y); mag_div(zr, arb_radref(x), ym); inexact = arf_div(arb_midref(z), arb_midref(x), y, prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), zr, arb_midref(z), prec); else mag_swap(arb_radref(z), zr); mag_clear(ym); mag_clear(zr); } }
double mag_get_d(const mag_t z) { if (mag_is_zero(z)) { return 0.0; } else if (mag_is_inf(z)) { return D_INF; } else if (MAG_EXP(z) < -1000 || MAG_EXP(z) > 1000) { if (fmpz_sgn(MAG_EXPREF(z)) < 0) return ldexp(1.0, -1000); else return D_INF; } else { return ldexp(MAG_MAN(z), MAG_EXP(z) - MAG_BITS); } }
void mag_pow_ui_lower(mag_t z, const mag_t x, ulong e) { if (e <= 2) { if (e == 0) mag_one(z); else if (e == 1) mag_set(z, x); else mag_mul_lower(z, x, x); } else if (mag_is_inf(x)) { mag_inf(z); } else { mag_t y; int i, bits; mag_init_set(y, x); bits = FLINT_BIT_COUNT(e); for (i = bits - 2; i >= 0; i--) { mag_mul_lower(y, y, y); if (e & (1UL << i)) mag_mul_lower(y, y, x); } mag_swap(z, y); mag_clear(y); } }
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_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); }