Skip to content

arb_pow could do much better for <a +- a> ^ <b +- c> with b >= c > 0 and a > 0 #444

@postmath

Description

@postmath

Consider arb_pow(z, x, y, prec) with x = <a +- a> and y nonnegative. This works as I would expect for x=0, and also for exact half integers y, including y = 0. But if a > 0 and y is not an exact half integer, then arb_pow returns a non-finite answer (because it takes the logarithm of x, then multiplies by y, then takes the exponential; but we can't represent the half-infinite interval that the logarithm requires), whereas there is a finite answer. I propose to do roughly this, after all existing special cases have been done:

    if(arf_cmp_si(arb_midref(x), 0) > 0
        && arf_cmpabs_mag(arb_midref(x), arb_radref(x)) == 0
        && arb_is_nonnegative(y)) {
        /* x is an interval of the form <a +- a>, y is an interval of the form <b +- c> with b >=
          c. 

          (x, y) -> x^y is nondecreasing in x for y >= 0, and it is 0 for x=0 and y>0.  The lower
          bound of the interval for x is 0, and we have points with y>0 (because the case
          arb_is_zero(y) is excluded above). So the lowerbound of the result is 0, and the
          upperbound can be found somewhere at (2*a)^y.

          We compute this upperbound by computing z^y with z = < 3*a/2 +- a/2 >, which has the same
          upperbound (2*a) as x, then keeping the upper bound of this result and setting the lower
          bound to 0. This necessarily drops the precision to MAG_BITS, so we might as well do that
          from the start. */
        prec = (prec > MAG_BITS) ? MAG_BITS : prec;
        arf_mul_ui(arb_midref(z), arb_midref(x), 3, prec, ARF_RND_UP);
        arf_mul_2exp_si(arb_midref(z), arb_midref(z), -1);
        mag_mul_2exp_si(arb_radref(z), arb_radref(x), -1);

        arb_pow(z, z, y);

        /* Now we keep the upper bound of z (we may need to round up) and set the lower bound to
           zero. That is, if currently, z = < zc +/- zr >, we set it to < (zc + zr)/2 +/- (zc +
           zr)/2 >. */
        arb_get_ubound_arf(arb_midref(z), z, prec);
        arf_mul_2exp_si(arb_midref(z), arb_midref(z), -1);
        arf_get_mag(arb_radref(z), arb_midref(z));
        /* Note the above is inexact (rounding up), so need to update arb_midref(z) to match again */
        arf_set_mag(arb_midref(z), arb_radref(z));
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions