Example #1
0
File: add.c Project: argriffing/arb
int
arf_add(arf_ptr z, arf_srcptr x, arf_srcptr y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn;
    mp_srcptr xptr, yptr;
    slong shift;

    if (arf_is_special(x) || arf_is_special(y))
    {
        return arf_add_special(z, x, y, prec, rnd);
    }

    shift = _fmpz_sub_small(ARF_EXPREF(x), ARF_EXPREF(y));

    if (shift < 0)
    {
        arf_srcptr __t;
        __t = x; x = y; y = __t;
        shift = -shift;
    }

    ARF_GET_MPN_READONLY(xptr, xn, x);
    ARF_GET_MPN_READONLY(yptr, yn, y);

    return _arf_add_mpn(z, xptr, xn, ARF_SGNBIT(x), ARF_EXPREF(x),
                           yptr, yn, ARF_SGNBIT(y), shift, prec, rnd);
}
Example #2
0
slong
fmpr_add_naive(fmpr_t z, const fmpr_t x, const fmpr_t y, slong prec, fmpr_rnd_t rnd)
{
    slong shift, xsize, ysize;

    if (fmpr_is_special(x) || fmpr_is_special(y))
    {
        return _fmpr_add_special(z, x, y, prec, rnd);
    }

    shift = _fmpz_sub_small(fmpr_expref(x), fmpr_expref(y));

    if (shift == 0)
    {
        fmpz_add(fmpr_manref(z), fmpr_manref(x), fmpr_manref(y));
        fmpz_set(fmpr_expref(z), fmpr_expref(x));
    }
    else if (shift > 0)
    {
        ysize = _fmpz_size(fmpr_manref(y)) * FLINT_BITS;

        /* x and y do not overlap */
        if (shift > ysize && prec != FMPR_PREC_EXACT)
        {
            /* y does not overlap with result */
            if (ysize + prec - (slong) fmpz_bits(fmpr_manref(x)) < shift)
            {
                return _fmpr_add_eps(z, x, fmpz_sgn(fmpr_manref(y)), prec, rnd);
            }
        }

        fmpz_add_mul2exp(fmpr_manref(z), fmpr_manref(y), fmpr_manref(x), shift);
        fmpz_set(fmpr_expref(z), fmpr_expref(y));
    }
    else
    {
        shift = -shift;

        xsize = _fmpz_size(fmpr_manref(x)) * FLINT_BITS;

        /* x and y do not overlap */
        if (shift > xsize && prec != FMPR_PREC_EXACT)
        {
            /* y does not overlap with result */
            if (xsize + prec - (slong) fmpz_bits(fmpr_manref(y)) < shift)
            {
                return _fmpr_add_eps(z, y, fmpz_sgn(fmpr_manref(x)), prec, rnd);
            }
        }

        fmpz_add_mul2exp(fmpr_manref(z), fmpr_manref(x), fmpr_manref(y), shift);
        fmpz_set(fmpr_expref(z), fmpr_expref(x));
    }

    return _fmpr_normalise(fmpr_manref(z), fmpr_expref(z), prec, rnd);
}
Example #3
0
File: sub.c Project: argriffing/arb
slong
fmpr_sub(fmpr_t z, const fmpr_t x, const fmpr_t y, slong prec, fmpr_rnd_t rnd)
{
    slong shift, xn, yn;
    mp_limb_t xtmp, ytmp;
    mp_ptr xptr, yptr;
    fmpz xv, yv;
    const fmpz * xexp;
    const fmpz * yexp;
    int xsign, ysign;

    if (fmpr_is_special(x) || fmpr_is_special(y))
    {
        return _fmpr_sub_special(z, x, y, prec, rnd);
    }

    shift = _fmpz_sub_small(fmpr_expref(y), fmpr_expref(x));

    if (shift >= 0)
    {
        xexp = fmpr_expref(x);
        yexp = fmpr_expref(y);
        xv = *fmpr_manref(x);
        yv = *fmpr_manref(y);
    }
    else
    {
        xexp = fmpr_expref(y);
        yexp = fmpr_expref(x);
        xv = *fmpr_manref(y);
        yv = *fmpr_manref(x);
    }

    FMPZ_GET_MPN_READONLY(xsign, xn, xptr, xtmp, xv)
    FMPZ_GET_MPN_READONLY(ysign, yn, yptr, ytmp, yv)

    if (shift >= 0)
    {
        ysign = !ysign;
    }
    else
    {
        shift = -shift;
        xsign = !xsign;
    }

    if ((xn == 1) && (yn == 1) && (shift < FLINT_BITS))
        return _fmpr_add_1x1(z, xptr[0], xsign, xexp, yptr[0], ysign, yexp, shift, prec, rnd);
    else
        return _fmpr_add_mpn(z, xptr, xn, xsign, xexp, yptr, yn, ysign, yexp, shift, prec, rnd);
}
Example #4
0
File: sub.c Project: isuruf/arb
int
arf_sub_si(arf_ptr z, arf_srcptr x, slong y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn;
    mp_srcptr xptr, yptr;
    mp_limb_t ytmp;
    int xsgnbit, ysgnbit;
    fmpz yexp;
    slong shift;

    if (y == 0)
    {
        return arf_set_round(z, x, prec, rnd);
    }
    else if (arf_is_special(x))
    {
        if (arf_is_zero(x))
        {
            arf_set_si(z, y);
            return arf_neg_round(z, z, prec, rnd);
        }
        else
        {
            arf_set(z, x);
            return 0;
        }
    }

    ysgnbit = (y < 0);
    if (ysgnbit)
        ytmp = -y;
    else
        ytmp = y;
    yptr = &ytmp;
    yn = 1;
    yexp = FLINT_BITS;
    ysgnbit ^= 1;

    shift = _fmpz_sub_small(ARF_EXPREF(x), &yexp);

    xsgnbit = ARF_SGNBIT(x);
    ARF_GET_MPN_READONLY(xptr, xn, x);

    if (shift >= 0)
        return _arf_add_mpn(z, xptr, xn, xsgnbit, ARF_EXPREF(x),
                               yptr, yn, ysgnbit, shift, prec, rnd);
    else
        return _arf_add_mpn(z, yptr, yn, ysgnbit, &yexp,
                               xptr, xn, xsgnbit, -shift, prec, rnd);
}
Example #5
0
File: add.c Project: argriffing/arb
int
arf_add_fmpz_2exp(arf_ptr z, arf_srcptr x, const fmpz_t y, const fmpz_t exp, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn;
    mp_srcptr xptr, yptr;
    mp_limb_t ytmp;
    int xsgnbit, ysgnbit, inexact;
    fmpz_t yexp;
    slong shift;

    if (fmpz_is_zero(y))
    {
        return arf_set_round(z, x, prec, rnd);
    }
    else if (arf_is_special(x))
    {
        if (arf_is_zero(x))
        {
            inexact = arf_set_round_fmpz(z, y, prec, rnd);
            arf_mul_2exp_fmpz(z, z, exp);
            return inexact;
        }
        else
        {
            arf_set(z, x);
            return 0;
        }
    }

    FMPZ_GET_MPN_READONLY(ysgnbit, yn, yptr, ytmp, *y)
    fmpz_init(yexp);
    fmpz_add_ui(yexp, exp, yn * FLINT_BITS);
    shift = _fmpz_sub_small(ARF_EXPREF(x), yexp);

    xsgnbit = ARF_SGNBIT(x);
    ARF_GET_MPN_READONLY(xptr, xn, x);

    if (shift >= 0)
        inexact = _arf_add_mpn(z, xptr, xn, xsgnbit, ARF_EXPREF(x),
                               yptr, yn, ysgnbit, shift, prec, rnd);
    else
        inexact = _arf_add_mpn(z, yptr, yn, ysgnbit, yexp,
                               xptr, xn, xsgnbit, -shift, prec, rnd);

    fmpz_clear(yexp);
    return inexact;
}
Example #6
0
File: sub.c Project: isuruf/arb
int
arf_sub_fmpz(arf_ptr z, arf_srcptr x, const fmpz_t y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn;
    mp_srcptr xptr, yptr;
    mp_limb_t ytmp;
    int xsgnbit, ysgnbit;
    fmpz yexp;
    slong shift;

    if (fmpz_is_zero(y))
    {
        return arf_set_round(z, x, prec, rnd);
    }
    else if (arf_is_special(x))
    {
        if (arf_is_zero(x))
        {
            arf_set_fmpz(z, y);
            return arf_neg_round(z, z, prec, rnd);
        }
        else
        {
            arf_set(z, x);
            return 0;
        }
    }

    FMPZ_GET_MPN_READONLY(ysgnbit, yn, yptr, ytmp, *y)
    yexp = yn * FLINT_BITS;
    shift = _fmpz_sub_small(ARF_EXPREF(x), &yexp);
    ysgnbit ^= 1;

    xsgnbit = ARF_SGNBIT(x);
    ARF_GET_MPN_READONLY(xptr, xn, x);

    if (shift >= 0)
        return _arf_add_mpn(z, xptr, xn, xsgnbit, ARF_EXPREF(x),
                               yptr, yn, ysgnbit, shift, prec, rnd);
    else
        return _arf_add_mpn(z, yptr, yn, ysgnbit, &yexp,
                               xptr, xn, xsgnbit, -shift, prec, rnd);
}
Example #7
0
void
fmprb_get_interval_fmpz_2exp(fmpz_t a, fmpz_t b, fmpz_t exp, const fmprb_t x)
{

    if (fmprb_is_exact(x))
    {
        fmpr_get_fmpz_2exp(a, exp, fmprb_midref(x));
        fmpz_set(b, a);
    }
    else
    {
        fmpr_t t;
        fmpz_t exp2;
        slong s;

        fmpr_init(t);
        fmpz_init(exp2);

        fmpr_sub(t, fmprb_midref(x), fmprb_radref(x), FMPR_PREC_EXACT, FMPR_RND_DOWN);
        fmpr_get_fmpz_2exp(a, exp, t);

        fmpr_add(t, fmprb_midref(x), fmprb_radref(x), FMPR_PREC_EXACT, FMPR_RND_DOWN);
        fmpr_get_fmpz_2exp(b, exp2, t);

        s = _fmpz_sub_small(exp, exp2);

        if (s <= 0)
        {
            fmpz_mul_2exp(b, b, -s);
        }
        else
        {
            fmpz_mul_2exp(a, a, s);
            fmpz_set(exp, exp2);
        }

        fmpr_clear(t);
        fmpz_clear(exp2);
    }
}
Example #8
0
File: sub.c Project: isuruf/arb
int
arf_sub(arf_ptr z, arf_srcptr x, arf_srcptr y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn;
    mp_srcptr xptr, yptr;
    slong shift;

    if (arf_is_special(x) || arf_is_special(y))
    {
        return arf_sub_special(z, x, y, prec, rnd);
    }

    shift = _fmpz_sub_small(ARF_EXPREF(x), ARF_EXPREF(y));

    ARF_GET_MPN_READONLY(xptr, xn, x);
    ARF_GET_MPN_READONLY(yptr, yn, y);

    if (shift >= 0)
        return _arf_add_mpn(z, xptr, xn, ARF_SGNBIT(x), ARF_EXPREF(x),
                           yptr, yn, ARF_SGNBIT(y) ^ 1, shift, prec, rnd);
    else
        return _arf_add_mpn(z, yptr, yn, ARF_SGNBIT(y) ^ 1, ARF_EXPREF(y),
                           xptr, xn, ARF_SGNBIT(x), -shift, prec, rnd);
}
Example #9
0
static __inline__ void
_mag_vec_get_fmpz_2exp_blocks(fmpz * coeffs,
                              double * dblcoeffs, fmpz * exps, slong * blocks, const fmpz_t scale,
                              arb_srcptr x, mag_srcptr xm, slong len)
{
    fmpz_t top, bot, t, b, v, block_top, block_bot;
    slong i, j, s, block, bits, maxheight;
    int in_zero;
    mag_srcptr cur;

    fmpz_init(top);
    fmpz_init(bot);
    fmpz_init(t);
    fmpz_init(b);
    fmpz_init(v);
    fmpz_init(block_top);
    fmpz_init(block_bot);

    blocks[0] = 0;
    block = 0;
    in_zero = 1;

    maxheight = ALPHA * MAG_BITS + BETA;
    if (maxheight > DOUBLE_BLOCK_MAX_HEIGHT)
        abort();

    for (i = 0; i < len; i++)
    {
        cur = (x == NULL) ? (xm + i) : arb_radref(x + i);

        /* Skip (must be zero, since we assume there are no Infs/NaNs). */
        if (mag_is_special(cur))
            continue;

        /* Bottom and top exponent of current number */
        bits = MAG_BITS;
        fmpz_set(top, MAG_EXPREF(cur));
        fmpz_submul_ui(top, scale, i);
        fmpz_sub_ui(bot, top, bits);

        /* Extend current block. */
        if (in_zero)
        {
            fmpz_swap(block_top, top);
            fmpz_swap(block_bot, bot);
        }
        else
        {
            fmpz_max(t, top, block_top);
            fmpz_min(b, bot, block_bot);
            fmpz_sub(v, t, b);

            /* extend current block */
            if (fmpz_cmp_ui(v, maxheight) < 0)
            {
                fmpz_swap(block_top, t);
                fmpz_swap(block_bot, b);
            }
            else  /* start new block */
            {
                /* write exponent for previous block */
                fmpz_set(exps + block, block_bot);

                block++;
                blocks[block] = i;

                fmpz_swap(block_top, top);
                fmpz_swap(block_bot, bot);
            }
        }

        in_zero = 0;
    }

    /* write exponent for last block */
    fmpz_set(exps + block, block_bot);

    /* end marker */
    blocks[block + 1] = len;

    /* write the block data */
    for (i = 0; blocks[i] != len; i++)
    {
        for (j = blocks[i]; j < blocks[i + 1]; j++)
        {
            cur = (x == NULL) ? (xm + j) : arb_radref(x + j);

            if (mag_is_special(cur))
            {
                fmpz_zero(coeffs + j);
                dblcoeffs[j] = 0.0;
            }
            else
            {
                mp_limb_t man;
                double c;

                man = MAG_MAN(cur);

                /* TODO: only write and use doubles when block is short? */

                /* Divide by 2^(scale * j) */
                fmpz_mul_ui(t, scale, j);
                fmpz_sub(t, MAG_EXPREF(cur), t);

                fmpz_sub_ui(t, t, MAG_BITS); /* bottom exponent */
                s = _fmpz_sub_small(t, exps + i);

                if (s < 0) abort(); /* Bug catcher */

                fmpz_set_ui(coeffs + j, man);
                fmpz_mul_2exp(coeffs + j, coeffs + j, s);
                c = man;
                c = ldexp(c, s - DOUBLE_BLOCK_SHIFT);
                if (c < 1e-150 || c > 1e150) /* Bug catcher */
                    abort();
                dblcoeffs[j] = c;
            }
        }
    }

    fmpz_clear(top);
    fmpz_clear(bot);
    fmpz_clear(t);
    fmpz_clear(b);
    fmpz_clear(v);
    fmpz_clear(block_top);
    fmpz_clear(block_bot);
}
Example #10
0
static __inline__ void
_arb_vec_get_fmpz_2exp_blocks(fmpz * coeffs, fmpz * exps,
                              slong * blocks, const fmpz_t scale, arb_srcptr x, slong len, slong prec)
{
    fmpz_t top, bot, t, b, v, block_top, block_bot;
    slong i, j, s, block, bits, maxheight;
    int in_zero;

    fmpz_init(top);
    fmpz_init(bot);
    fmpz_init(t);
    fmpz_init(b);
    fmpz_init(v);
    fmpz_init(block_top);
    fmpz_init(block_bot);

    blocks[0] = 0;
    block = 0;
    in_zero = 1;

    if (prec == ARF_PREC_EXACT)
        maxheight = ARF_PREC_EXACT;
    else
        maxheight = ALPHA * prec + BETA;

    for (i = 0; i < len; i++)
    {
        bits = arf_bits(arb_midref(x + i));

        /* Skip (must be zero, since we assume there are no Infs/NaNs). */
        if (bits == 0)
            continue;

        /* Bottom and top exponent of current number */
        fmpz_set(top, ARF_EXPREF(arb_midref(x + i)));
        fmpz_submul_ui(top, scale, i);
        fmpz_sub_ui(bot, top, bits);

        /* Extend current block. */
        if (in_zero)
        {
            fmpz_swap(block_top, top);
            fmpz_swap(block_bot, bot);
        }
        else
        {
            fmpz_max(t, top, block_top);
            fmpz_min(b, bot, block_bot);
            fmpz_sub(v, t, b);

            /* extend current block */
            if (fmpz_cmp_ui(v, maxheight) < 0)
            {
                fmpz_swap(block_top, t);
                fmpz_swap(block_bot, b);
            }
            else  /* start new block */
            {
                /* write exponent for previous block */
                fmpz_set(exps + block, block_bot);

                block++;
                blocks[block] = i;

                fmpz_swap(block_top, top);
                fmpz_swap(block_bot, bot);
            }
        }

        in_zero = 0;
    }

    /* write exponent for last block */
    fmpz_set(exps + block, block_bot);

    /* end marker */
    blocks[block + 1] = len;

    /* write the block data */
    for (i = 0; blocks[i] != len; i++)
    {
        for (j = blocks[i]; j < blocks[i + 1]; j++)
        {
            if (arf_is_special(arb_midref(x + j)))
            {
                fmpz_zero(coeffs + j);
            }
            else
            {
                /* TODO: make this a single operation */
                arf_get_fmpz_2exp(coeffs + j, bot, arb_midref(x + j));

                fmpz_mul_ui(t, scale, j);
                fmpz_sub(t, bot, t);
                s = _fmpz_sub_small(t, exps + i);
                if (s < 0) abort(); /* Bug catcher */
                fmpz_mul_2exp(coeffs + j, coeffs + j, s);
            }
        }
    }

    fmpz_clear(top);
    fmpz_clear(bot);
    fmpz_clear(t);
    fmpz_clear(b);
    fmpz_clear(v);
    fmpz_clear(block_top);
    fmpz_clear(block_bot);
}
Example #11
0
/* convert to an fmpz poly with a common exponent and coefficients
   at most prec bits, also bounding input error plus rounding error */
