/*
 * exp.cpp: Exponential functions (exp, log and derived stuff).
 */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#include "spigot.h"
#include "funcs.h"
#include "cr.h"
#include "error.h"

class ExpRational : public Source {
    /*
     * We compute the exponential of a rational by translating the
     * obvious power series for exp(x) into a spigot description.
     *
     * Let x = n/d. Then we have
     *
     *                    n      n^2      n^3
     *   exp(n/d) = 1 + ---- + ------ + ------ + ...
     *                  1! d   2! d^2   3! d^3
     *
     *                    n         n         n         n
     *            = 1 + --- ( 1 + --- ( 1 + --- ( 1 + --- ( ... ) ) )
     *                  1.d       2.d       3.d       4.d
     *
     * so our matrices go
     *
     *   ( n 1.d ) ( n 2.d ) ( n 3.d ) ...
     *   ( 0 1.d ) ( 0 2.d ) ( 0 3.d )
     */

    bigint n, d, k;
    int crState;

  public:
    ExpRational(const bigint &an, const bigint &ad)
        : n(an), d(ad)
    {
        crState = -1;
    }

    virtual ExpRational *clone() { return new ExpRational(n, d); }

    bool gen_interval(bigint *low, bigint *high)
    {
        /* I totally made these numbers up, but they seem to work. Ahem. */
        *low = 0;
        *high = 2;
        return true;
    }

    bool gen_matrix(bigint *matrix)
    {
        crBegin;

        k = 1;
        while (1) {
            matrix[0] = n;
            matrix[1] = matrix[3] = d * k;
            matrix[2] = 0;
            ++k;
            crReturn(false);
        }

        crEnd;
    }
};

class LogRational : public Source {
    /*
     * We compute the logarithm of a rational by translating the
     * obvious power series for log(1+x) into a spigot description.
     *
     * Let x = 1 + n/d. Then we have
     *
     *                     n   2 n^2   3 n^3
     * So log(1 + n/d) = ( - - ----- + ----- - ...
     *                     d     d^2     d^3
     *
     *                     n         n       2.n
     *                   = - ( 1 - --- ( 1 - --- ( ... ) ) )
     *                     d       2.d       3.d
     *
     * so our matrices go
     *
     *   ( n 0 ) ( -n 2d ) ( -2n 3d ) ...
     *   ( 0 d ) (  0 2d ) (   0 3d )
     */

    bigint in, n, d, k;
    int crState;

  public:
    LogRational(const bigint &an, const bigint &ad)
        : in(an), d(ad)
    {
        n = in - d; /* we're computing log(1+x), not log(x), so subtract one */
        crState = -1;
    }

    virtual LogRational *clone() { return new LogRational(in, d); }

    bool gen_interval(bigint *low, bigint *high)
    {
        /* I totally made these numbers up, but they seem to work. Ahem. */
        *low = 0;
        *high = 2;
        return true;
    }

    bool gen_matrix(bigint *matrix)
    {
        crBegin;

        /*
         * The initial anomalous matrix.
         */
        matrix[1] = matrix[2] = 0;
        matrix[0] = n;
        matrix[3] = d;
        crReturn(false);

        /*
         * Then the regular series.
         */
        k = 1;
        while (1) {
            matrix[0] = -n * k;
            ++k;
            matrix[1] = matrix[3] = d * k;
            matrix[2] = 0;
            crReturn(false);
        }

        crEnd;
    }
};

struct ExpConstructor : MonotoneConstructor {
    MonotoneConstructor *clone() { return new ExpConstructor(); }
    Spigot *construct(const bigint &n, const bigint &d) {
        /*
         * Handle the special case of exp(0).
         */
        if (n == 0)
            return spigot_integer(1);

        return new ExpRational(n, d);
    }
};
struct LogConstructor : MonotoneConstructor {
    MonotoneConstructor *clone() { return new LogConstructor(); }
    Spigot *construct(const bigint &n, const bigint &d) {
        return new LogRational(n, d);
    }
};

Spigot *spigot_exp(Spigot *a)
{
    bigint n;

    /*
     * Range-reduce by subtracting some multiple of log(2).
     *
     * We absolutely don't want to do this _exactly_ right, by
     * rounding every number to the very nearest multiple of
     * 1/log(2): that would introduce an exactness hazard, so that
     * exp(log(2)/2) would hang without producing any output not
     * because it's fundamentally uncomputable but simply because
     * the range reducer couldn't decide which way to throw it.
     *
     * So instead, we find a rational approximation to the answer,
     * and range-reduce based on that.
     */
    {
        /*
         * Start by finding n such that n/32 is close (enough) to
         * a/log(1/2). (LogRational will converge faster for 1/2 than
         * for 2, so we do this backwards.)
         */
        StaticGenerator test(spigot_div(a->clone(), new LogRational(1, 2)));
        n = test.get_approximate_approximant(32);
    }

    /*
     * Now divide by 32 so as to round to the nearest integer n.
     */
    n = fdiv(n + 16, 32);
    if (n != 0) {
        /* Subtract off that multiple of log(1/2). */
        a = spigot_sub(a, spigot_mul(spigot_integer(n),
                                     new LogRational(1, 2)));
    }

    /*
     * Compute exp of the reduced number.
     */
    Spigot *reduced = spigot_monotone(new ExpConstructor, a);

    /*
     * And now we must scale the answer by 2^-n. But first, check that
     * the result isn't out of range for an argument to bigint_power,
     * by converting the power to an unsigned and making sure it
     * didn't overflow in the process.
     */
    bigint big_abs_n = bigint_abs(n);
    unsigned abs_n = (unsigned)big_abs_n;
    if ((bigint)abs_n != big_abs_n)
        throw spigot_error("cannot take exp of numbers this large");
    bigint twon = bigint_power(2, abs_n);
    if (n > 0) {
        return spigot_rational_mul(reduced, 1, twon);
    } else {
        return spigot_rational_mul(reduced, twon, 1);
    }
}

Spigot *spigot_log(Spigot *a)
{
    bigint term, n;

    /*
     * Spot really easy error cases before getting into the more
     * sophisticated test below.
     */
    {
        bigint an, ad;
        if (a->is_rational(&an, &ad) && an <= 0) {
            if (an < 0)
                throw spigot_error("log of negative number");
            else
                throw spigot_error("log of zero");
        }
    }

    /*
     * Range-reduce by dividing by a power of two, of which we must
     * try to find approximately the right one without running into
     * any exactness hazards.
     *
     * For best convergence, we really want to get the input into the
     * range (2/3,4/3), because then we're computing log(1+x) with
     * |x|<1/3 always. But going over a little in either direction is
     * OK. So we bounce on both 96*a and 96/a until we've narrowed one
     * of their integer parts to a range that's at least _nearly_
     * within the same power of 2 and whose low end is at least
     * (about) 64; then we know what to divide by.
     */
    {
        StaticGenerator testpos(spigot_rational_mul(a->clone(), 96, 1));
        StaticGenerator testneg(spigot_mobius(a->clone(), 0, 96, 1, 0));
        bigint lo, hi;

        while (1) {
            testpos.iterate_to_bounds(&lo, &hi, NULL, NULL, 0, NULL, true);
            if (hi < 0)
                throw spigot_error("log of negative number");
            if (lo == 0 && hi == 0)
                throw spigot_error("log of zero");
            if (lo >= 63 && (hi - lo <= 2 || (bigint_approxlog2(lo + 1) ==
                                              bigint_approxlog2(hi - 1)))) {
                n = bigint_approxlog2(hi + lo);
                // If (lo,hi) == (63,64) then we can just about hit
                // n=6, in which case simply subtracting 7 from n
                // wraps round and we'd end up trying to compute
                // 2^UINT_MAX.
                assert(n >= 6);
                if (n == 6)
                    ++n;
                n -= 7;
                a = spigot_rational_mul(a, 1, bigint_power(2, n));
                break;
            }

            testneg.iterate_to_bounds(&lo, &hi, NULL, NULL, 0, NULL, true);
            if (hi < 0)
                throw spigot_error("log of negative number");
            if (lo == 0 && hi == 0)
                throw spigot_error("log of zero");
            if (lo >= 63 && (hi - lo <= 2 || (bigint_approxlog2(lo + 1) ==
                                              bigint_approxlog2(hi - 1)))) {
                n = bigint_approxlog2(hi + lo);
                // Same safety precaution as above.
                assert(n >= 6);
                if (n == 6)
                    ++n;
                n -= 7;
                a = spigot_rational_mul(a, bigint_power(2, n), 1);
                n = -n;
                break;
            }
        }
    }

    Spigot *ret = spigot_monotone(new LogConstructor, a);
    /* Add n*log(2). (Well, subtract n*log(1/2), for faster convergence.) */
    if (n != 0)
        ret = spigot_sub(ret,
                         spigot_rational_mul(new LogRational(1, 2), n, 1));
    return ret;
}

Spigot *spigot_exp2(Spigot *a)
{
    return spigot_pow(spigot_integer(2), a);
}

Spigot *spigot_exp10(Spigot *a)
{
    return spigot_pow(spigot_integer(10), a);
}

// Given integers a,b > 1: if log_b(a) is rational, set n,d to be its
// numerator and denominator, and return true. Otherwise, return false.
static bool exact_log_z(bigint a, bigint b, bigint *n, bigint *d)
{
    bigint n0 = 1, n1 = 0;
    bigint d0 = 0, d1 = 1;

    assert(a > 1);
    assert(b > 1);

    /*
     * Algorithm is 'Euclid in the exponents'.
     *
     * If a is a rational power of b, this is equivalent to saying
     * that a = k^A and b = k^B, for some k.
     *
     *    Proof: certainly a,b must have the same _set_ of prime
     *    factors, i.e. we can write
     *         a = \prod p_i^{a_i}
     *         b = \prod p_i^{b_i}
     *    over a common set {p_i}, with all a_i,b_i > 0. Moreover,
     *    a_i/b_i must take the same value for all i. Let that value
     *    be A/B, in lowest terms (i.e. A,B coprime). Then we have
     *    Ba_i = Ab_i, i.e. A | Ba_i, but A does not divide B, so
     *    A | a_i. Similarly, B | b_i, and of course a_i/A = b_i/B. So
     *    if we define k_i = a_i/A = b_i/B for all i, then we can set
     *         k = \prod p_i^{k_i}
     *    and we have a = k^A and b = k^B as required. []
     *
     * But more than one k might satisfy that equation. (The above
     * proof constructs the _maximal_ k, but a smaller one might work,
     * e.g. if the k derived above is a square then its square root
     * would do just as well.) However, any two possible values (say,
     * k and k') will give rise to exponent pairs (A,B) and (A',B')
     * that are just scalings of each other, i.e. their ratios A/B and
     * A'/B' will be the same.
     *
     * We can find that ratio without having to know k by running
     * Euclid's algorithm, because that will yield the same sequence
     * of quotients if you adjust its inputs by a constant factor. But
     * we must modify the details a little, because we can't run
     * unmodified Euclid directly on A,B when what we have is k^A and
     * k^B for unknown k.
     *
     * So, we start by expressing Euclid in a way that does not refer
     * to 'reducing mod B', obtaining the following algorithm to find
     * the gcd of two integers A,B > 0:
     *
     *   - If A = 0, terminate.
     *   - Otherwise, find the maximal q such that B - qA >= 0.
     *   - Replace (A, B) with (B - qA, A), and repeat.
     *
     * Now all the operations we're performing on A,B are operations
     * we can still perform when what we actually have is a,b which
     * are the Ath and Bth powers of something we don't know. It's
     * clear that 'A=0' is true iff a=1; 'B - qA >= 0' is true iff
     * a^q | b; computing B - qA corresponds to computing b / a^q. So
     * we obtain *this* algorithm, which for anagram reasons surely
     * ought to go by the name 'Euclid's Logarithm':
     *
     *   - If a = 1, terminate.
     *   - Otherwise, find the maximal q such that a^q | b.
     *   - Replace (a, b) with (b / a^q, a), and repeat.
     *
     * If this algorithm succeeds, then we have found the common base
     * k such that a,b are powers of k; it will be in the variable b
     * when the algorithm terminates with a=1 (just as the ordinary
     * gcd would have been in B when the ordinary algorithm hit A=0).
     * So we could then recover the exponents A and B by repeated
     * division starting from the original a,b.
     *
     * However, there's a neater way. Recall that Euclid can be
     * augmented so that every new remainder it generates comes with a
     * pair of coefficients expressing that remainder as a linear
     * combination of the original inputs. In normal uses, you want
     * the pair of coefficients corresponding to the gcd of the
     * inputs, because that does modular inversion. But the algorithm
     * also generates the pair of coefficients corresponding to
     * _zero_, and it does it in lowest terms, i.e. running Euclid on
     * integers A,B gives you the pair (A,B) reduced to lowest terms
     * as a by-product. That's usually a bit pointless, but in this
     * case it's just what we want, because we _didn't_ know the ratio
     * A/B already, and it is exactly the output value log_b(a) that
     * we're after! So all we have to do is to build up that pair of
     * integers from the sequence of quotient values q, in just the
     * same way we would in ordinary Euclid.
     */

    while (a != 1) {
        // Find q and b/a^q simultaneously, by dividing off a as many
        // times as we can and counting how many times that was.
        bigint q;
        for (q = 0; b % a == 0; b /= a, ++q)
            /* empty loop body */;

        // Check that the resulting value of b is less than a. If the
        // algorithm has not managed to achieve this, that's the
        // failure condition: it can only happen if a,b were not in
        // fact powers of a common k at all.
        if (b >= a)
            return false;

        // Swap a,b, ready for the next iteration.
        { bigint tmp = a; a = b; b = tmp; }

        // Update our linear-combination coefficients. We only need
        // their absolute values for this application (because we know
        // our output must be a _positive_ rational).
        { bigint tmp = n0; n0 = n1; n1 = tmp + q * n1; }
        { bigint tmp = d0; d0 = d1; d1 = tmp + q * d1; }
    }

    // Done! n1/d1 is the rational we want.
    *n = n1;
    *d = d1;
    return true;
}

