void mag_sqrt(mag_t y, const mag_t x) { if (mag_is_special(x)) { mag_set(y, x); } else { double t; fmpz e; t = MAG_MAN(x) * ldexp(1.0, -MAG_BITS); e = MAG_EXP(x); if (!COEFF_IS_MPZ(e)) { if (e % 2 != 0) { e = (e - 1) >> 1; t *= 2.0; } else { e >>= 1; } t = sqrt(t) * (1 + 1e-13); mag_set_d_2exp_fmpz(y, t, &e); }
static void acb_rising_get_mag2_right(mag_t bound, const arb_t a, const arb_t b, ulong n) { mag_t t, u; ulong k; mag_init(t); mag_init(u); arb_get_mag(t, a); arb_get_mag(u, b); mag_mul(bound, t, t); mag_addmul(bound, u, u); mag_set(u, bound); mag_mul_2exp_si(t, t, 1); for (k = 1; k < n; k++) { mag_add_ui_2exp_si(u, u, 2 * k - 1, 0); mag_add(u, u, t); mag_mul(bound, bound, u); } mag_clear(t); mag_clear(u); }
static void _acb_mul_fast(acb_t z, const acb_t x, const acb_t y, slong prec) { int inexact; mag_t am, bm, cm, dm, er, fr; mag_fast_init_set_arf(am, arb_midref(a)); mag_fast_init_set_arf(bm, arb_midref(b)); mag_fast_init_set_arf(cm, arb_midref(c)); mag_fast_init_set_arf(dm, arb_midref(d)); mag_init(er); mag_init(fr); mag_fast_addmul(er, am, cr); mag_fast_addmul(er, bm, dr); mag_fast_addmul(er, cm, ar); mag_fast_addmul(er, dm, br); mag_fast_addmul(er, ar, cr); mag_fast_addmul(er, br, dr); mag_fast_addmul(fr, am, dr); mag_fast_addmul(fr, bm, cr); mag_fast_addmul(fr, cm, br); mag_fast_addmul(fr, dm, ar); mag_fast_addmul(fr, br, cr); mag_fast_addmul(fr, ar, dr); inexact = arf_complex_mul(arb_midref(e), arb_midref(f), arb_midref(a), arb_midref(b), arb_midref(c), arb_midref(d), prec, ARB_RND); if (inexact & 1) arf_mag_add_ulp(arb_radref(e), er, arb_midref(e), prec); else mag_set(arb_radref(e), er); if (inexact & 2) arf_mag_add_ulp(arb_radref(f), fr, arb_midref(f), prec); else mag_set(arb_radref(f), fr); }
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_hypgeom_erf_propagated_error(mag_t re, mag_t im, const acb_t z) { mag_t x, y; mag_init(x); mag_init(y); /* |exp(-(x+y)^2)| = exp(y^2-x^2) */ arb_get_mag(y, acb_imagref(z)); mag_mul(y, y, y); arb_get_mag_lower(x, acb_realref(z)); mag_mul_lower(x, x, x); if (mag_cmp(y, x) >= 0) { mag_sub(re, y, x); mag_exp(re, re); } else { mag_sub_lower(re, x, y); mag_expinv(re, re); } /* Radius. */ mag_hypot(x, arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); mag_mul(re, re, x); /* 2/sqrt(pi) < 289/256 */ mag_mul_ui(re, re, 289); mag_mul_2exp_si(re, re, -8); if (arb_is_zero(acb_imagref(z))) { /* todo: could bound magnitude even for complex numbers */ mag_set_ui(y, 2); mag_min(re, re, y); mag_zero(im); } else if (arb_is_zero(acb_realref(z))) { mag_swap(im, re); mag_zero(re); } else { mag_set(im, re); } mag_clear(x); mag_clear(y); }
void arb_addmul(arb_t z, const arb_t x, const arb_t y, slong prec) { mag_t zr, xm, ym; int inexact; if (arb_is_exact(y)) { arb_addmul_arf(z, x, arb_midref(y), prec); } else if (arb_is_exact(x)) { arb_addmul_arf(z, y, arb_midref(x), prec); } else if (ARB_IS_LAGOM(x) && ARB_IS_LAGOM(y) && ARB_IS_LAGOM(z)) { mag_fast_init_set_arf(xm, arb_midref(x)); mag_fast_init_set_arf(ym, arb_midref(y)); mag_fast_init_set(zr, arb_radref(z)); mag_fast_addmul(zr, xm, arb_radref(y)); mag_fast_addmul(zr, ym, arb_radref(x)); mag_fast_addmul(zr, arb_radref(x), arb_radref(y)); inexact = arf_addmul(arb_midref(z), arb_midref(x), arb_midref(y), prec, ARF_RND_DOWN); if (inexact) arf_mag_fast_add_ulp(zr, zr, arb_midref(z), prec); *arb_radref(z) = *zr; } else { mag_init_set_arf(xm, arb_midref(x)); mag_init_set_arf(ym, arb_midref(y)); mag_init_set(zr, arb_radref(z)); mag_addmul(zr, xm, arb_radref(y)); mag_addmul(zr, ym, arb_radref(x)); mag_addmul(zr, arb_radref(x), arb_radref(y)); inexact = arf_addmul(arb_midref(z), arb_midref(x), arb_midref(y), prec, ARF_RND_DOWN); if (inexact) arf_mag_add_ulp(arb_radref(z), zr, arb_midref(z), prec); else mag_set(arb_radref(z), zr); mag_clear(zr); mag_clear(xm); mag_clear(ym); } }
static void _acb_sqr_fast(acb_t z, const acb_t x, slong prec) { int inexact; mag_t am, bm, er, fr; mag_fast_init_set_arf(am, arb_midref(a)); mag_fast_init_set_arf(bm, arb_midref(b)); mag_init(er); mag_init(fr); mag_fast_addmul(er, am, ar); mag_fast_addmul(er, bm, br); mag_fast_mul_2exp_si(er, er, 1); mag_fast_addmul(er, ar, ar); mag_fast_addmul(er, br, br); mag_fast_addmul(fr, bm, ar); mag_fast_addmul(fr, am, br); mag_fast_addmul(fr, ar, br); mag_fast_mul_2exp_si(fr, fr, 1); inexact = arf_complex_sqr(arb_midref(e), arb_midref(f), arb_midref(a), arb_midref(b), prec, ARB_RND); if (inexact & 1) arf_mag_add_ulp(arb_radref(e), er, arb_midref(e), prec); else mag_set(arb_radref(e), er); if (inexact & 2) arf_mag_add_ulp(arb_radref(f), fr, arb_midref(f), prec); else mag_set(arb_radref(f), fr); }
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 mag_root(mag_t y, const mag_t x, ulong n) { if (n == 0) { mag_inf(y); } else if (n == 1 || mag_is_special(x)) { mag_set(y, x); } else if (n == 2) { mag_sqrt(y, x); } else if (n == 4) { mag_sqrt(y, x); mag_sqrt(y, y); } else { fmpz_t e, f; fmpz_init_set_ui(e, MAG_BITS); fmpz_init(f); /* We evaluate exp(log(1+2^(kn)x)/n) 2^-k where k is chosen so that 2^(kn) x ~= 2^30. TODO: this rewriting is probably unnecessary with the new exp/log functions. */ fmpz_sub(e, e, MAG_EXPREF(x)); fmpz_cdiv_q_ui(e, e, n); fmpz_mul_ui(f, e, n); mag_mul_2exp_fmpz(y, x, f); mag_log1p(y, y); mag_div_ui(y, y, n); mag_exp(y, y); fmpz_neg(e, e); mag_mul_2exp_fmpz(y, y, e); fmpz_clear(e); fmpz_clear(f); } }
void arb_atan(arb_t z, const arb_t x, slong prec) { if (arb_is_exact(x)) { arb_atan_arf(z, arb_midref(x), prec); } else { mag_t t, u; mag_init(t); mag_init(u); arb_get_mag_lower(t, x); if (mag_is_zero(t)) { mag_set(t, arb_radref(x)); } else { mag_mul_lower(t, t, t); mag_one(u); mag_add_lower(t, t, u); mag_div(t, arb_radref(x), t); } if (mag_cmp_2exp_si(t, 0) > 0) { mag_const_pi(u); mag_min(t, t, u); } arb_atan_arf(z, arb_midref(x), prec); mag_add(arb_radref(z), arb_radref(z), t); mag_clear(t); mag_clear(u); } }
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); } }
/* derivatives: |8/sqrt(pi) sin(2z^2)|, |8/sqrt(pi) cos(2z^2)| <= 5 exp(4|xy|) */ void acb_hypgeom_fresnel_erf_error(acb_t res1, acb_t res2, const acb_t z, slong prec) { mag_t re; mag_t im; acb_t zmid; mag_init(re); mag_init(im); acb_init(zmid); if (arf_cmpabs_ui(arb_midref(acb_realref(z)), 1000) < 0 && arf_cmpabs_ui(arb_midref(acb_imagref(z)), 1000) < 0) { arb_get_mag(re, acb_realref(z)); arb_get_mag(im, acb_imagref(z)); mag_mul(re, re, im); mag_mul_2exp_si(re, re, 2); mag_exp(re, re); mag_mul_ui(re, re, 5); } else { arb_t t; arb_init(t); arb_mul(t, acb_realref(z), acb_imagref(z), prec); arb_abs(t, t); arb_mul_2exp_si(t, t, 2); arb_exp(t, t, prec); arb_get_mag(re, t); mag_mul_ui(re, re, 5); arb_clear(t); } mag_hypot(im, arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); mag_mul(re, re, im); if (arb_is_zero(acb_imagref(z))) { mag_set_ui(im, 8); /* For real x, |S(x)| < 4, |C(x)| < 4. */ mag_min(re, re, im); mag_zero(im); } else if (arb_is_zero(acb_realref(z))) { mag_set_ui(im, 8); mag_min(im, re, im); mag_zero(re); } else { mag_set(im, re); } 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_fresnel_erf(res1, res2, zmid, prec); if (res1 != NULL) { arb_add_error_mag(acb_realref(res1), re); arb_add_error_mag(acb_imagref(res1), im); } if (res2 != NULL) { arb_add_error_mag(acb_realref(res2), re); arb_add_error_mag(acb_imagref(res2), im); } mag_clear(re); mag_clear(im); acb_clear(zmid); }
/* Given T(K), compute bound for T(n) z^n. We need to multiply by z^n * 1/rf(K+1,m)^r * (rf(K+1,m)/rf(K+1-A,m)) * (rf(K+1-B,m)/rf(K+1-2B,m)) where m = n - K. This is equal to z^n * (K+A)! (K-2B)! (K-B+m)! ----------------------- * ((K+m)! / K!)^(1-r) (K-B)! (K-A+m)! (K-2B+m)! */ void hypgeom_term_bound(mag_t Tn, const mag_t TK, slong K, slong A, slong B, int r, const mag_t z, slong n) { mag_t t, u, num; slong m; mag_init(t); mag_init(u); mag_init(num); m = n - K; if (m < 0) { flint_printf("hypgeom term bound\n"); abort(); } /* TK * z^n */ mag_pow_ui(t, z, n); mag_mul(num, TK, t); /* numerator: (K+A)! (K-2B)! (K-B+m)! */ mag_fac_ui(t, K+A); mag_mul(num, num, t); mag_fac_ui(t, K-2*B); mag_mul(num, num, t); mag_fac_ui(t, K-B+m); mag_mul(num, num, t); /* denominator: (K-B)! (K-A+m)! (K-2B+m)! */ mag_rfac_ui(t, K-B); mag_mul(num, num, t); mag_rfac_ui(t, K-A+m); mag_mul(num, num, t); mag_rfac_ui(t, K-2*B+m); mag_mul(num, num, t); /* ((K+m)! / K!)^(1-r) */ if (r == 0) { mag_fac_ui(t, K+m); mag_mul(num, num, t); mag_rfac_ui(t, K); mag_mul(num, num, t); } else if (r != 1) { mag_fac_ui(t, K); mag_rfac_ui(u, K+m); mag_mul(t, t, u); mag_pow_ui(t, t, r-1); mag_mul(num, num, t); } mag_set(Tn, num); mag_clear(t); mag_clear(u); mag_clear(num); }
slong hypgeom_bound(mag_t error, int r, slong A, slong B, slong K, const mag_t TK, const mag_t z, slong tol_2exp) { mag_t Tn, t, u, one, tol, num, den; slong n, m; mag_init(Tn); mag_init(t); mag_init(u); mag_init(one); mag_init(tol); mag_init(num); mag_init(den); mag_one(one); mag_set_ui_2exp_si(tol, UWORD(1), -tol_2exp); /* approximate number of needed terms */ n = hypgeom_estimate_terms(z, r, tol_2exp); /* required for 1 + O(1/k) part to be decreasing */ n = FLINT_MAX(n, K + 1); /* required for z^k / (k!)^r to be decreasing */ m = hypgeom_root_bound(z, r); n = FLINT_MAX(n, m); /* We now have |R(k)| <= G(k) where G(k) is monotonically decreasing, and can bound the tail using a geometric series as soon as soon as G(k) < 1. */ /* bound T(n-1) */ hypgeom_term_bound(Tn, TK, K, A, B, r, z, n-1); while (1) { /* bound R(n) */ mag_mul_ui(num, z, n); mag_mul_ui(num, num, n - B); mag_set_ui_lower(den, n - A); mag_mul_ui_lower(den, den, n - 2*B); if (r != 0) { mag_set_ui_lower(u, n); mag_pow_ui_lower(u, u, r); mag_mul_lower(den, den, u); } mag_div(t, num, den); /* multiply bound for T(n-1) by bound for R(n) to bound T(n) */ mag_mul(Tn, Tn, t); /* geometric series termination check */ /* u = max(1-t, 0), rounding down [lower bound] */ mag_sub_lower(u, one, t); if (!mag_is_zero(u)) { mag_div(u, Tn, u); if (mag_cmp(u, tol) < 0) { mag_set(error, u); break; } } /* move on to next term */ n++; } mag_clear(Tn); mag_clear(t); mag_clear(u); mag_clear(one); mag_clear(tol); mag_clear(num); mag_clear(den); return n; }
void arb_abs(arb_t y, const arb_t x) { arf_abs(arb_midref(y), arb_midref(x)); mag_set(arb_radref(y), arb_radref(x)); }
void arb_set(arb_t x, const arb_t y) { arf_set(arb_midref(x), arb_midref(y)); mag_set(arb_radref(x), arb_radref(y)); }
/* computes the factors that are independent of n (all are upper bounds) */ void acb_hypgeom_u_asymp_bound_factors(int * R, mag_t alpha, mag_t nu, mag_t sigma, mag_t rho, mag_t zinv, const acb_t a, const acb_t b, const acb_t z) { mag_t r, u, zre, zim, zlo, sigma_prime; acb_t t; mag_init(r); mag_init(u); mag_init(zre); mag_init(zim); mag_init(zlo); mag_init(sigma_prime); acb_init(t); /* lower bounds for |re(z)|, |im(z)|, |z| */ arb_get_mag_lower(zre, acb_realref(z)); arb_get_mag_lower(zim, acb_imagref(z)); acb_get_mag_lower(zlo, z); /* todo: hypot */ /* upper bound for 1/|z| */ mag_one(u); mag_div(zinv, u, zlo); /* upper bound for r = |b - 2a| */ acb_mul_2exp_si(t, a, 1); acb_sub(t, b, t, MAG_BITS); acb_get_mag(r, t); /* determine region */ *R = 0; if (mag_cmp(zlo, r) >= 0) { int znonneg = arb_is_nonnegative(acb_realref(z)); if (znonneg && mag_cmp(zre, r) >= 0) { *R = 1; } else if (mag_cmp(zim, r) >= 0 || znonneg) { *R = 2; } else { mag_mul_2exp_si(u, r, 1); if (mag_cmp(zlo, u) >= 0) *R = 3; } } if (R == 0) { mag_inf(alpha); mag_inf(nu); mag_inf(sigma); mag_inf(rho); } else { /* sigma = |(b-2a)/z| */ mag_mul(sigma, r, zinv); /* nu = (1/2 + 1/2 sqrt(1-4 sigma^2))^(-1/2) <= 1 + 2 sigma^2 */ if (mag_cmp_2exp_si(sigma, -1) <= 0) { mag_mul(nu, sigma, sigma); mag_mul_2exp_si(nu, nu, 1); mag_one(u); mag_add(nu, nu, u); } else { mag_inf(nu); } /* modified sigma for alpha, beta, rho when in R3 */ if (*R == 3) mag_mul(sigma_prime, sigma, nu); else mag_set(sigma_prime, sigma); /* alpha = 1/(1-sigma') */ mag_one(alpha); mag_sub_lower(alpha, alpha, sigma_prime); mag_one(u); mag_div(alpha, u, alpha); /* rho = |2a^2-2ab+b|/2 + sigma'*(1+sigma'/4)/(1-sigma')^2 */ mag_mul_2exp_si(rho, sigma_prime, -2); mag_one(u); mag_add(rho, rho, u); mag_mul(rho, rho, sigma_prime); mag_mul(rho, rho, alpha); mag_mul(rho, rho, alpha); acb_sub(t, a, b, MAG_BITS); acb_mul(t, t, a, MAG_BITS); acb_mul_2exp_si(t, t, 1); acb_add(t, t, b, MAG_BITS); acb_get_mag(u, t); mag_mul_2exp_si(u, u, -1); mag_add(rho, rho, u); } mag_clear(r); mag_clear(u); mag_clear(zre); mag_clear(zim); mag_clear(zlo); mag_clear(sigma_prime); acb_clear(t); }
void mag_polylog_tail(mag_t u, const mag_t z, long sigma, ulong d, ulong N) { mag_t TN, UN, t; if (N < 2) { mag_inf(u); return; } mag_init(TN); mag_init(UN); mag_init(t); if (mag_cmp_2exp_si(z, 0) >= 0) { mag_inf(u); } else { /* Bound T(N) */ mag_pow_ui(TN, z, N); /* multiply by log(N)^d */ if (d > 0) { mag_log_ui(t, N); mag_pow_ui(t, t, d); mag_mul(TN, TN, t); } /* multiply by 1/k^s */ if (sigma > 0) { mag_set_ui_lower(t, N); mag_pow_ui_lower(t, t, sigma); mag_div(TN, TN, t); } else if (sigma < 0) { mag_set_ui(t, N); mag_pow_ui(t, t, -sigma); mag_mul(TN, TN, t); } /* Bound U(N) */ mag_set(UN, z); /* multiply by (1 + 1/N)**S */ if (sigma < 0) { mag_binpow_uiui(t, N, -sigma); mag_mul(UN, UN, t); } /* multiply by (1 + 1/(N log(N)))^d */ if (d > 0) { ulong nl; /* rounds down */ nl = mag_d_log_lower_bound(N) * N * (1 - 1e-13); mag_binpow_uiui(t, nl, d); mag_mul(UN, UN, t); } /* T(N) / (1 - U(N)) */ if (mag_cmp_2exp_si(UN, 0) >= 0) { mag_inf(u); } else { mag_one(t); mag_sub_lower(t, t, UN); mag_div(u, TN, t); } } mag_clear(TN); mag_clear(UN); mag_clear(t); }
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); }
void mag_log1p(mag_t z, const mag_t x) { if (mag_is_special(x)) { if (mag_is_zero(x)) mag_zero(z); else mag_inf(z); } else { fmpz exp = MAG_EXP(x); if (!COEFF_IS_MPZ(exp)) { /* Quick bound by x */ if (exp < -10) { mag_set(z, x); return; } else if (exp < 1000) { double t; t = ldexp(MAG_MAN(x), exp - MAG_BITS); t = (1.0 + t) * (1 + 1e-14); t = mag_d_log_upper_bound(t); mag_set_d(z, t); return; } } else if (fmpz_sgn(MAG_EXPREF(x)) < 0) { /* Quick bound by x */ mag_set(z, x); return; } /* Now we must have x >= 2^1000 */ /* Use log(2^(exp-1) * (2*v)) = exp*log(2) + log(2*v) */ { double t; fmpz_t b; mag_t u; mag_init(u); fmpz_init(b); /* incrementing the mantissa gives an upper bound for x+1 */ t = ldexp(MAG_MAN(x) + 1, 1 - MAG_BITS); t = mag_d_log_upper_bound(t); mag_set_d(u, t); /* log(2) < 744261118/2^30 */ _fmpz_add_fast(b, MAG_EXPREF(x), -1); fmpz_mul_ui(b, b, 744261118); mag_set_fmpz(z, b); _fmpz_add_fast(MAG_EXPREF(z), MAG_EXPREF(z), -30); mag_add(z, z, u); mag_clear(u); fmpz_clear(b); } } }
int main() { slong iter; flint_rand_t state; flint_printf("rel_accuracy_bits...."); fflush(stdout); flint_randinit(state); /* test aliasing of c and a */ for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) { arb_t x; acb_t z; slong a1, a2; arb_init(x); acb_init(z); arb_randtest_special(x, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); acb_set_arb(z, x); a1 = arb_rel_accuracy_bits(x); a2 = acb_rel_accuracy_bits(z); if (a1 != a2) { flint_printf("FAIL: acb != arb\n\n"); flint_printf("x = "); arb_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } acb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); a1 = acb_rel_accuracy_bits(z); if (n_randint(state, 2)) arf_swap(arb_midref(acb_realref(z)), arb_midref(acb_imagref(z))); if (n_randint(state, 2)) mag_swap(arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); a2 = acb_rel_accuracy_bits(z); if (a1 != a2) { flint_printf("FAIL: swapping\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } acb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 200)); if (arf_cmpabs(arb_midref(acb_realref(z)), arb_midref(acb_imagref(z))) >= 0) arf_set(arb_midref(x), arb_midref(acb_realref(z))); else arf_set(arb_midref(x), arb_midref(acb_imagref(z))); if (mag_cmp(arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))) >= 0) mag_set(arb_radref(x), arb_radref(acb_realref(z))); else mag_set(arb_radref(x), arb_radref(acb_imagref(z))); a1 = acb_rel_accuracy_bits(z); a2 = arb_rel_accuracy_bits(x); if (a1 != a2) { flint_printf("FAIL: acb != arb (2)\n\n"); flint_printf("x = "); arb_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_print(z); flint_printf("\n\n"); flint_printf("a1 = %wd, a2 = %wd\n\n", a1, a2); abort(); } arb_clear(x); acb_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void _arb_sin_cos_generic(arb_t s, arb_t c, const arf_t x, const mag_t xrad, slong prec) { int want_sin, want_cos; slong maglim; want_sin = (s != NULL); want_cos = (c != NULL); if (arf_is_zero(x) && mag_is_zero(xrad)) { if (want_sin) arb_zero(s); if (want_cos) arb_one(c); return; } if (!arf_is_finite(x) || !mag_is_finite(xrad)) { if (arf_is_nan(x)) { if (want_sin) arb_indeterminate(s); if (want_cos) arb_indeterminate(c); } else { if (want_sin) arb_zero_pm_one(s); if (want_cos) arb_zero_pm_one(c); } return; } maglim = FLINT_MAX(65536, 4 * prec); if (mag_cmp_2exp_si(xrad, -16) > 0 || arf_cmpabs_2exp_si(x, maglim) > 0) { _arb_sin_cos_wide(s, c, x, xrad, prec); return; } if (arf_cmpabs_2exp_si(x, -(prec/2) - 2) <= 0) { mag_t t, u, v; mag_init(t); mag_init(u); mag_init(v); arf_get_mag(t, x); mag_add(t, t, xrad); mag_mul(u, t, t); /* |sin(z)-z| <= z^3/6 */ if (want_sin) { arf_set(arb_midref(s), x); mag_set(arb_radref(s), xrad); arb_set_round(s, s, prec); mag_mul(v, u, t); mag_div_ui(v, v, 6); arb_add_error_mag(s, v); } /* |cos(z)-1| <= z^2/2 */ if (want_cos) { arf_one(arb_midref(c)); mag_mul_2exp_si(arb_radref(c), u, -1); } mag_clear(t); mag_clear(u); mag_clear(v); return; } if (mag_is_zero(xrad)) { arb_sin_cos_arf_generic(s, c, x, prec); } else { mag_t t; slong exp, radexp; mag_init_set(t, xrad); exp = arf_abs_bound_lt_2exp_si(x); radexp = MAG_EXP(xrad); if (radexp < MAG_MIN_LAGOM_EXP || radexp > MAG_MAX_LAGOM_EXP) radexp = MAG_MIN_LAGOM_EXP; if (want_cos && exp < -2) prec = FLINT_MIN(prec, 20 - FLINT_MAX(exp, radexp) - radexp); else prec = FLINT_MIN(prec, 20 - radexp); arb_sin_cos_arf_generic(s, c, x, prec); /* todo: could use quadratic bound */ if (want_sin) mag_add(arb_radref(s), arb_radref(s), t); if (want_cos) mag_add(arb_radref(c), arb_radref(c), t); mag_clear(t); } }