void _fmprb_poly_get_fmpz_poly_2exp(fmpr_t error, fmpz_t exp, fmpz  * coeffs,
                            fmprb_srcptr A, long lenA, long prec)
{
    fmpz_t top_exp, bot_exp;
    long shift;
    long i;
    int rounding;

    fmpz_init(top_exp);
    fmpz_init(bot_exp);

    if (!_fmprb_poly_mid_get_hull(bot_exp, top_exp, A, lenA))
    {
        fmpz_zero(exp);
        _fmpz_vec_zero(coeffs, lenA);
        fmpr_zero(error);
        for (i = 0; i < lenA; i++)
        {
            if (fmpr_cmp(fmprb_radref(A + i), error) > 0)
                fmpr_set(error, fmprb_radref(A + i));
        }

        return;   /* no need to clear fmpzs */
    }

    /* only take as much precision as necessary */
    shift = _fmpz_sub_small(top_exp, bot_exp);
    prec = FLINT_MIN(prec, shift);

    fmpz_sub_ui(exp, top_exp, prec);

    /* extract integer polynomial */
    rounding = 0;
    for (i = 0; i < lenA; i++)
        rounding |= fmpr_get_fmpz_fixed_fmpz(coeffs + i,
                        fmprb_midref(A + i), exp);

    fmpr_zero(error);

    /* compute maximum of input errors */
    for (i = 0; i < lenA; i++)
    {
        if (fmpr_cmp(fmprb_radref(A + i), error) > 0)
            fmpr_set(error, fmprb_radref(A + i));
    }

    /* add rounding error */
    if (rounding)
    {
        fmpr_t t;
        fmpr_init(t);

        fmpz_set_ui(fmpr_manref(t), 1UL);
        fmpz_set(fmpr_expref(t), exp);

        fmpr_add(error, error, t, FMPRB_RAD_PREC, FMPR_RND_UP);

        fmpr_clear(t);
    }

    fmpz_clear(top_exp);
}
Example #12
0
File: submul.c Project: isuruf/arb
int
arf_submul_mpz(arf_ptr z, arf_srcptr x, const mpz_t y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn, zn, tn, alloc;
    mp_srcptr xptr, yptr, zptr;
    mp_ptr tptr, tptr2;
    fmpz_t texp, yexp;
    slong shift;
    int tsgnbit, ysgnbit, inexact;
    ARF_MUL_TMP_DECL

    yn = FLINT_ABS(y->_mp_size);

    if (arf_is_special(x) || yn == 0 || arf_is_special(z))
    {
        if (arf_is_zero(z))
        {
            /* TODO: make more efficient */
            arf_mul_mpz(z, x, y, ARF_PREC_EXACT, rnd);
            return arf_neg_round(z, z, prec, rnd);
        }
        else if (arf_is_finite(x))
        {
            return arf_set_round(z, z, prec, rnd);
        }
        else
        {
            /* todo: speed up */
            arf_t t;
            arf_init(t);
            arf_mul_mpz(t, x, y, ARF_PREC_EXACT, ARF_RND_DOWN);
            inexact = arf_sub(z, z, t, prec, rnd);
            arf_clear(t);
            return inexact;
        }
    }

    ARF_GET_MPN_READONLY(xptr, xn, x);

    yptr = y->_mp_d;
    ysgnbit = (y->_mp_size > 0);
    *yexp = yn * FLINT_BITS;

    ARF_GET_MPN_READONLY(zptr, zn, z);

    fmpz_init(texp);

    tsgnbit = ARF_SGNBIT(x) ^ ysgnbit;

    alloc = tn = xn + yn;
    ARF_MUL_TMP_ALLOC(tptr2, alloc)
    tptr = tptr2;

    ARF_MPN_MUL(tptr, xptr, xn, yptr, yn);

    shift = (tptr[tn - 1] == 0) * FLINT_BITS;
    tn -= (tptr[tn - 1] == 0);

    _fmpz_add2_fast(texp, ARF_EXPREF(x), yexp, -shift);
    shift = _fmpz_sub_small(ARF_EXPREF(z), texp);

    if (shift >= 0)
        inexact = _arf_add_mpn(z, zptr, zn, ARF_SGNBIT(z), ARF_EXPREF(z),
            tptr, tn, tsgnbit, shift, prec, rnd);
    else
        inexact = _arf_add_mpn(z, tptr, tn, tsgnbit, texp,
            zptr, zn, ARF_SGNBIT(z), -shift, prec, rnd);

    ARF_MUL_TMP_FREE(tptr2, alloc)
    fmpz_clear(texp);

    return inexact;
}
Example #13
0
File: submul.c Project: isuruf/arb
int
arf_submul(arf_ptr z, arf_srcptr x, arf_srcptr y, slong prec, arf_rnd_t rnd)
{
    mp_size_t xn, yn, zn, tn, alloc;
    mp_srcptr xptr, yptr, zptr;
    mp_ptr tptr, tptr2;
    fmpz_t texp;
    slong shift;
    int tsgnbit, inexact;
    ARF_MUL_TMP_DECL

    if (arf_is_special(x) || arf_is_special(y) || arf_is_special(z))
    {
        if (arf_is_zero(z))
        {
            return arf_neg_mul(z, x, y, prec, rnd);
        }
        else if (arf_is_finite(x) && arf_is_finite(y))
        {
            return arf_set_round(z, z, prec, rnd);
        }
        else
        {
            /* todo: speed up */
            arf_t t;
            arf_init(t);
            arf_mul(t, x, y, ARF_PREC_EXACT, ARF_RND_DOWN);
            inexact = arf_sub(z, z, t, prec, rnd);
            arf_clear(t);
            return inexact;
        }
    }

    tsgnbit = ARF_SGNBIT(x) ^ ARF_SGNBIT(y) ^ 1;
    ARF_GET_MPN_READONLY(xptr, xn, x);
    ARF_GET_MPN_READONLY(yptr, yn, y);
    ARF_GET_MPN_READONLY(zptr, zn, z);

    fmpz_init(texp);

    _fmpz_add2_fast(texp, ARF_EXPREF(x), ARF_EXPREF(y), 0);
    shift = _fmpz_sub_small(ARF_EXPREF(z), texp);

    alloc = tn = xn + yn;
    ARF_MUL_TMP_ALLOC(tptr2, alloc)
    tptr = tptr2;

    ARF_MPN_MUL(tptr, xptr, xn, yptr, yn);

    tn -= (tptr[0] == 0);
    tptr += (tptr[0] == 0);

    if (shift >= 0)
        inexact = _arf_add_mpn(z, zptr, zn, ARF_SGNBIT(z), ARF_EXPREF(z),
            tptr, tn, tsgnbit, shift, prec, rnd);
    else
        inexact = _arf_add_mpn(z, tptr, tn, tsgnbit, texp,
            zptr, zn, ARF_SGNBIT(z), -shift, prec, rnd);

    ARF_MUL_TMP_FREE(tptr2, alloc)
    fmpz_clear(texp);

    return inexact;
}
Example #14
0
void
_arb_bell_sum_taylor(arb_t res, const fmpz_t n,
        const fmpz_t a, const fmpz_t b, const fmpz_t mmag, long tol)
{
    fmpz_t m, r, R, tmp;
    mag_t B, C, D, bound;
    arb_t t, u;
    long wp, k, N;

    if (_fmpz_sub_small(b, a) < 5)
    {
        arb_bell_sum_bsplit(res, n, a, b, mmag, tol);
        return;
    }

    fmpz_init(m);
    fmpz_init(r);
    fmpz_init(R);
    fmpz_init(tmp);

    /* r = max(m - a, b - m) */
    /* m = a + (b - a) / 2 */
    fmpz_sub(r, b, a);
    fmpz_cdiv_q_2exp(r, r, 1);
    fmpz_add(m, a, r);

    fmpz_mul_2exp(R, r, RADIUS_BITS);

    mag_init(B);
    mag_init(C);
    mag_init(D);
    mag_init(bound);

    arb_init(t);
    arb_init(u);

    if (fmpz_cmp(R, m) >= 0)
    {
        mag_inf(C);
        mag_inf(D);
    }
    else
    {
        /* C = exp(R * |F'(m)| + (1/2) R^2 * (n/(m-R)^2 + 1/(m-R))) */
        /* C = exp(R * (|F'(m)| + (1/2) R * (n/(m-R) + 1)/(m-R))) */
        /* D = (1/2) R * (n/(m-R) + 1)/(m-R) */
        fmpz_sub(tmp, m, R);
        mag_set_fmpz(D, n);
        mag_div_fmpz(D, D, tmp);
        mag_one(C);
        mag_add(D, D, C);
        mag_div_fmpz(D, D, tmp);
        mag_mul_fmpz(D, D, R);
        mag_mul_2exp_si(D, D, -1);

        /* C = |F'(m)| */
        wp = 20 + 1.05 * fmpz_bits(n);
        arb_set_fmpz(t, n);
        arb_div_fmpz(t, t, m, wp);
        fmpz_add_ui(tmp, m, 1);
        arb_set_fmpz(u, tmp);
        arb_digamma(u, u, wp);
        arb_sub(t, t, u, wp);
        arb_get_mag(C, t);

        /* C = exp(R * (C + D)) */
        mag_add(C, C, D);
        mag_mul_fmpz(C, C, R);
        mag_exp(C, C);
    }

    if (mag_cmp_2exp_si(C, tol / 4 + 2) > 0)
    {
        _arb_bell_sum_taylor(res, n, a, m, mmag, tol);
        _arb_bell_sum_taylor(t, n, m, b, mmag, tol);
        arb_add(res, res, t, 2 * tol);
    }
    else
    {
        arb_ptr mx, ser1, ser2, ser3;

        /* D = T(m) */
        wp = 20 + 1.05 * fmpz_bits(n);
        arb_set_fmpz(t, m);
        arb_pow_fmpz(t, t, n, wp);
        fmpz_add_ui(tmp, m, 1);
        arb_gamma_fmpz(u, tmp, wp);
        arb_div(t, t, u, wp);
        arb_get_mag(D, t);

        /* error bound: (b-a) * C * D * B^N / (1 - B), B = r/R */
        /*              ((b-a) * C * D * 2) * 2^(-N*RADIUS_BITS) */

        /* ((b-a) * C * D * 2) */
        mag_mul(bound, C, D);
        mag_mul_2exp_si(bound, bound, 1);
        fmpz_sub(tmp, b, a);
        mag_mul_fmpz(bound, bound, tmp);

        /* N = (tol + log2((b-a)*C*D*2) - mmag) / RADIUS_BITS */
        if (mmag == NULL)
        {
            /* estimate D ~= 2^mmag */
            fmpz_add_ui(tmp, MAG_EXPREF(C), tol);
            fmpz_cdiv_q_ui(tmp, tmp, RADIUS_BITS);
        }
        else
        {
            fmpz_sub(tmp, MAG_EXPREF(bound), mmag);
            fmpz_add_ui(tmp, tmp, tol);
            fmpz_cdiv_q_ui(tmp, tmp, RADIUS_BITS);
        }

        if (fmpz_cmp_ui(tmp, 5 * tol / 4) > 0)
            N = 5 * tol / 4;
        else if (fmpz_cmp_ui(tmp, 2) < 0)
            N = 2;
        else
            N = fmpz_get_ui(tmp);

        /* multiply by 2^(-N*RADIUS_BITS) */
        mag_mul_2exp_si(bound, bound, -N * RADIUS_BITS);

        mx = _arb_vec_init(2);
        ser1 = _arb_vec_init(N);
        ser2 = _arb_vec_init(N);
        ser3 = _arb_vec_init(N);

        /* estimate (this should work for moderate n and tol) */
        wp = 1.1 * tol + 1.05 * fmpz_bits(n) + 5;

        /* increase precision until convergence */
        while (1)
        {
            /* (m+x)^n / gamma(m+1+x) */
            arb_set_fmpz(mx, m);
            arb_one(mx + 1);
            _arb_poly_log_series(ser1, mx, 2, N, wp);
            for (k = 0; k < N; k++)
                arb_mul_fmpz(ser1 + k, ser1 + k, n, wp);
            arb_add_ui(mx, mx, 1, wp);
            _arb_poly_lgamma_series(ser2, mx, 2, N, wp);
            _arb_vec_sub(ser1, ser1, ser2, N, wp);
            _arb_poly_exp_series(ser3, ser1, N, N, wp);

            /* t = a - m, u = b - m */
            arb_set_fmpz(t, a);
            arb_sub_fmpz(t, t, m, wp);
            arb_set_fmpz(u, b);
            arb_sub_fmpz(u, u, m, wp);
            arb_power_sum_vec(ser1, t, u, N, wp);

            arb_zero(res);
            for (k = 0; k < N; k++)
                arb_addmul(res, ser3 + k, ser1 + k, wp);

            if (mmag != NULL)
            {
                if (_fmpz_sub_small(MAG_EXPREF(arb_radref(res)), mmag) <= -tol)
                    break;
            }
            else
            {
                if (arb_rel_accuracy_bits(res) >= tol)
                    break;
            }

            wp = 2 * wp;
        }

        /* add the series truncation bound */
        arb_add_error_mag(res, bound);

        _arb_vec_clear(mx, 2);
        _arb_vec_clear(ser1, N);
        _arb_vec_clear(ser2, N);
        _arb_vec_clear(ser3, N);
    }

    mag_clear(B);
    mag_clear(C);
    mag_clear(D);
    mag_clear(bound);
    arb_clear(t);
    arb_clear(u);

    fmpz_clear(m);
    fmpz_clear(r);
    fmpz_clear(R);
    fmpz_clear(tmp);
}