// Same as exact_log_z, but the inputs are rationals an/ad and bn/bd,
// expected to already be in lowest terms.
static bool exact_log_q(bigint an, bigint ad, bigint bn, bigint bd,
                        bigint *n, bigint *d)
{
    // Error cases.
    if (an < 0 || bn < 0)
        throw spigot_error("log of negative number");
    if (an == 0 || bn == 0)
        throw spigot_error("log of zero");
    if (bn == 1 && bd == 1)
        throw spigot_error("log to base 1 is meaningless");

    // Trivial special case.
    if (an == 1 && ad == 1) {
        *n = 0;
        *d = 1;
        return true;
    }

    // Now neither input is 1, so we can know which side of 1 they're
    // on. Normalise so they're the same way up, by flipping the sign
    // of the number we'll end up returning.
    bigint sign = +1;
    if ((an > ad) != (bn > bd)) {
        bigint tmp = bn; bn = bd; bd = tmp;
        sign = -1;
    }

    // If the numerators are both 1, or the denominators are both 1,
    // then just run the integer log-finder on the other pair.

    do { /* do-while-0 just so we can 'break' - *marginally* nicer than goto */
        bool ret;
        if (ad == 1 && bd == 1) {
            ret = exact_log_z(an, bn, n, d);
        } else if (an == 1 && bn == 1) {
            ret = exact_log_z(ad, bd, n, d);
        } else {
            break;
        }

        if (ret)
            *n *= sign;
        return ret;
    } while (0);

    // We've ruled out all the ways any numerator or denominator can
    // be 1 and still give a rational answer. If none of those apply,
    // then any remaining 1 anywhere indicates failure.
    if (an == 1 || ad == 1 || bn == 1 || bd == 1)
        return false;

    // The most general case: the numerators and the denominators must
    // both have the same rational log.
    bigint dn, dd;
    if (!exact_log_z(ad, bd, &dn, &dd))
        return false;
    if (!exact_log_z(an, bn, n, d))
        return false;
    if (!(*n == dn && *d == dd))
        return false;
    *n *= sign;
    return true;
}

