void fmprb_tanh(fmprb_t y, const fmprb_t x, long prec) { fmprb_t t, u; fmprb_init(t); fmprb_init(u); fmprb_mul_2exp_si(t, x, 1); if (fmpr_sgn(fmprb_midref(x)) >= 0) { fmprb_neg(t, t); fmprb_expm1(t, t, prec + 4); fmprb_add_ui(y, t, 2, prec + 4); fmprb_div(y, t, y, prec); fmprb_neg(y, y); } else { fmprb_expm1(t, t, prec + 4); fmprb_add_ui(y, t, 2, prec + 4); fmprb_div(y, t, y, prec); } fmprb_clear(t); fmprb_clear(u); }
void gamma_taylor_bound_remainder(fmpr_t err, const fmpr_t z, long n) { fmpr_t t, u; gamma_taylor_bound_extend_cache(n + 1); fmpr_init(t); fmpr_init(u); /* denominator: 1 - r(n+1) * z, rounded down */ fmpr_mul(t, gamma_taylor_bound_ratio_cache + n + 1, z, FMPRB_RAD_PREC, FMPR_RND_UP); fmpr_one(u); fmpr_sub(u, u, t, FMPRB_RAD_PREC, FMPR_RND_DOWN); if (fmpr_sgn(u) <= 0) { fmpr_pos_inf(err); } else { fmpr_pow_sloppy_ui(t, z, n, FMPRB_RAD_PREC, FMPR_RND_UP); fmpr_mul_2exp_si(t, t, gamma_taylor_bound_mag_cache[n + 1]); fmpr_div(err, t, u, FMPRB_RAD_PREC, FMPR_RND_UP); } fmpr_clear(t); fmpr_clear(u); }
static void _fmpr_div_special(fmpr_t z, const fmpr_t x, const fmpr_t y) { if ((fmpr_is_zero(x) && !fmpr_is_zero(y) && !fmpr_is_nan(y)) || (fmpr_is_inf(y) && !fmpr_is_special(x))) { fmpr_zero(z); } else if (fmpr_is_zero(y) || (fmpr_is_special(x) && fmpr_is_special(y)) || fmpr_is_nan(x) || fmpr_is_nan(y)) { fmpr_nan(z); } else if (fmpr_sgn(x) == fmpr_sgn(y)) fmpr_pos_inf(z); else fmpr_neg_inf(z); }
int fmpr_cmpabs(const fmpr_t x, const fmpr_t y) { int res, xsign, ysign; fmpr_t t; if (fmpr_equal(x, y)) return 0; if (fmpr_is_special(x) || fmpr_is_special(y)) { if (fmpr_is_nan(x) || fmpr_is_nan(y)) return 0; if (fmpr_is_zero(x)) return -1; if (fmpr_is_zero(y)) return 1; if (fmpr_is_inf(x)) return fmpr_is_inf(y) ? 0 : 1; if (fmpr_is_inf(y)) return -1; return -1; } /* Reduces to integer comparison if bottom exponents are the same */ if (fmpz_equal(fmpr_expref(x), fmpr_expref(y))) { res = fmpz_cmpabs(fmpr_manref(x), fmpr_manref(y)); if (res != 0) res = (res < 0) ? -1 : 1; } else { /* TODO: compare position of top exponents to avoid subtraction */ xsign = fmpr_sgn(x); ysign = fmpr_sgn(y); fmpr_init(t); if (xsign == ysign) fmpr_sub(t, x, y, 2, FMPR_RND_DOWN); else fmpr_add(t, x, y, 2, FMPR_RND_DOWN); res = fmpr_sgn(t) * xsign; fmpr_clear(t); } return res; }
slong fmpr_rsqrt(fmpr_t y, const fmpr_t x, slong prec, fmpr_rnd_t rnd) { slong r; if (fmpr_is_special(x)) { if (fmpr_is_zero(x)) fmpr_pos_inf(y); else if (fmpr_is_pos_inf(x)) fmpr_zero(y); else fmpr_nan(y); return FMPR_RESULT_EXACT; } if (fmpr_sgn(x) < 0) { fmpr_nan(y); return FMPR_RESULT_EXACT; } /* special case: 4^n */ if (fmpz_is_one(fmpr_manref(x)) && fmpz_is_even(fmpr_expref(x))) { r = fmpr_set_round(y, x, prec, rnd); fmpz_tdiv_q_2exp(fmpr_expref(y), fmpr_expref(y), 1); fmpz_neg(fmpr_expref(y), fmpr_expref(y)); return r; } { fmpr_t t; fmpz_t e; fmpr_init(t); fmpz_init(e); fmpz_neg(e, fmpr_expref(x)); if (fmpz_is_odd(e)) fmpz_add_ui(e, e, 1); fmpr_mul_2exp_fmpz(t, x, e); CALL_MPFR_FUNC(r, mpfr_rec_sqrt, y, t, prec, rnd); fmpz_tdiv_q_2exp(e, e, 1); fmpr_mul_2exp_fmpz(y, y, e); fmpr_clear(t); fmpz_clear(e); return r; } }
int fmpr_cmp(const fmpr_t x, const fmpr_t y) { int res, xsign, ysign; fmpr_t t; if (fmpr_equal(x, y)) return 0; if (fmpr_is_special(x) || fmpr_is_special(y)) { if (fmpr_is_nan(x) || fmpr_is_nan(y)) return 0; if (fmpr_is_zero(y)) return fmpr_sgn(x); if (fmpr_is_zero(x)) return -fmpr_sgn(y); if (fmpr_is_pos_inf(x)) return 1; if (fmpr_is_neg_inf(y)) return 1; return -1; } xsign = fmpr_sgn(x); ysign = fmpr_sgn(y); if (xsign != ysign) return (xsign < 0) ? -1 : 1; /* Reduces to integer comparison if bottom exponents are the same */ if (fmpz_equal(fmpr_expref(x), fmpr_expref(y))) return fmpz_cmp(fmpr_manref(x), fmpr_manref(y)) < 0 ? -1 : 1; /* TODO: compare position of top exponents to avoid subtraction */ fmpr_init(t); fmpr_sub(t, x, y, 2, FMPR_RND_DOWN); res = fmpr_sgn(t); fmpr_clear(t); return res; }
slong fmpr_mul_fmpz(fmpr_t z, const fmpr_t x, const fmpz_t y, slong prec, fmpr_rnd_t rnd) { fmpz xv, yv; fmpz yexp; if (fmpr_is_special(x) || fmpz_is_zero(y)) { if (fmpr_is_zero(x)) { fmpr_zero(z); } else if (fmpz_is_zero(y) && fmpr_is_finite(x)) { fmpr_zero(z); } else if (fmpr_is_inf(x) && !fmpz_is_zero(y)) { if (fmpr_sgn(x) == fmpz_sgn(y)) fmpr_pos_inf(z); else fmpr_neg_inf(z); } else { fmpr_nan(z); } return FMPR_RESULT_EXACT; } xv = *fmpr_manref(x); yv = *y; if (!COEFF_IS_MPZ(xv) && !COEFF_IS_MPZ(yv)) { mp_limb_t ytmp; unsigned int bc; ytmp = FLINT_ABS(yv); count_trailing_zeros(bc, ytmp); ytmp >>= bc; yexp = bc; return _fmpr_mul_1x1(z, FLINT_ABS(xv), fmpr_expref(x), ytmp, &yexp, (xv ^ yv) < 0, prec, rnd); }
void fmprb_hypgeom_infsum(fmprb_t P, fmprb_t Q, hypgeom_t hyp, long target_prec, long prec) { mag_t err, z; long n; mag_init(err); mag_init(z); mag_set_fmpz(z, hyp->P->coeffs + hyp->P->length - 1); mag_div_fmpz(z, z, hyp->Q->coeffs + hyp->Q->length - 1); if (!hyp->have_precomputed) { hypgeom_precompute(hyp); hyp->have_precomputed = 1; } n = hypgeom_bound(err, hyp->r, hyp->boundC, hyp->boundD, hyp->boundK, hyp->MK, z, target_prec); fmprb_hypgeom_sum(P, Q, hyp, n, prec); if (fmpr_sgn(fmprb_midref(Q)) < 0) { fmprb_neg(P, P); fmprb_neg(Q, Q); } /* We have p/q = s + err i.e. (p + q*err)/q = s */ { fmpr_t u, v; fmpr_init(u); fmpr_init(v); mag_get_fmpr(v, err); fmpr_add(u, fmprb_midref(Q), fmprb_radref(Q), FMPRB_RAD_PREC, FMPR_RND_UP); fmpr_mul(u, u, v, FMPRB_RAD_PREC, FMPR_RND_UP); fmprb_add_error_fmpr(P, u); fmpr_clear(u); fmpr_clear(v); } mag_clear(z); mag_clear(err); }
static __inline__ void fmprb_nonnegative_part(fmprb_t z, const fmprb_t x, slong prec) { if (fmprb_contains_negative(x)) { fmpr_add(fmprb_midref(z), fmprb_midref(x), fmprb_radref(x), prec, FMPR_RND_CEIL); if (fmpr_sgn(fmprb_midref(z)) <= 0) { fmpr_zero(fmprb_radref(z)); } else { fmpr_mul_2exp_si(fmprb_midref(z), fmprb_midref(z), -1); fmpr_set(fmprb_midref(z), fmprb_radref(z)); } } else { fmprb_set(z, x); } }
void fmprb_sqrtpos(fmprb_t z, const fmprb_t x, slong prec) { if (!fmprb_is_finite(x)) { if (fmpr_is_zero(fmprb_radref(x)) && fmpr_is_pos_inf(fmprb_midref(x))) fmprb_pos_inf(z); else fmprb_zero_pm_inf(z); } else if (fmprb_contains_nonpositive(x)) { fmpr_t t; fmpr_init(t); fmpr_add(t, fmprb_midref(x), fmprb_radref(x), FMPRB_RAD_PREC, FMPR_RND_CEIL); if (fmpr_sgn(t) <= 0) { fmprb_zero(z); } else { fmpr_sqrt(t, t, FMPRB_RAD_PREC, FMPR_RND_CEIL); fmpr_mul_2exp_si(t, t, -1); fmpr_set(fmprb_midref(z), t); fmpr_set(fmprb_radref(z), t); } fmpr_clear(t); } else { fmprb_sqrt(z, x, prec); } fmprb_nonnegative_part(z, z, prec); }
void _fmprb_poly_zeta_series(fmprb_ptr res, fmprb_srcptr h, long hlen, const fmprb_t a, int deflate, long len, long prec) { long i; fmpcb_t cs, ca; fmpcb_ptr z; fmprb_ptr t, u; if (fmprb_contains_nonpositive(a)) { _fmprb_vec_indeterminate(res, len); return; } hlen = FLINT_MIN(hlen, len); z = _fmpcb_vec_init(len); t = _fmprb_vec_init(len); u = _fmprb_vec_init(len); fmpcb_init(cs); fmpcb_init(ca); /* use reflection formula */ if (fmpr_sgn(fmprb_midref(h)) < 0 && fmprb_is_one(a)) { /* zeta(s) = (2*pi)**s * sin(pi*s/2) / pi * gamma(1-s) * zeta(1-s) */ fmprb_t pi; fmprb_ptr f, s1, s2, s3, s4; fmprb_init(pi); f = _fmprb_vec_init(2); s1 = _fmprb_vec_init(len); s2 = _fmprb_vec_init(len); s3 = _fmprb_vec_init(len); s4 = _fmprb_vec_init(len); fmprb_const_pi(pi, prec); /* s1 = (2*pi)**s */ fmprb_mul_2exp_si(pi, pi, 1); _fmprb_poly_pow_cpx(s1, pi, h, len, prec); fmprb_mul_2exp_si(pi, pi, -1); /* s2 = sin(pi*s/2) / pi */ fmprb_mul_2exp_si(pi, pi, -1); fmprb_mul(f, pi, h, prec); fmprb_set(f + 1, pi); fmprb_mul_2exp_si(pi, pi, 1); _fmprb_poly_sin_series(s2, f, 2, len, prec); _fmprb_vec_scalar_div(s2, s2, len, pi, prec); /* s3 = gamma(1-s) */ fmprb_sub_ui(f, h, 1, prec); fmprb_neg(f, f); fmprb_set_si(f + 1, -1); _fmprb_poly_gamma_series(s3, f, 2, len, prec); /* s4 = zeta(1-s) */ fmprb_sub_ui(f, h, 1, prec); fmprb_neg(f, f); fmpcb_set_fmprb(cs, f); fmpcb_one(ca); zeta_series(z, cs, ca, 0, len, prec); for (i = 0; i < len; i++) fmprb_set(s4 + i, fmpcb_realref(z + i)); for (i = 1; i < len; i += 2) fmprb_neg(s4 + i, s4 + i); _fmprb_poly_mullow(u, s1, len, s2, len, len, prec); _fmprb_poly_mullow(s1, s3, len, s4, len, len, prec); _fmprb_poly_mullow(t, u, len, s1, len, len, prec); /* add 1/(1-(s+t)) = 1/(1-s) + t/(1-s)^2 + ... */ if (deflate) { fmprb_sub_ui(u, h, 1, prec); fmprb_neg(u, u); fmprb_ui_div(u, 1, u, prec); for (i = 1; i < len; i++) fmprb_mul(u + i, u + i - 1, u, prec); _fmprb_vec_add(t, t, u, len, prec); } fmprb_clear(pi); _fmprb_vec_clear(f, 2); _fmprb_vec_clear(s1, len); _fmprb_vec_clear(s2, len); _fmprb_vec_clear(s3, len); _fmprb_vec_clear(s4, len); } else { fmpcb_set_fmprb(cs, h); fmpcb_set_fmprb(ca, a); zeta_series(z, cs, ca, deflate, len, prec); for (i = 0; i < len; i++) fmprb_set(t + i, fmpcb_realref(z + i)); } /* compose with nonconstant part */ fmprb_zero(u); _fmprb_vec_set(u + 1, h + 1, hlen - 1); _fmprb_poly_compose_series(res, t, len, u, hlen, len, prec); _fmpcb_vec_clear(z, len); _fmprb_vec_clear(t, len); _fmprb_vec_clear(u, len); fmpcb_init(cs); fmpcb_init(ca); }
int fmprb_contains(const fmprb_t x, const fmprb_t y) { fmpr_t t; fmpr_t u; fmpr_struct tmp[4]; int left_ok, right_ok; if (fmprb_is_exact(y)) return fmprb_contains_fmpr(x, fmprb_midref(y)); if (fmpr_is_nan(fmprb_midref(y))) return fmpr_is_nan(fmprb_midref(x)); fmpr_init(t); fmpr_init(u); /* fast check */ fmpr_sub(t, fmprb_midref(x), fmprb_radref(x), 30, FMPR_RND_CEIL); fmpr_sub(u, fmprb_midref(y), fmprb_radref(y), 30, FMPR_RND_FLOOR); left_ok = fmpr_cmp(t, u) <= 0; /* exact check */ if (!left_ok) { fmpr_init(tmp + 0); fmpr_init(tmp + 1); fmpr_init(tmp + 2); fmpr_init(tmp + 3); fmpr_set(tmp + 0, fmprb_midref(x)); fmpr_neg(tmp + 1, fmprb_radref(x)); fmpr_neg(tmp + 2, fmprb_midref(y)); fmpr_set(tmp + 3, fmprb_radref(y)); fmpr_sum(t, tmp, 4, 30, FMPR_RND_DOWN); left_ok = fmpr_sgn(t) <= 0; fmpr_clear(tmp + 0); fmpr_clear(tmp + 1); fmpr_clear(tmp + 2); fmpr_clear(tmp + 3); } /* fast check */ fmpr_add(t, fmprb_midref(x), fmprb_radref(x), 30, FMPR_RND_FLOOR); fmpr_add(u, fmprb_midref(y), fmprb_radref(y), 30, FMPR_RND_CEIL); right_ok = (fmpr_cmp(t, u) >= 0); /* exact check */ if (!right_ok) { fmpr_init(tmp + 0); fmpr_init(tmp + 1); fmpr_init(tmp + 2); fmpr_init(tmp + 3); fmpr_set(tmp + 0, fmprb_midref(x)); fmpr_set(tmp + 1, fmprb_radref(x)); fmpr_neg(tmp + 2, fmprb_midref(y)); fmpr_neg(tmp + 3, fmprb_radref(y)); fmpr_sum(t, tmp, 4, 30, FMPR_RND_DOWN); right_ok = fmpr_sgn(t) >= 0; fmpr_clear(tmp + 0); fmpr_clear(tmp + 1); fmpr_clear(tmp + 2); fmpr_clear(tmp + 3); } fmpr_clear(t); fmpr_clear(u); return left_ok && right_ok; }