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_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 _acb_poly_add(acb_ptr res, acb_srcptr poly1, long len1, acb_srcptr poly2, long len2, long prec) { long i, min = FLINT_MIN(len1, len2); for (i = 0; i < min; i++) acb_add(res + i, poly1 + i, poly2 + i, prec); for (i = min; i < len1; i++) acb_set_round(res + i, poly1 + i, prec); for (i = min; i < len2; i++) acb_set_round(res + i, poly2 + i, prec); }
void _acb_poly_compose(acb_ptr res, acb_srcptr poly1, slong len1, acb_srcptr poly2, slong len2, slong prec) { if (len1 == 1) { acb_set_round(res, poly1, prec); } else if (len2 == 1) { _acb_poly_evaluate(res, poly1, len1, poly2, prec); } else if (_acb_vec_is_zero(poly2 + 1, len2 - 2)) { _acb_poly_compose_axnc(res, poly1, len1, poly2, poly2 + len2 - 1, len2 - 1, prec); } else if (len1 <= 7) { _acb_poly_compose_horner(res, poly1, len1, poly2, len2, prec); } else { _acb_poly_compose_divconquer(res, poly1, len1, poly2, len2, prec); } }
void acb_dot_simple(acb_t res, const acb_t initial, int subtract, acb_srcptr x, slong xstep, acb_srcptr y, slong ystep, slong len, slong prec) { slong i; if (len <= 0) { if (initial == NULL) acb_zero(res); else acb_set_round(res, initial, prec); return; } if (initial == NULL) { acb_mul(res, x, y, prec); } else { if (subtract) acb_neg(res, initial); else acb_set(res, initial); acb_addmul(res, x, y, prec); } for (i = 1; i < len; i++) acb_addmul(res, x + i * xstep, y + i * ystep, prec); if (subtract) acb_neg(res, res); }
void _acb_poly_evaluate_rectangular(acb_t y, acb_srcptr poly, slong len, const acb_t x, slong prec) { slong i, j, m, r; acb_ptr xs; acb_t s, t, c; if (len < 3) { if (len == 0) { acb_zero(y); } else if (len == 1) { acb_set_round(y, poly + 0, prec); } else if (len == 2) { acb_mul(y, x, poly + 1, prec); acb_add(y, y, poly + 0, prec); } return; } m = n_sqrt(len) + 1; r = (len + m - 1) / m; xs = _acb_vec_init(m + 1); acb_init(s); acb_init(t); acb_init(c); _acb_vec_set_powers(xs, x, m + 1, prec); acb_set(y, poly + (r - 1) * m); for (j = 1; (r - 1) * m + j < len; j++) acb_addmul(y, xs + j, poly + (r - 1) * m + j, prec); for (i = r - 2; i >= 0; i--) { acb_set(s, poly + i * m); for (j = 1; j < m; j++) acb_addmul(s, xs + j, poly + i * m + j, prec); acb_mul(y, y, xs + m, prec); acb_add(y, y, s, prec); } _acb_vec_clear(xs, m + 1); acb_clear(s); acb_clear(t); acb_clear(c); }
void _acb_poly_compose_series(acb_ptr res, acb_srcptr poly1, slong len1, acb_srcptr poly2, slong len2, slong n, slong prec) { if (len2 == 1) { acb_set_round(res, poly1, prec); _acb_vec_zero(res + 1, n - 1); } else if (_acb_vec_is_zero(poly2 + 1, len2 - 2)) /* poly2 is a monomial */ { slong i, j; acb_t t; acb_init(t); acb_set(t, poly2 + len2 - 1); acb_set_round(res, poly1, prec); for (i = 1, j = len2 - 1; i < len1 && j < n; i++, j += len2 - 1) { acb_mul(res + j, poly1 + i, t, prec); if (i + 1 < len1 && j + len2 - 1 < n) acb_mul(t, t, poly2 + len2 - 1, prec); } if (len2 != 2) for (i = 1; i < n; i++) if (i % (len2 - 1) != 0) acb_zero(res + i); acb_clear(t); } else if (len1 < 6 || n < 6) { _acb_poly_compose_series_horner(res, poly1, len1, poly2, len2, n, prec); } else { _acb_poly_compose_series_brent_kung(res, poly1, len1, poly2, len2, n, prec); } }
void acb_mat_det(acb_t det, const acb_mat_t A, slong prec) { slong n; if (!acb_mat_is_square(A)) { flint_printf("acb_mat_det: a square matrix is required!\n"); flint_abort(); } n = acb_mat_nrows(A); if (n == 0) { acb_one(det); } else if (n == 1) { acb_set_round(det, acb_mat_entry(A, 0, 0), prec); } else if (n == 2) { _acb_mat_det_cofactor_2x2(det, A, prec); } else if (!acb_mat_is_finite(A)) { acb_indeterminate(det); } else if (acb_mat_is_tril(A) || acb_mat_is_triu(A)) { acb_mat_diag_prod(det, A, prec); } else if (n == 3) { _acb_mat_det_cofactor_3x3(det, A, prec); /* note: 4x4 performs worse than LU */ } else { if (n <= 14 || prec > 10.0 * n) acb_mat_det_lu(det, A, prec); else acb_mat_det_precond(det, A, prec); } }
void acb_hypgeom_m(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, slong prec) { int asymp, kummer; slong wp; acb_hypgeom_m_choose(&asymp, &kummer, &wp, a, b, z, regularized, prec); if (asymp) { acb_hypgeom_m_asymp(res, a, b, z, regularized, wp); } else { _acb_hypgeom_m_1f1(res, a, b, z, regularized, wp, FLINT_MIN(wp, prec), kummer); } acb_set_round(res, res, prec); }
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); }
void _acb_mat_diag_prod(acb_t res, const acb_mat_t A, slong a, slong b, slong prec) { if (b - a == 0) acb_one(res); else if (b - a == 1) acb_set_round(res, acb_mat_entry(A, a, a), prec); else if (b - a == 2) acb_mul(res, acb_mat_entry(A, a, a), acb_mat_entry(A, a + 1, a + 1), prec); else if (b - a == 3) { acb_mul(res, acb_mat_entry(A, a, a), acb_mat_entry(A, a + 1, a + 1), prec); acb_mul(res, res, acb_mat_entry(A, a + 2, a + 2), prec); } else { acb_t t; acb_init(t); _acb_mat_diag_prod(t, A, a, a + (b - a) / 2, prec); _acb_mat_diag_prod(res, A, a + (b - a) / 2, b, prec); acb_mul(res, res, t, prec); acb_clear(t); } }
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); }
void acb_gamma_stirling_eval(acb_t s, const acb_t z, long nterms, int digamma, long prec) { acb_t t, logz, zinv, zinv2; arb_t b; mag_t err; long k, term_prec; double z_mag, term_mag; acb_init(t); acb_init(logz); acb_init(zinv); acb_init(zinv2); arb_init(b); acb_log(logz, z, prec); acb_inv(zinv, z, prec); nterms = FLINT_MAX(nterms, 1); acb_zero(s); if (nterms > 1) { acb_mul(zinv2, zinv, zinv, prec); z_mag = arf_get_d(arb_midref(acb_realref(logz)), ARF_RND_UP) * 1.44269504088896; for (k = nterms - 1; k >= 1; k--) { term_mag = bernoulli_bound_2exp_si(2 * k); term_mag -= (2 * k - 1) * z_mag; term_prec = prec + term_mag; term_prec = FLINT_MIN(term_prec, prec); term_prec = FLINT_MAX(term_prec, 10); arb_gamma_stirling_coeff(b, k, digamma, term_prec); if (prec > 2000) { acb_set_round(t, zinv2, term_prec); acb_mul(s, s, t, term_prec); } else acb_mul(s, s, zinv2, term_prec); arb_add(acb_realref(s), acb_realref(s), b, term_prec); } if (digamma) acb_mul(s, s, zinv2, prec); else acb_mul(s, s, zinv, prec); } /* remainder bound */ mag_init(err); acb_gamma_stirling_bound(err, z, digamma ? 1 : 0, 1, nterms); mag_add(arb_radref(acb_realref(s)), arb_radref(acb_realref(s)), err); mag_add(arb_radref(acb_imagref(s)), arb_radref(acb_imagref(s)), err); mag_clear(err); if (digamma) { acb_neg(s, s); acb_mul_2exp_si(zinv, zinv, -1); acb_sub(s, s, zinv, prec); acb_add(s, s, logz, prec); } else { /* (z-0.5)*log(z) - z + log(2*pi)/2 */ arb_one(b); arb_mul_2exp_si(b, b, -1); arb_set(acb_imagref(t), acb_imagref(z)); arb_sub(acb_realref(t), acb_realref(z), b, prec); acb_mul(t, logz, t, prec); acb_add(s, s, t, prec); acb_sub(s, s, z, prec); arb_const_log_sqrt2pi(b, prec); arb_add(acb_realref(s), acb_realref(s), b, prec); } acb_clear(t); acb_clear(logz); acb_clear(zinv); acb_clear(zinv2); arb_clear(b); }
int acb_mat_eig_simple_rump(acb_ptr E, acb_mat_t L, acb_mat_t R, const acb_mat_t A, acb_srcptr E_approx, const acb_mat_t R_approx, slong prec) { slong i, j, n; acb_mat_t X, R2; int result; n = acb_mat_nrows(A); if (n == 0) return 1; if (n == 1) { acb_set_round(E, acb_mat_entry(A, 0, 0), prec); if (L != NULL) acb_one(acb_mat_entry(L, 0, 0)); if (R != NULL) acb_one(acb_mat_entry(R, 0, 0)); return 1; } acb_mat_init(X, n, 1); acb_mat_init(R2, n, n); result = 1; for (i = 0; i < n && result; i++) { for (j = 0; j < n; j++) acb_set(acb_mat_entry(X, j, 0), acb_mat_entry(R_approx, j, i)); acb_mat_eig_enclosure_rump(E + i, NULL, X, A, E_approx + i, X, prec); if (!acb_is_finite(E + i)) result = 0; for (j = 0; j < i; j++) if (acb_overlaps(E + i, E + j)) result = 0; for (j = 0; j < n; j++) acb_set(acb_mat_entry(R2, j, i), acb_mat_entry(X, j, 0)); } if (R != NULL) { if (result) acb_mat_set(R, R2); else acb_mat_indeterminate(R); } if (L != NULL) { if (!result || !acb_mat_inv(L, R, prec)) acb_mat_indeterminate(L); } if (!result) _acb_vec_indeterminate(E, n); acb_mat_clear(X); acb_mat_clear(R2); return result; }
void acb_pow_fmpz_binexp(acb_t y, const acb_t b, const fmpz_t e, long prec) { long i, wp, bits; if (-2L <= *e && *e <= 4L) { if (*e == 0L) { acb_one(y); } else if (*e == 1L) { acb_set_round(y, b, prec); } else if (*e == -1L) { acb_inv(y, b, prec); } else if (*e == 2L) { acb_mul(y, b, b, prec); } else if (*e == 3L) { acb_cube(y, b, prec); } else if (*e == 4L) { acb_mul(y, b, b, prec); acb_mul(y, y, y, prec); } else { acb_inv(y, b, prec); acb_mul(y, y, y, prec); } return; } if (fmpz_sgn(e) < 0) { fmpz_t f; fmpz_init(f); fmpz_neg(f, e); acb_pow_fmpz_binexp(y, b, f, prec + 2); acb_inv(y, y, prec); fmpz_clear(f); return; } if (!COEFF_IS_MPZ(*e) && ((*e) % 3 == 0)) { fmpz e3 = (*e) / 3; acb_pow_fmpz_binexp(y, b, &e3, prec); acb_cube(y, y, prec); return; } if (y == b) { acb_t t; acb_init(t); acb_set(t, b); acb_pow_fmpz_binexp(y, t, e, prec); acb_clear(t); return; } acb_set(y, b); bits = fmpz_bits(e); wp = ARF_PREC_ADD(prec, bits); for (i = bits - 2; i >= 0; i--) { acb_mul(y, y, y, wp); if (fmpz_tstbit(e, i)) acb_mul(y, y, b, wp); } }
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); } }
void acb_modular_theta_const_sum_rs(acb_t theta2, acb_t theta3, acb_t theta4, const acb_t q, long N, long prec) { long * tab; long k, term_prec, i, e, eprev; long M, m2, m3, num_square, num_trigonal; double log2q_approx, log2term_approx; acb_ptr qpow; acb_t tmp1, tmp2; mag_t qmag; mag_init(qmag); acb_get_mag(qmag, q); log2q_approx = mag_get_log2_d_approx(qmag); mag_clear(qmag); acb_init(tmp1); acb_init(tmp2); /* choose rectangular splitting parameters */ m2 = acb_modular_rs_optimal_m(trigonal_best_m, trigonal_best_m_residues, N); m3 = acb_modular_rs_optimal_m(square_best_m, square_best_m_residues, N); M = FLINT_MAX(m2, m3) + 1; /* build addition sequence */ tab = flint_calloc(M, sizeof(long)); for (k = 0; k*(k+1) < N; k++) tab[(k*(k+1)) % m2] = -1; num_trigonal = k; for (k = 0; k*k < N; k++) tab[(k*k) % m3] = -1; num_square = k; tab[m2] = -1; tab[m3] = -1; /* compute powers in addition sequence */ qpow = _acb_vec_init(M); acb_modular_fill_addseq(tab, M); for (k = 0; k < M; k++) { if (k == 0) { acb_one(qpow + k); } else if (k == 1) { acb_set_round(qpow + k, q, prec); } else if (tab[k] != 0) { log2term_approx = k * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); acb_mul_approx(qpow + k, tmp1, tmp2, qpow + tab[k], qpow + k - tab[k], term_prec, prec); } } /* compute theta2 */ acb_zero(theta2); term_prec = prec; for (k = num_trigonal - 1; k >= 0; k--) { e = k * (k + 1); /* exponent */ eprev = (k + 1) * (k + 2); log2term_approx = e * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); /* giant steps */ for (i = e / m2; i < eprev / m2; i++) { if (!acb_is_zero(theta2)) acb_mul_approx(theta2, tmp1, tmp2, theta2, qpow + m2, term_prec, prec); } acb_add(theta2, theta2, qpow + (e % m2), prec); } acb_mul_2exp_si(theta2, theta2, 1); /* compute theta3, theta4 */ acb_zero(theta3); acb_zero(theta4); term_prec = prec; for (k = num_square - 1; k >= 0; k--) { e = k * k; /* exponent */ eprev = (k + 1) * (k + 1); log2term_approx = e * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); /* giant steps */ for (i = e / m3; i < eprev / m3; i++) { if (!acb_is_zero(theta3)) acb_mul_approx(theta3, tmp1, tmp2, theta3, qpow + m3, term_prec, prec); if (!acb_is_zero(theta4)) acb_mul_approx(theta4, tmp1, tmp2, theta4, qpow + m3, term_prec, prec); } if (k == 0) { acb_mul_2exp_si(theta3, theta3, 1); acb_mul_2exp_si(theta4, theta4, 1); } acb_add(theta3, theta3, qpow + (e % m3), prec); if (k % 2 == 0) acb_add(theta4, theta4, qpow + (e % m3), prec); else acb_sub(theta4, theta4, qpow + (e % m3), prec); } acb_clear(tmp1); acb_clear(tmp2); _acb_vec_clear(qpow, M); flint_free(tab); }
void acb_modular_theta_const_sum_basecase(acb_t theta2, acb_t theta3, acb_t theta4, const acb_t q, slong N, slong prec) { slong * tab; slong k, term_prec; double log2q_approx, log2term_approx; mag_t qmag; acb_ptr qpow; acb_t s1, s2, s3, t1, t2; if (N < 2) { acb_set_ui(theta2, 2 * (N > 0)); acb_set_ui(theta3, N > 0); acb_set(theta4, theta3); return; } if (N < 25) { acb_t q1, q2, q4, q8, q16; acb_init(q1); acb_init(q2); acb_init(q4); acb_init(q8); acb_init(q16); acb_set_round(q1, q, prec); if (N > 2) acb_mul(q2, q1, q1, prec); if (N > 4) acb_mul(q4, q2, q2, prec); if (N > 9) acb_mul(q8, q4, q4, prec); if (N > 16) acb_mul(q16, q8, q8, prec); /* theta2 = 2 + 2q^2 + 2q^4 [2q^2 + 2q^8 + 2q^16] */ if (N > 6) { if (N > 12) { acb_add(theta2, q2, q8, prec); if (N > 20) acb_add(theta2, theta2, q16, prec); acb_mul(theta2, theta2, q4, prec); } else { acb_mul(theta2, q2, q4, prec); } acb_add(theta2, theta2, q2, prec); acb_add_ui(theta2, theta2, 1, prec); } else if (N > 2) acb_add_ui(theta2, q2, 1, prec); else acb_one(theta2); acb_mul_2exp_si(theta2, theta2, 1); /* theta3 = [1 + 2q^4 + 2q^16] + [2q + 2q^9] */ /* theta4 = [1 + 2q^4 + 2q^16] - [2q + 2q^9] */ if (N > 4) { if (N > 16) acb_add(q4, q4, q16, prec); acb_mul_2exp_si(q4, q4, 1); acb_add_ui(q4, q4, 1, prec); if (N > 9) acb_addmul(q1, q1, q8, prec); acb_mul_2exp_si(q1, q1, 1); acb_add(theta3, q4, q1, prec); acb_sub(theta4, q4, q1, prec); } else { acb_mul_2exp_si(q1, q1, 1); acb_add_ui(theta3, q1, 1, prec); acb_sub_ui(theta4, q1, 1, prec); acb_neg(theta4, theta4); } acb_clear(q1); acb_clear(q2); acb_clear(q4); acb_clear(q8); acb_clear(q16); return; } mag_init(qmag); acb_init(s1); acb_init(s2); acb_init(s3); acb_init(t1); acb_init(t2); tab = flint_calloc(N, sizeof(slong)); qpow = _acb_vec_init(N); for (k = 0; k*(k+1) < N; k++) tab[k*(k+1)] = -1; for (k = 0; 4*k*k < N; k++) tab[4*k*k] = -1; for (k = 0; 4*k*(k+1) + 1 < N; k++) tab[4*k*(k+1)] = -1; if (N > 0) tab[0] = 0; if (N > 1) tab[1] = 1; acb_modular_fill_addseq(tab, N); acb_get_mag(qmag, q); log2q_approx = mag_get_log2_d_approx(qmag); for (k = 0; k < N; k++) { if (k == 0) { acb_one(qpow + k); } else if (k == 1) { acb_set_round(qpow + k, q, prec); } else if (tab[k] != 0) { log2term_approx = k * log2q_approx; term_prec = FLINT_MIN(FLINT_MAX(prec + log2term_approx + 16.0, 16.0), prec); acb_mul_approx(qpow + k, t1, t2, qpow + tab[k], qpow + k - tab[k], term_prec, prec); } } for (k = 0; k*(k+1) < N; k++) acb_add(s1, s1, qpow + k*(k+1), prec); for (k = 1; 4*k*k < N; k++) acb_add(s2, s2, qpow + 4*k*k, prec); for (k = 0; 4*k*(k+1) + 1 < N; k++) acb_add(s3, s3, qpow + 4*k*(k+1), prec); /* theta2 = 2 + 2q^2 + 2q^6 + 2q^12 + 2q^20 + 2q^30 + ... theta3 = 1 + 2 (q^4 + q^16 + ...) + 2q (1 + q^8 + q^24 + ...) theta4 = 1 + 2 (q^4 + q^16 + ...) - 2q (1 + q^8 + q^24 + ...) */ acb_mul(s3, s3, q, prec); acb_mul_2exp_si(s3, s3, 1); acb_mul_2exp_si(s2, s2, 1); acb_add(theta3, s2, s3, prec); acb_sub(theta4, s2, s3, prec); acb_add_ui(theta3, theta3, 1, prec); acb_add_ui(theta4, theta4, 1, prec); acb_mul_2exp_si(theta2, s1, 1); _acb_vec_clear(qpow, N); flint_free(tab); acb_clear(s1); acb_clear(s2); acb_clear(s3); acb_clear(t1); acb_clear(t2); mag_clear(qmag); }
void acb_rising_ui_rs(acb_t y, const acb_t x, ulong n, ulong m, slong prec) { acb_ptr xs; acb_t t, u, v; ulong i, k, rem; fmpz_t c, h; fmpz *s, *d; slong wp; if (n == 0) { acb_one(y); return; } if (n == 1) { acb_set_round(y, x, prec); return; } wp = ARF_PREC_ADD(prec, FLINT_BIT_COUNT(n)); acb_init(t); acb_init(u); acb_init(v); fmpz_init(c); fmpz_init(h); if (m == 0) { ulong m1, m2; m1 = 0.2 * pow(2.0 * wp, 0.4); m2 = n_sqrt(n); m = FLINT_MIN(m1, m2); } m = FLINT_MIN(m, n); m = FLINT_MAX(m, 1); xs = _acb_vec_init(m + 1); d = _fmpz_vec_init(m * m); s = _fmpz_vec_init(m + 1); _acb_vec_set_powers(xs, x, m + 1, wp); rising_difference_polynomial(s, d, m); /* tail */ rem = m; while (rem + m <= n) rem += m; acb_one(y); for (k = rem; k < n; k++) { acb_add_ui(t, xs + 1, k, wp); acb_mul(y, y, t, wp); } /* initial rising factorial */ acb_zero(t); for (i = 1; i <= m; i++) acb_addmul_fmpz(t, xs + i, s + i, wp); acb_mul(y, y, t, wp); /* the leading coefficient is always the same */ acb_mul_fmpz(xs + m - 1, xs + m - 1, d + m - 1 + 0, wp); for (k = 0; k + 2 * m <= n; k += m) { for (i = 0; i < m - 1; i++) { fmpz_set_ui(h, k); _fmpz_poly_evaluate_horner_fmpz(c, d + i * m, m - i, h); if (i == 0) acb_add_fmpz(t, t, c, wp); else acb_addmul_fmpz(t, xs + i, c, wp); } acb_add(t, t, xs + m - 1, wp); acb_mul(y, y, t, wp); } acb_set_round(y, y, prec); acb_clear(t); acb_clear(u); acb_clear(v); _acb_vec_clear(xs, m + 1); _fmpz_vec_clear(d, m * m); _fmpz_vec_clear(s, m + 1); fmpz_clear(c); fmpz_clear(h); }