Spigot *spigot_log_to_base(Spigot *input, Spigot *base)
{
    bigint in, id, bn, bd, n, d;

    /* Spot cases where we can prove the answer is an exact rational. */
    if (input->is_rational(&in, &id) && base->is_rational(&bn, &bd) &&
        exact_log_q(in, id, bn, bd, &n, &d)) {
        delete input;
        delete base;
        return spigot_rational(n, d);
    }

    /* Otherwise, log_b(a) == log(a)/log(b). */
    return spigot_div(spigot_log(input), spigot_log(base));
}

Spigot *spigot_log2(Spigot *a)
{
    return spigot_log_to_base(a, spigot_integer(2));
}

Spigot *spigot_log10(Spigot *a)
{
    return spigot_log_to_base(a, spigot_integer(10));
}

Spigot *spigot_log_wrapper(const std::vector<Spigot *> &args)
{
    /*
     * Implement operator overloading for the expression language. We
     * permit 'log' to take either one or two arguments, and invoke
     * spigot_log or spigot_log_to_base as appropriate. In C++ or
     * Python terms, this is like defining it as log(x, base=e) - the
     * second argument is optional and defaults to e if omitted.
     */
    if (args.size() == 1)
        return spigot_log(args[0]);
    else if (args.size() == 2)
        return spigot_log_to_base(args[0], args[1]);
    else
        throw spigot_error("expected either one or two arguments to 'log'");

}

Spigot *spigot_expm1(Spigot *a)
{
    return spigot_sub(spigot_exp(a), spigot_integer(1));
}

Spigot *spigot_log1p(Spigot *a)
{
    return spigot_log(spigot_add(a, spigot_integer(1)));
}

Spigot *spigot_sinh(Spigot *a)
{
    Spigot *ea = spigot_exp(a->clone());
    Spigot *ema = spigot_exp(spigot_neg(a));
    return spigot_rational_mul(spigot_sub(ea, ema), 1, 2);
}

Spigot *spigot_cosh(Spigot *a)
{
    Spigot *ea = spigot_exp(a->clone());
    Spigot *ema = spigot_exp(spigot_neg(a));
    return spigot_rational_mul(spigot_add(ea, ema), 1, 2);
}

Spigot *spigot_tanh(Spigot *a)
{
    Spigot *ea = spigot_exp(a->clone());
    Spigot *ema = spigot_exp(spigot_neg(a));
    return spigot_div(spigot_sub(ea, ema),
                      spigot_add(ea->clone(), ema->clone()));
}

Spigot *spigot_asinh(Spigot *a)
{
    /*
     * asinh(x) = log ( x + sqrt(x^2+1) )
     */
    return spigot_log(
        spigot_add(a, spigot_sqrt(spigot_quadratic(a->clone(), 1, 0, 1))));
}

Spigot *spigot_acosh(Spigot *a)
{
    /*
     * acosh(x) = log ( x + sqrt(x^2-1) )
     */
    return spigot_log(
        spigot_add(a, spigot_sqrt(spigot_quadratic(a->clone(), 1, 0, -1))));
}

Spigot *spigot_atanh(Spigot *a)
{
    /*
     *            1       1+x
     * atanh(x) = - log ( --- )
     *            2       1-x
     */
    Spigot *n = spigot_add(spigot_integer(1), a->clone());
    Spigot *d = spigot_sub(spigot_integer(1), a);
    return spigot_rational_mul(spigot_log(spigot_div(n, d)), 1, 2);
}

/* ----------------------------------------------------------------------
 * pow(), implemented using exp+log in the general case but with a lot
 * of faff beforehand.
 *
 * There are a lot of obvious special cases of pow which we'd like to
 * deal with directly: a rational raised to a rational power might
 * come out actually rational, in which case we'd prefer to return it
 * as an explicit rational than as an exp+log expression so that
 * further rational-consuming special cases can recognise it. Then we
 * can also convert easy things like 0^x, x^0, x^1 and x^-1 into
 * simpler computations.
 *
 * After that, you might think that a^b = exp(b*log(a)) is the
 * fallback. But not quite: there's still one thing to be careful of.
 *
 * To use the exp+log strategy, we have to start by checking the sign
 * of a, because if a<0, then we must enforce that b is a known
 * rational with an odd denominator, and use the sign of the numerator
 * to choose the output sign.
 *
 * And a sign check of a would introduce an exactness hazard: what if
 * a is non-obviously zero and b is positive, such as sin(pi)^pi? In
 * that situation, *starting* by checking the sign of a would
 * introduce an exactness hazard, whereas in fact we would like to be
 * able to keep narrowing an output interval about zero.
 *
 * So, in cases like that, we must begin generating output information
 * about a^b _before_ we find out the sign of a, and when (or if) we
 * do find it out, _then_ go and do exp+log.
 */

