int arf_sub_special(arf_t z, const arf_t x, const arf_t y, slong prec, arf_rnd_t rnd) { if (arf_is_zero(x)) { if (arf_is_zero(y)) { arf_zero(z); return 0; } else return arf_neg_round(z, y, prec, rnd); } else if (arf_is_zero(y)) { return arf_set_round(z, x, prec, rnd); } else if (arf_is_nan(x) || arf_is_nan(y) || (arf_is_pos_inf(x) && arf_is_pos_inf(y)) || (arf_is_neg_inf(x) && arf_is_neg_inf(y))) { arf_nan(z); return 0; } else if (arf_is_special(x)) { arf_set(z, x); return 0; } else { arf_neg(z, y); return 0; } }
void arf_fprint(FILE * file, const arf_t x) { if (arf_is_normal(x)) { fmpz_t man, exp; fmpz_init(man); fmpz_init(exp); arf_get_fmpz_2exp(man, exp, x); flint_fprintf(file, "("); fmpz_fprint(file, man); flint_fprintf(file, " * 2^"); fmpz_fprint(file, exp); flint_fprintf(file, ")"); fmpz_clear(man); fmpz_clear(exp); } else { if (arf_is_zero(x)) flint_fprintf(file, "(0)"); else if (arf_is_pos_inf(x)) flint_fprintf(file, "(+inf)"); else if (arf_is_neg_inf(x)) flint_fprintf(file, "(-inf)"); else flint_fprintf(file, "(nan)"); } }
void arf_get_fmpr(fmpr_t y, const arf_t x) { if (arf_is_special(x)) { if (arf_is_zero(x)) fmpr_zero(y); else if (arf_is_pos_inf(x)) fmpr_pos_inf(y); else if (arf_is_neg_inf(x)) fmpr_neg_inf(y); else fmpr_nan(y); } else { arf_get_fmpz_2exp(fmpr_manref(y), fmpr_expref(y), x); } }
int arf_cmp_2exp_si(const arf_t x, long e) { if (arf_is_special(x)) { if (arf_is_zero(x)) return -1; if (arf_is_pos_inf(x)) return 1; if (arf_is_neg_inf(x)) return -1; return 0; } if (ARF_SGNBIT(x)) return -1; /* Fast path. */ if (!COEFF_IS_MPZ(ARF_EXP(x))) { if (ARF_IS_POW2(x) && (ARF_EXP(x) - 1 == e)) return 0; else return (ARF_EXP(x) <= e) ? -1 : 1; } if (ARF_IS_POW2(x)) { fmpz_t t; fmpz_init(t); fmpz_one(t); fmpz_add_si(t, t, e); if (fmpz_equal(ARF_EXPREF(x), t)) { fmpz_clear(t); return 0; } fmpz_clear(t); } return (fmpz_cmp_si(ARF_EXPREF(x), e) <= 0) ? -1 : 1; }
int arf_root(arf_ptr z, arf_srcptr x, ulong k, slong prec, arf_rnd_t rnd) { mp_size_t xn, zn, val; mp_srcptr xptr; mp_ptr tmp, zptr; mpfr_t xf, zf; fmpz_t q, r; int inexact; if (k == 0) { arf_nan(z); return 0; } if (k == 1) return arf_set_round(z, x, prec, rnd); if (k == 2) return arf_sqrt(z, x, prec, rnd); if (arf_is_special(x)) { if (arf_is_neg_inf(x)) arf_nan(z); else arf_set(z, x); return 0; } if (ARF_SGNBIT(x)) { arf_nan(z); return 0; } fmpz_init(q); fmpz_init(r); /* x = m * 2^e where e = qk + r */ /* x^(1/k) = (m * 2^(qk+r))^(1/k) */ /* x^(1/k) = (m * 2^r)^(1/k) * 2^q */ fmpz_set_ui(r, k); fmpz_fdiv_qr(q, r, ARF_EXPREF(x), r); ARF_GET_MPN_READONLY(xptr, xn, x); zn = (prec + FLINT_BITS - 1) / FLINT_BITS; zf->_mpfr_d = tmp = flint_malloc(zn * sizeof(mp_limb_t)); zf->_mpfr_prec = prec; zf->_mpfr_sign = 1; zf->_mpfr_exp = 0; xf->_mpfr_d = (mp_ptr) xptr; xf->_mpfr_prec = xn * FLINT_BITS; xf->_mpfr_sign = 1; xf->_mpfr_exp = fmpz_get_ui(r); inexact = mpfr_root(zf, xf, k, arf_rnd_to_mpfr(rnd)); inexact = (inexact != 0); val = 0; while (tmp[val] == 0) val++; ARF_GET_MPN_WRITE(zptr, zn - val, z); flint_mpn_copyi(zptr, tmp + val, zn - val); fmpz_add_si(ARF_EXPREF(z), q, zf->_mpfr_exp); flint_free(tmp); fmpz_clear(q); fmpz_clear(r); return inexact; }
void arb_atan_arf(arb_t z, const arf_t x, slong prec) { if (arf_is_special(x)) { if (arf_is_zero(x)) { arb_zero(z); } else if (arf_is_pos_inf(x)) { arb_const_pi(z, prec); arb_mul_2exp_si(z, z, -1); } else if (arf_is_neg_inf(x)) { arb_const_pi(z, prec); arb_mul_2exp_si(z, z, -1); arb_neg(z, z); } else { arb_indeterminate(z); } } else if (COEFF_IS_MPZ(*ARF_EXPREF(x))) { if (fmpz_sgn(ARF_EXPREF(x)) < 0) arb_atan_eps(z, x, prec); else arb_atan_inf_eps(z, x, prec); } else { slong exp, wp, wn, N, r; mp_srcptr xp; mp_size_t xn, tn; mp_ptr tmp, w, t, u; mp_limb_t p1, q1bits, p2, q2bits, error, error2; int negative, inexact, reciprocal; TMP_INIT; exp = ARF_EXP(x); negative = ARF_SGNBIT(x); if (exp < -(prec/2) - 2 || exp > prec + 2) { if (exp < 0) arb_atan_eps(z, x, prec); else arb_atan_inf_eps(z, x, prec); return; } ARF_GET_MPN_READONLY(xp, xn, x); /* Special case: +/- 1 (we require |x| != 1 later on) */ if (exp == 1 && xn == 1 && xp[xn-1] == LIMB_TOP) { arb_const_pi(z, prec); arb_mul_2exp_si(z, z, -2); if (negative) arb_neg(z, z); return; } /* Absolute working precision (NOT rounded to a limb multiple) */ wp = prec - FLINT_MIN(0, exp) + 4; /* Too high precision to use table */ if (wp > ARB_ATAN_TAB2_PREC) { arb_atan_arf_bb(z, x, prec); return; } /* Working precision in limbs */ wn = (wp + FLINT_BITS - 1) / FLINT_BITS; TMP_START; tmp = TMP_ALLOC_LIMBS(4 * wn + 3); w = tmp; /* requires wn+1 limbs */ t = w + wn + 1; /* requires wn+1 limbs */ u = t + wn + 1; /* requires 2wn+1 limbs */ /* ----------------------------------------------------------------- */ /* Convert x or 1/x to a fixed-point number |w| < 1 */ /* ----------------------------------------------------------------- */ if (exp <= 0) /* |x| < 1 */ { reciprocal = 0; /* todo: just zero top */ flint_mpn_zero(w, wn); /* w = x as a fixed-point number */ error = _arf_get_integer_mpn(w, xp, xn, exp + wn * FLINT_BITS); } else /* |x| > 1 */ { slong one_exp, one_limbs, one_bits; mp_ptr one; reciprocal = 1; one_exp = xn * FLINT_BITS + wn * FLINT_BITS - exp; flint_mpn_zero(w, wn); /* 1/x becomes zero */ if (one_exp >= FLINT_BITS - 1) { /* w = 1/x */ one_limbs = one_exp / FLINT_BITS; one_bits = one_exp % FLINT_BITS; if (one_limbs + 1 >= xn) { one = TMP_ALLOC_LIMBS(one_limbs + 1); flint_mpn_zero(one, one_limbs); one[one_limbs] = UWORD(1) << one_bits; /* todo: only zero necessary part */ flint_mpn_zero(w, wn); mpn_tdiv_q(w, one, one_limbs + 1, xp, xn); /* Now w must be < 1 since x > 1 and we rounded down; thus w[wn] must be zero */ } } /* todo: moderate powers of two would be exact... */ error = 1; } /* ----------------------------------------------------------------- */ /* Table-based argument reduction */ /* ----------------------------------------------------------------- */ /* choose p such that p/q <= x < (p+1)/q */ if (wp <= ARB_ATAN_TAB1_PREC) q1bits = ARB_ATAN_TAB1_BITS; else q1bits = ARB_ATAN_TAB21_BITS; p1 = w[wn-1] >> (FLINT_BITS - q1bits); /* atan(w) = atan(p/q) + atan(w2) */ /* where w2 = (q*w-p)/(q+p*w) */ if (p1 != 0) { t[wn] = (UWORD(1) << q1bits) + mpn_mul_1(t, w, wn, p1); flint_mpn_zero(u, wn); u[2 * wn] = mpn_lshift(u + wn, w, wn, q1bits) - p1; mpn_tdiv_q(w, u, 2 * wn + 1, t, wn + 1); error++; /* w2 is computed with 1 ulp error */ } /* Do a second round of argument reduction */ if (wp <= ARB_ATAN_TAB1_PREC) { p2 = 0; } else { q2bits = ARB_ATAN_TAB21_BITS + ARB_ATAN_TAB22_BITS; p2 = w[wn-1] >> (FLINT_BITS - q2bits); if (p2 != 0) { t[wn] = (UWORD(1) << q2bits) + mpn_mul_1(t, w, wn, p2); flint_mpn_zero(u, wn); u[2 * wn] = mpn_lshift(u + wn, w, wn, q2bits) - p2; mpn_tdiv_q(w, u, 2 * wn + 1, t, wn + 1); error++; } } /* |w| <= 2^-r */ r = _arb_mpn_leading_zeros(w, wn); /* N >= (wp-r)/(2r) */ N = (wp - r + (2*r-1)) / (2*r); /* Evaluate Taylor series */ _arb_atan_taylor_rs(t, &error2, w, wn, N, 1); /* Taylor series evaluation error */ error += error2; /* Size of output number */ tn = wn; /* First table lookup */ if (p1 != 0) { if (wp <= ARB_ATAN_TAB1_PREC) mpn_add_n(t, t, arb_atan_tab1[p1] + ARB_ATAN_TAB1_LIMBS - tn, tn); else mpn_add_n(t, t, arb_atan_tab21[p1] + ARB_ATAN_TAB2_LIMBS - tn, tn); error++; } /* Second table lookup */ if (p2 != 0) { mpn_add_n(t, t, arb_atan_tab22[p2] + ARB_ATAN_TAB2_LIMBS - tn, tn); error++; } /* pi/2 - atan(1/x) */ if (reciprocal) { t[tn] = LIMB_ONE - mpn_sub_n(t, arb_atan_pi2_minus_one + ARB_ATAN_TAB2_LIMBS - tn, t, tn); /* result can be >= 1 */ tn += (t[tn] != 0); /* error of pi/2 */ error++; } /* The accumulated arithmetic error */ mag_set_ui_2exp_si(arb_radref(z), error, -wn * FLINT_BITS); /* Truncation error from the Taylor series */ mag_add_ui_2exp_si(arb_radref(z), arb_radref(z), 1, -r*(2*N+1)); /* Set the midpoint */ inexact = _arf_set_mpn_fixed(arb_midref(z), t, tn, wn, negative, prec, ARB_RND); if (inexact) arf_mag_add_ulp(arb_radref(z), arb_radref(z), arb_midref(z), prec); TMP_END; } }
int arf_sum(arf_t s, arf_srcptr terms, long len, long prec, arf_rnd_t rnd) { arf_ptr blocks; long i, j, used; int have_merged, res; /* first check if the result is inf or nan */ { int have_pos_inf = 0; int have_neg_inf = 0; for (i = 0; i < len; i++) { if (arf_is_pos_inf(terms + i)) { if (have_neg_inf) { arf_nan(s); return 0; } have_pos_inf = 1; } else if (arf_is_neg_inf(terms + i)) { if (have_pos_inf) { arf_nan(s); return 0; } have_neg_inf = 1; } else if (arf_is_nan(terms + i)) { arf_nan(s); return 0; } } if (have_pos_inf) { arf_pos_inf(s); return 0; } if (have_neg_inf) { arf_neg_inf(s); return 0; } } blocks = flint_malloc(sizeof(arf_struct) * len); for (i = 0; i < len; i++) arf_init(blocks + i); /* put all terms into blocks */ used = 0; for (i = 0; i < len; i++) { if (!arf_is_zero(terms + i)) { arf_set(blocks + used, terms + i); used++; } } /* merge blocks until all are well separated */ have_merged = 1; while (used >= 2 && have_merged) { have_merged = 0; for (i = 0; i < used && !have_merged; i++) { for (j = i + 1; j < used && !have_merged; j++) { if (_arf_are_close(blocks + i, blocks + j, prec)) { arf_add(blocks + i, blocks + i, blocks + j, ARF_PREC_EXACT, ARF_RND_DOWN); /* remove the merged block */ arf_swap(blocks + j, blocks + used - 1); used--; /* remove the updated block if the sum is zero */ if (arf_is_zero(blocks + i)) { arf_swap(blocks + i, blocks + used - 1); used--; } have_merged = 1; } } } } if (used == 0) { arf_zero(s); res = 0; } else if (used == 1) { res = arf_set_round(s, blocks + 0, prec, rnd); } else { /* find the two largest blocks */ for (i = 1; i < used; i++) if (arf_cmpabs(blocks + 0, blocks + i) < 0) arf_swap(blocks + 0, blocks + i); for (i = 2; i < used; i++) if (arf_cmpabs(blocks + 1, blocks + i) < 0) arf_swap(blocks + 1, blocks + i); res = _arf_add_eps(s, blocks + 0, arf_sgn(blocks + 1), prec, rnd); } for (i = 0; i < len; i++) arf_clear(blocks + i); flint_free(blocks); return res; }