Exemple #1
0
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);
}
Exemple #2
0
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);
    }
}
Exemple #3
0
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);
    }
}
Exemple #4
0
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);
    }
}
Exemple #5
0
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;
}
Exemple #6
0
void
acb_inv(acb_t res, const acb_t z, slong prec)
{
    mag_t am, bm;
    slong hprec;

#define a arb_midref(acb_realref(z))
#define b arb_midref(acb_imagref(z))
#define x arb_radref(acb_realref(z))
#define y arb_radref(acb_imagref(z))

    /* choose precision for the floating-point approximation of a^2+b^2 so
       that the double rounding result in less than
       2 ulp error; also use at least MAG_BITS bits since the
       value will be recycled for error bounds */
    hprec = FLINT_MAX(prec + 3, MAG_BITS);

    if (arb_is_zero(acb_imagref(z)))
    {
        arb_inv(acb_realref(res), acb_realref(z), prec);
        arb_zero(acb_imagref(res));
        return;
    }

    if (arb_is_zero(acb_realref(z)))
    {
        arb_inv(acb_imagref(res), acb_imagref(z), prec);
        arb_neg(acb_imagref(res), acb_imagref(res));
        arb_zero(acb_realref(res));
        return;
    }

    if (!acb_is_finite(z))
    {
        acb_indeterminate(res);
        return;
    }

    if (mag_is_zero(x) && mag_is_zero(y))
    {
        int inexact;

        arf_t a2b2;
        arf_init(a2b2);

        inexact = arf_sosq(a2b2, a, b, hprec, ARF_RND_DOWN);

        if (arf_is_special(a2b2))
        {
            acb_indeterminate(res);
        }
        else
        {
            _arb_arf_div_rounded_den(acb_realref(res), a, a2b2, inexact, prec);
            _arb_arf_div_rounded_den(acb_imagref(res), b, a2b2, inexact, prec);
            arf_neg(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(res)));
        }

        arf_clear(a2b2);
        return;
    }

    mag_init(am);
    mag_init(bm);

    /* first bound |a|-x, |b|-y */
    arb_get_mag_lower(am, acb_realref(z));
    arb_get_mag_lower(bm, acb_imagref(z));

    if ((mag_is_zero(am) && mag_is_zero(bm)))
    {
        acb_indeterminate(res);
    }
    else
    {
        /*
        The propagated error in the real part is given exactly by

             (a+x')/((a+x')^2+(b+y'))^2 - a/(a^2+b^2) = P / Q,

             P = [(b^2-a^2) x' - a (x'^2+y'^2 + 2y'b)]
             Q = [(a^2+b^2)((a+x')^2+(b+y')^2)]

        where |x'| <= x and |y'| <= y, and analogously for the imaginary part.
        */
        mag_t t, u, v, w;
        arf_t a2b2;
        int inexact;

        mag_init(t);
        mag_init(u);
        mag_init(v);
        mag_init(w);

        arf_init(a2b2);

        inexact = arf_sosq(a2b2, a, b, hprec, ARF_RND_DOWN);

        /* compute denominator */
        /* t = (|a|-x)^2 + (|b|-x)^2 (lower bound) */
        mag_mul_lower(t, am, am);
        mag_mul_lower(u, bm, bm);
        mag_add_lower(t, t, u);
        /* u = a^2 + b^2 (lower bound) */
        arf_get_mag_lower(u, a2b2);
        /* t = ((|a|-x)^2 + (|b|-x)^2)(a^2 + b^2) (lower bound) */
        mag_mul_lower(t, t, u);

        /* compute numerator */
        /* real: |a^2-b^2| x  + |a| ((x^2 + y^2) + 2 |b| y)) */
        /* imag: |a^2-b^2| y  + |b| ((x^2 + y^2) + 2 |a| x)) */
        /* am, bm = upper bounds for a, b */
        arf_get_mag(am, a);
        arf_get_mag(bm, b);

        /* v = x^2 + y^2 */
        mag_mul(v, x, x);
        mag_addmul(v, y, y);

        /* u = |a| ((x^2 + y^2) + 2 |b| y) */
        mag_mul_2exp_si(u, bm, 1);
        mag_mul(u, u, y);
        mag_add(u, u, v);
        mag_mul(u, u, am);

        /* v = |b| ((x^2 + y^2) + 2 |a| x) */
        mag_mul_2exp_si(w, am, 1);
        mag_addmul(v, w, x);
        mag_mul(v, v, bm);

        /* w = |b^2 - a^2| (upper bound) */
        if (arf_cmpabs(a, b) >= 0)
            mag_mul(w, am, am);
        else
            mag_mul(w, bm, bm);

        mag_addmul(u, w, x);
        mag_addmul(v, w, y);

        mag_div(arb_radref(acb_realref(res)), u, t);
        mag_div(arb_radref(acb_imagref(res)), v, t);

        _arb_arf_div_rounded_den_add_err(acb_realref(res), a, a2b2, inexact, prec);
        _arb_arf_div_rounded_den_add_err(acb_imagref(res), b, a2b2, inexact, prec);
        arf_neg(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(res)));

        mag_clear(t);
        mag_clear(u);
        mag_clear(v);
        mag_clear(w);

        arf_clear(a2b2);
    }

    mag_clear(am);
    mag_clear(bm);
#undef a
#undef b
#undef x
#undef y
}