/*
 * This is a subfunction of pow() which deals with the general case
 * once we know we're going to have to take logs.
 *
 * It takes the sign of a as an extra input rather than finding it
 * itself; see the call site in spigot_pow() for explanation.
 */
static Spigot *spigot_pow_general_case(Spigot *a, Spigot *b, int a_sign)
{
    if (a_sign >= 0) {
        /* a^b == a^(b*log(a)). */
        return spigot_exp(spigot_mul(b, spigot_log(a)));
    } else {
        bigint bn, bd;

        if (!b->is_rational(&bn, &bd)) {
            throw spigot_error("negative number raised to"
                               " not-obviously-rational power");
        }
        while (bn % 2U == 0 && bd % 2U == 0) {
            bn /= 2;
            bd /= 2;
        }
        if (bd % 2U == 0) {
            throw spigot_error("negative number raised to"
                               " power with even denominator");
        }
        a = spigot_rational_mul(a, -1, 1);
        Spigot *absret = spigot_exp(spigot_mul(b, spigot_log(a)));
        if (bn % 2U == 0)
            return absret;
        else
            return spigot_neg(absret);
    }
}

/*
 * This class deals with the case where we had to defer the sign check
 * of a. It narrows an output interval conservatively about zero for
 * as long as we haven't distinguished a from 0 yet, and then if we
 * later do find out a's sign, it switches to returning the output of
 * spigot_pow_general_case.
 */
class PowPrefixWrapper : public BinaryIntervalSource {
    Spigot *a, *b;
    bigint xn;
    bool reciprocal;
    int a_sign;
    BracketingGenerator *bg;
    int crState;

  public:
    PowPrefixWrapper(Spigot *aa, Spigot *ab, bigint axn, bool areciprocal)
        : a(aa), b(ab), xn(axn), reciprocal(areciprocal)
    {
        bg = NULL;
        a_sign = 0;
        crState = -1;
        dprint("hello PowPrefixWrapper %p %p %b %B", a, b, &xn, reciprocal);
    }

    ~PowPrefixWrapper()
    {
        delete a;
        delete b;
        if (bg)
            delete bg;
    }

    virtual PowPrefixWrapper *clone()
    {
        return new PowPrefixWrapper(a->clone(), b->clone(), xn, reciprocal);
    }

    virtual void gen_bin_interval(bigint *ret_lo, bigint *ret_hi,
                                  unsigned *ret_bits)
    {
        crBegin;

        /*
         * Initially, we set up a BracketingGenerator for just a.
         */
        bg = new BracketingGenerator(a->clone());
        while (1) {
            /*
             * Fetch some information about a, and see what we can do
             * with it.
             */
            {
                bigint nlo, nhi;
                unsigned dbits;
                bg->get_bracket_shift(&nlo, &nhi, &dbits);
                dprint("input bracket for a: (%b,%b) / 2^%d",
                       &nlo, &nhi, (int)dbits);

                /*
                 * If the interval tells us the sign of a, then we can
                 * leave this preliminary loop and go to sensible
                 * exp+log evaluation.
                 */
                if (nlo > 0) {
                    dprint("a > 0");
                    a_sign = +1;
                    break;
                } else if (nhi < 0) {
                    dprint("a < 0");
                    a_sign = -1;
                    break;
                }

                /*
                 * Otherwise, approximate this interval by expanding
                 * it to one of the form [-2^k,+2^k], and then turn
                 * that into an output interval.
                 */
                int k, k2;

                k = -(int)dbits + bigint_approxlog2(bigint_abs(nlo)) + 1;
                k2 = -(int)dbits + bigint_approxlog2(bigint_abs(nhi)) + 1;
                if (k < k2)
                    k = k2;
                dprint("expanded input bracket for a: [-2^%d, +2^%d]", k, k);

                /*
                 * We have a in [-2^k, +2^k]. Compute a bounding
                 * interval for a^b using xn and reciprocal.
                 */
                if (reciprocal) {
                    k = fdiv(k + xn - 1, xn);
                } else {
                    k = k * xn;
                }

                /*
                 * Now we know a^b in [-2^k, +2^k], so we can safely
                 * return that.
                 */
                *ret_lo = -1;
                *ret_hi = +1;
                *ret_bits = abs(k);
            }
            dprint("output bracket for a^b: (%b,%b) / 2^%d",
                   ret_lo, ret_hi, (int)*ret_bits);

            crReturnV;
        }

        /*
         * If we've broken out of this loop, then we now know the sign
         * of a, so we can switch over to returning binary intervals
         * from that.
         *
         * The implementation of BinaryIntervalSource will take care
         * of us potentially not passing a _nested_ sequence of
         * intervals, so we've got no need to deal with any fiddly
         * special cases in that area.
         */
        delete bg;
        bg = new BracketingGenerator(spigot_pow_general_case(a->clone(),
                                                             b->clone(),
                                                             a_sign));
        while (1) {
            bg->get_bracket_shift(ret_lo, ret_hi, ret_bits);
            dprint("passthrough bracket for a^b: (%b,%b) / 2^%d",
                   ret_lo, ret_hi, (int)*ret_bits);
            crReturnV;
        }

        crEnd;
    }
};

Spigot *spigot_pow(Spigot *a, Spigot *b)
{
    bigint an, ad, bn, bd;
    bool a_rat, b_rat;

    /*
     * Start with the special-case of _both_ inputs being rational
     * (and within a range we can handle, and a is not zero, which
     * this handler wouldn't like anyway).
     */
    a_rat = a->is_rational(&an, &ad);
    b_rat = b->is_rational(&bn, &bd);
    if (a_rat && b_rat && an != 0 && bn != 0 && an != ad) {
        /*
         * Special case we can handle easily, at least if the numbers
         * aren't too excessive: a rational raised to a rational
         * power. We deal with the numerator of b by simply raising an
         * and ad to that power using integer exponentiation; then, if
         * b has a nontrivial denominator, we use spigot_algebraic to
         * take a root of it.
         *
         * Raising an integer to a power is nice and easy, and we
         * permit it as long as the output number isn't too excessive
         * (determined by the constant 'pow_bits_limit'). The
         * root-taking via spigot_algebraic is more costly, and we
         * have a smaller limit for that, after which it's cheaper to
         * use exp+log anyway.
         */
        const int pow_bits_limit = 1000000;
        const int alg_degree_limit = 100;

        bigint an_abs = bigint_abs(an);
        bigint ad_abs = bigint_abs(ad);
        bigint bn_abs = bigint_abs(bn);
        bigint bd_abs = bigint_abs(bd);

        bool bn_ok = (bigint_approxlog2(an_abs) * bn_abs < pow_bits_limit &&
                      bigint_approxlog2(ad_abs) * bn_abs < pow_bits_limit);
        bool bd_ok = (bd_abs < alg_degree_limit);

        if (bn_ok && bd_ok) {
            bigint abs_n = bigint_power(an_abs, bn_abs);
            bigint abs_d = bigint_power(ad_abs, bn_abs);
            if (an < 0 && bd % 2U == 0) {
                throw spigot_error("negative number raised to"
                                   " power with even denominator");
            }
            int sign = (an < 0 && (bn_abs % 2U) != 0) ? -1 : +1;
            if (bd == 1) {
                if (bn >= 0)
                    return spigot_rational(sign * abs_n, abs_d);
                else
                    return spigot_rational(sign * abs_d, abs_n);
            } else {
                std::vector<bigint> P;
                P.push_back(sign * (bn >= 0 ? abs_n : abs_d));
                P.resize((unsigned)bd, 0);
                P.push_back(-(bn >= 0 ? abs_d : abs_n));
                return spigot_algebraic(P, 0, P[0], 1);
            }
        }
    }

    /*
     * A few other special cases where one of a,b has a particular
     * rational value (but the other doesn't have to).
     */
    if (a_rat && an == 0) {
        /*
         * 0^positive = 0, 0^0 and 0^negative are errors.
         */
        if (get_sign(b) > 0)
            return spigot_integer(0);
        else
            throw spigot_error("zero raised to non-positive power");
    }
    if (b_rat && bn == 0) {
        /*
         * Apart from the above case, anything^0 = 1.
         */
        return spigot_integer(1);
    }
    if (a_rat && an == 1*ad) {
        /*
         * So is 1^anything.
         */
        return spigot_integer(1);
    }
    if (b_rat && bn == 1*bd) {
        /*
         * Anything^1 is just itself.
         */
        return a;
    }
    if (b_rat && bn == -1*bd) {
        /*
         * Anything^-1 is its reciprocal.
         */
        return spigot_reciprocal(a);
    }
    if (b_rat && bn == 2*bd) {
        /*
         * For anything^2, we have a nice fast spigot_square.
         */
        return spigot_square(a);
    }
    if (b_rat && bn == -2*bd) {
        /*
         * Ditto invsquare.
         */
        return spigot_invsquare(a);
    }

    /*
     * Now we're nearly ready to do exp+log, modulo a sign check of a,
     * and (as explained above) that's hazardous to do in the obvious
     * way. Instead we do some complicated faffing about to find out
     * _either_ the sign of a _or_ narrow down to a special case in
     * which we can use the PowPrefixWrapper class.
     */

    /* pow has a discontinuity at (0,0), so a _parallel_ sign test of
     * a,b does not introduce any avoidable exactness hazard */
    int s = parallel_sign_test(a->clone(), b->clone());
    if (s == +1 || s == -1) {
        /*
         * The parallel sign test has delivered us the sign of a, so
         * we can go straight to the general case.
         */
        return spigot_pow_general_case(a, b, s);
    }

    if (s == -2) {
        /*
         * If b < 0, then a |-> pow(a,b) is discontinuous at 0, so we
         * can't avoid a hazard anyway at a=0, and hence can safely
         * test the sign of a without introducing any further hazards.
         */
        return spigot_pow_general_case(a, b, get_sign(a->clone()));
    }

    /*
     * The only remaining case is s == +2, i.e. we know b > 0 and we
     * don't yet know about the sign of a.
     *
     * This is _potentially_ our special case. But it'll be much
     * easier if we know that |a| < 1, and if that's not the case then
     * finding the sign of a will be unproblematic anyway. So let's
     * start by narrowing down to _that_ case.
     */
    {
        StaticGenerator sg(a->clone());
        bigint approx = sg.get_approximate_approximant(8);
        if (bigint_abs(approx) > 4) {
            /*
             * We know the sign of a.
             */
            return spigot_pow_general_case(a, b, (approx > 0) ? +1 : -1);
        }
        /*
         * Otherwise, we know |a| < 1.
         */
    }

    /*
     * Now we know that b > 0 and |a| < 1, so this really is
     * the special case we want to take care with.
     *
     * Next, find a nice lower bound on b, i.e. a number 0 < x < b
     * such that it's easy to compute an upper bound on epsilon^x for
     * epsilon a power of two. I think making x an integer or the
     * reciprocal of an integer should be nice enough.
     */
    bool reciprocal;                   // if true, x=1/xn, else x=xn
    bigint xn;
    {
        StaticGenerator sg(b->clone());
        bigint approx = sg.get_approximate_approximant(32);
        if (approx > 36) {
            // b is big enough that we can take x an integer
            reciprocal = false;
            xn = fdiv(approx - 4, 32);
        } else {
            // Otherwise, find an integer _upper_ bound on 1/b, and
            // use the reciprocal of that
            StaticGenerator sg2(spigot_reciprocal(b->clone()));
            approx = sg2.get_approximate_approximant(32);
            reciprocal = true;
            xn = fdiv(approx + 4 + 31, 32);
        }
    }

    return new PowPrefixWrapper(a, b, xn, reciprocal);
}
