/*
 * qfunc - extended precision rational arithmetic non-primitive functions
 *
 * Copyright (C) 1999-2007,2021-2023,2026  David I. Bell and Ernest Bowen
 *
 * Primary author:  David I. Bell
 *
 * Calc is open software; you can redistribute it and/or modify it under
 * the terms of the version 2.1 of the GNU Lesser General Public License
 * as published by the Free Software Foundation.
 *
 * Calc is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
 * Public License for more details.
 *
 * A copy of version 2.1 of the GNU Lesser General Public License is
 * distributed with calc under the filename COPYING-LGPL.  You should have
 * received a copy with calc; if not, write to Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Under source code control:   1990/02/15 01:48:20
 * File existed as early as:    before 1990
 *
 * Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/
 */

/*
 * important <system> header includes
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

/*
 * calc local src includes
 */
#include "zmath.h"
#include "qmath.h"
#include "config.h"
#include "prime.h"
#include "attribute.h"
#include "errtbl.h"

#include "banned.h" /* include after all other includes */

static NUMBER **B_table;
static long B_num;
static long B_allocnum;
static NUMBER **E_table;
static long E_num;

#define QALLOCNUM 64

/*
 * check_epsilon - verify that 0 < epsilon < 1
 *
 * given:
 *      q       epsilon or eps argument
 *
 * returns:
 *      false   q is NULL or q <= 0 or q >= 1
 *      true    0 < q < 1
 */
bool
check_epsilon(NUMBER *q)
{
    /* verify that 0 < epsilon < 1 */
    if (q == NULL || qisneg(q) || qiszero(q) || qisone(q) || qreli(q, 1) > 0) {
        return false;
    }
    return true;
}

/*
 * Set the default epsilon for approximate calculations.
 * This must be greater than zero.
 *
 * given:
 *      q               number to be set as the new epsilon
 */
void
setepsilon(NUMBER *q)
{
    NUMBER *old;

    /*
     * firewall
     */
    if (q == NULL) {
        math_error("q is NULL for %s", __func__);
        not_reached();
    }
    if (check_epsilon(q) == false) {
        math_error("Invalid value for epsilon: must be: 0 < epsilon < 1");
        not_reached();
    }

    old = conf->epsilon;
    conf->epsilonprec = qprecision(q);
    conf->epsilon = qlink(q);
    if (old) {
        qfree(old);
    }
}

/*
 * Return the inverse of one number modulo another.
 * That is, find x such that:
 *      Ax = 1 (mod B)
 * Returns zero if the numbers are not relatively prime (temporary hack).
 */
NUMBER *
qminv(NUMBER *q1, NUMBER *q2)
{
    NUMBER *r;
    ZVALUE z1, z2, tmp;
    int s, t;
    long rnd;

    if (qisfrac(q1) || qisfrac(q2)) {
        math_error("Non-integers for minv");
        not_reached();
    }
    if (qiszero(q2)) {
        if (qisunit(q1)) {
            return qlink(q1);
        }
        return qlink(&_qzero_);
    }
    if (qisunit(q2)) {
        return qlink(&_qzero_);
    }
    rnd = conf->mod;
    s = (rnd & 4) ? 0 : q2->num.sign;
    if (rnd & 1) {
        s ^= 1;
    }

    tmp = q2->num;
    tmp.sign = 0;
    if (zmodinv(q1->num, tmp, &z1)) {
        return qlink(&_qzero_);
    }
    zsub(tmp, z1, &z2);
    if (rnd & 16) {
        t = zrel(z1, z2);
        if (t < 0) {
            s = 0;
        } else if (t > 0) {
            s = 1;
        }
    }
    r = qalloc();
    if (s) {
        zfree(z1);
        z2.sign = true;
        r->num = z2;
        return r;
    }
    zfree(z2);
    r->num = z1;
    return r;
}

/*
 * Return the residue modulo an integer (q3) of an integer (q1)
 * raised to a positive integer (q2) power.
 */
NUMBER *
qpowermod(NUMBER *q1, NUMBER *q2, NUMBER *q3)
{
    NUMBER *r;
    ZVALUE z1, z2, tmp;
    int s, t;
    long rnd;

    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3)) {
        math_error("Non-integers for pmod");
        not_reached();
    }
    if (qisneg(q2)) {
        math_error("Negative power for pmod");
        not_reached();
    }
    if (qiszero(q3)) {
        return qpowi(q1, q2);
    }
    if (qisunit(q3)) {
        return qlink(&_qzero_);
    }
    rnd = conf->mod;
    s = (rnd & 4) ? 0 : q3->num.sign;
    if (rnd & 1) {
        s ^= 1;
    }
    tmp = q3->num;
    tmp.sign = 0;
    zpowermod(q1->num, q2->num, tmp, &z1);
    if (ziszero(z1)) {
        zfree(z1);
        return qlink(&_qzero_);
    }
    zsub(tmp, z1, &z2);
    if (rnd & 16) {
        t = zrel(z1, z2);
        if (t < 0) {
            s = 0;
        } else if (t > 0) {
            s = 1;
        }
    }
    r = qalloc();
    if (s) {
        zfree(z1);
        z2.sign = true;
        r->num = z2;
        return r;
    }
    zfree(z2);
    r->num = z1;
    return r;
}

/*
 * Return the power function of one number with another.
 * The power must be integral.
 *      q3 = qpowi(q1, q2);
 */
NUMBER *
qpowi(NUMBER *q1, NUMBER *q2)
{
    register NUMBER *r;
    bool invert, sign;
    ZVALUE num, zden, z2;

    if (qisfrac(q2)) {
        math_error("Raising number to fractional power");
        not_reached();
    }
    num = q1->num;
    zden = q1->den;
    z2 = q2->num;
    sign = (num.sign && zisodd(z2));
    invert = z2.sign;
    num.sign = 0;
    z2.sign = 0;
    /*
     * Check for trivial cases first.
     */
    if (ziszero(num) && !ziszero(z2)) { /* zero raised to a power */
        if (invert) {
            math_error("Zero raised to negative power");
            not_reached();
        }
        return qlink(&_qzero_);
    }
    if (zisunit(num) && zisunit(zden)) { /* 1 or -1 raised to a power */
        r = (sign ? q1 : &_qone_);
        r->links++;
        return r;
    }
    if (ziszero(z2)) { /* raising to zeroth power */
        return qlink(&_qone_);
    }
    if (zisunit(z2)) { /* raising to power 1 or -1 */
        if (invert) {
            return qinv(q1);
        }
        return qlink(q1);
    }
    /*
     * Not a trivial case.  Do the real work.
     */
    r = qalloc();
    if (!zisunit(num)) {
        zpowi(num, z2, &r->num);
    }
    if (!zisunit(zden)) {
        zpowi(zden, z2, &r->den);
    }
    if (invert) {
        z2 = r->num;
        r->num = r->den;
        r->den = z2;
    }
    r->num.sign = sign;
    return r;
}

/*
 * Given the legs of a right triangle, compute its hypotenuse within
 * the specified error.  This is sqrt(a^2 + b^2).
 */
NUMBER *
qhypot(NUMBER *q1, NUMBER *q2, NUMBER *epsilon)
{
    NUMBER *tmp1, *tmp2, *tmp3;

    if (qiszero(epsilon)) {
        math_error("Zero epsilon value for hypot");
        not_reached();
    }
    if (qiszero(q1)) {
        return qqabs(q2);
    }
    if (qiszero(q2)) {
        return qqabs(q1);
    }
    tmp1 = qsquare(q1);
    tmp2 = qsquare(q2);
    tmp3 = qqadd(tmp1, tmp2);
    qfree(tmp1);
    qfree(tmp2);
    tmp1 = qsqrt(tmp3, epsilon, conf->triground);
    qfree(tmp3);
    return tmp1;
}

/*
 * Given one leg of a right triangle with unit hypotenuse, calculate
 * the other leg within the specified error.  This is sqrt(1 - a^2).
 * If the wantneg flag is nonzero, then negative square root is returned.
 */
NUMBER *
qlegtoleg(NUMBER *q, NUMBER *epsilon, bool wantneg)
{
    NUMBER *res, *qtmp1, *qtmp2;
    ZVALUE num;

    if (qiszero(epsilon)) {
        math_error("Zero epsilon value for ltol");
        not_reached();
    }
    if (qisunit(q)) {
        return qlink(&_qzero_);
    }
    if (qiszero(q)) {
        if (wantneg) {
            return qlink(&_qnegone_);
        }
        return qlink(&_qone_);
    }
    num = q->num;
    num.sign = 0;
    if (zrel(num, q->den) >= 0) {
        math_error("Leg too large for ltol");
        not_reached();
    }
    qtmp1 = qsquare(q);
    qtmp2 = qsub(&_qone_, qtmp1);
    qfree(qtmp1);
    res = qsqrt(qtmp2, epsilon, conf->triground);
    qfree(qtmp2);
    if (wantneg) {
        qtmp1 = qneg(res);
        qfree(res);
        res = qtmp1;
    }
    return res;
}

/*
 * Compute the square root of a real number.
 * Type of rounding if any depends on rnd.
 * If rnd & 32 is nonzero, result is exact for square numbers;
 * If rnd & 64 is nonzero, the negative square root is returned;
 * If rnd < 32, result is rounded to a multiple of epsilon
 *      up, down, etc. depending on bits 0, 2, 4 of v.
 */

NUMBER *
qsqrt(NUMBER *q1, NUMBER *epsilon, long rnd)
{
    NUMBER *r, etemp;
    ZVALUE tmp1, tmp2, quo, mul, divisor;
    long s1, s2, up, RR, RS;
    int sign;

    if (qisneg(q1)) {
        math_error("Square root of negative number for qsqrt");
        not_reached();
    }
    if (qiszero(q1)) {
        return qlink(&_qzero_);
    }
    sign = (rnd & 64) != 0;
    if (qiszero(epsilon)) {
        math_error("Zero epsilon for qsqrt");
        not_reached();
    }

    etemp = *epsilon;
    etemp.num.sign = 0;
    RS = rnd & 25;
    if (!(RS & 8)) {
        RS ^= epsilon->num.sign;
    }
    if (rnd & 2) {
        RS ^= sign ^ epsilon->num.sign;
    }
    if (rnd & 4) {
        RS ^= epsilon->num.sign;
    }
    RR = zisunit(q1->den) && qisunit(epsilon);
    if (rnd & 32 || RR) {
        s1 = zsqrt(q1->num, &tmp1, RS);
        if (RR) {
            if (ziszero(tmp1)) {
                zfree(tmp1);
                return qlink(&_qzero_);
            }
            r = qalloc();
            tmp1.sign = sign;
            r->num = tmp1;
            return r;
        }
        if (!s1) {
            s2 = zsqrt(q1->den, &tmp2, 0);
            if (!s2) {
                r = qalloc();
                tmp1.sign = sign;
                r->num = tmp1;
                r->den = tmp2;
                return r;
            }
            zfree(tmp2);
        }
        zfree(tmp1);
    }
    up = 0;
    zsquare(epsilon->den, &tmp1);
    zmul(tmp1, q1->num, &tmp2);
    zfree(tmp1);
    zsquare(epsilon->num, &tmp1);
    zmul(tmp1, q1->den, &divisor);
    zfree(tmp1);
    if (rnd & 16) {
        zshift(tmp2, 2, &tmp1);
        zfree(tmp2);
        s1 = zquo(tmp1, divisor, &quo, 16);
        zfree(tmp1);
        s2 = zsqrt(quo, &tmp1, s1 ? s1 < 0 : 16);
        zshift(tmp1, -1, &mul);
        up = (*tmp1.v & 1) ? s1 + s2 : -1;
        zfree(tmp1);
    } else {
        s1 = zquo(tmp2, divisor, &quo, 0);
        zfree(tmp2);
        s2 = zsqrt(quo, &mul, 0);
        up = (s1 + s2) ? 0 : -1;
    }
    if (up == 0) {
        if (rnd & 8) {
            up = (long)((RS ^ *mul.v) & 1);
        } else {
            up = RS ^ sign;
        }
    }
    if (up > 0) {
        zadd(mul, _one_, &tmp2);
        zfree(mul);
        mul = tmp2;
    }
    zfree(divisor);
    zfree(quo);
    if (ziszero(mul)) {
        zfree(mul);
        return qlink(&_qzero_);
    }
    r = qalloc();
    zreduce(mul, etemp.den, &tmp1, &r->den);
    zfree(mul);
    tmp1.sign = sign;
    zmul(tmp1, etemp.num, &r->num);
    zfree(tmp1);
    return r;
}

/*
 * Calculate the integral part of the square root of a number.
 * Example:  qisqrt(13) = 3.
 */
NUMBER *
qisqrt(NUMBER *q)
{
    NUMBER *r;
    ZVALUE tmp;

    if (qisneg(q)) {
        math_error("Square root of negative number for isqrt");
        not_reached();
    }
    if (qiszero(q)) {
        return qlink(&_qzero_);
    }
    r = qalloc();
    if (qisint(q)) {
        (void)zsqrt(q->num, &r->num, 0);
        return r;
    }
    zquo(q->num, q->den, &tmp, 0);
    (void)zsqrt(tmp, &r->num, 0);
    zfree(tmp);
    return r;
}

/*
 * Return whether or not a number is an exact square.
 */
bool
qissquare(NUMBER *q)
{
    bool flag;

    flag = zissquare(q->num);
    if (qisint(q) || !flag) {
        return flag;
    }
    return zissquare(q->den);
}

/*
 * Compute the greatest integer of the K-th root of a number.
 * Example:  qiroot(85, 3) = 4.
 */
NUMBER *
qiroot(NUMBER *q1, NUMBER *q2)
{
    NUMBER *r;
    ZVALUE tmp;

    if (qisneg(q2) || qiszero(q2) || qisfrac(q2)) {
        math_error("Taking number to bad root value");
        not_reached();
    }
    if (qiszero(q1)) {
        return qlink(&_qzero_);
    }
    if (qisone(q1) || qisone(q2)) {
        return qlink(q1);
    }
    if (qistwo(q2)) {
        return qisqrt(q1);
    }
    r = qalloc();
    if (qisint(q1)) {
        zroot(q1->num, q2->num, &r->num);
        return r;
    }
    zquo(q1->num, q1->den, &tmp, 0);
    zroot(tmp, q2->num, &r->num);
    zfree(tmp);
    return r;
}

/*
 * Return the greatest integer of the base 2 log of a number.
 * This is the number such that  1 <= x / log2(x) < 2.
 * Examples:  qilog2(8) = 3, qilog2(1.3) = 1, qilog2(1/7) = -3.
 *
 * given:
 *      q               number to take log of
 */
long
qilog2(NUMBER *q)
{
    long n;            /* power of two */
    int c;             /* result of comparison */
    ZVALUE tmp1, tmp2; /* temporary values */

    if (qiszero(q)) {
        math_error("Zero argument for ilog2");
        not_reached();
    }
    if (qisint(q)) {
        return zhighbit(q->num);
    }
    tmp1 = q->num;
    tmp1.sign = 0;
    n = zhighbit(tmp1) - zhighbit(q->den);
    if (n == 0) {
        c = zrel(tmp1, q->den);
    } else if (n > 0) {
        zshift(q->den, n, &tmp2);
        c = zrel(tmp1, tmp2);
        zfree(tmp2);
    } else {
        zshift(tmp1, -n, &tmp2);
        c = zrel(tmp2, q->den);
        zfree(tmp2);
    }
    if (c < 0) {
        n--;
    }
    return n;
}

/*
 * Return the greatest integer of the base 10 log of a number.
 * This is the number such that  1 <= x / log10(x) < 10.
 * Examples:  qilog10(100) = 2, qilog10(12.3) = 1, qilog10(.023) = -2.
 *
 * given:
 *      q               number to take log of
 */
long
qilog10(NUMBER *q)
{
    long n;            /* log value */
    ZVALUE tmp1, tmp2; /* temporary values */

    if (qiszero(q)) {
        math_error("Zero argument for ilog10");
        not_reached();
    }
    tmp1 = q->num;
    tmp1.sign = 0;
    if (qisint(q)) {
        return zlog10(tmp1, NULL);
    }
    /*
     * The number is not an integer.
     * Compute the result if the number is greater than one.
     */
    if (zrel(tmp1, q->den) > 0) {
        zquo(tmp1, q->den, &tmp2, 0);
        n = zlog10(tmp2, NULL);
        zfree(tmp2);
        return n;
    }
    /*
     * Here if the number is less than one.
     * If the number is the inverse of a power of ten, then the
     * obvious answer will be off by one.  Subtracting one if the
     * number is the inverse of an integer will fix it.
     */
    if (zisunit(tmp1)) {
        zsub(q->den, _one_, &tmp2);
    } else {
        zquo(q->den, tmp1, &tmp2, 0);
    }
    n = -zlog10(tmp2, NULL) - 1;
    zfree(tmp2);
    return n;
}

/*
 * Return the integer floor of the logarithm of a number relative to
 * a specified integral base.
 */
NUMBER *
qilog(NUMBER *q, ZVALUE base)
{
    long n;
    ZVALUE tmp1, tmp2;

    if (qiszero(q)) {
        return NULL;
    }

    if (qisunit(q)) {
        return qlink(&_qzero_);
    }
    if (qisint(q)) {
        return itoq(zlog(q->num, base));
    }
    tmp1 = q->num;
    tmp1.sign = 0;
    if (zrel(tmp1, q->den) > 0) {
        zquo(tmp1, q->den, &tmp2, 0);
        n = zlog(tmp2, base);
        zfree(tmp2);
        return itoq(n);
    }
    if (zisunit(tmp1)) {
        zsub(q->den, _one_, &tmp2);
    } else {
        zquo(q->den, tmp1, &tmp2, 0);
    }
    n = -zlog(tmp2, base) - 1;
    zfree(tmp2);
    return itoq(n);
}

/*
 * Return the number of digits in the representation to a specified
 * base of the integral part of a number.
 *
 * Examples: qdigits(3456,10) = 4, qdigits(-23.45, 10) = 2.
 *
 * One should remember these special cases:
 *
 *      digits(12.3456) == 2    computes with the integer part only
 *      digits(-1234) == 4      computes with the absolute value only
 *      digits(0) == 1          special case
 *      digits(-0.123) == 1     combination of all of the above
 *
 * given:
 *      q               number to count digits of
 */
long
qdigits(NUMBER *q, ZVALUE base)
{
    long n;      /* number of digits */
    ZVALUE temp; /* temporary value */

    if (zabsrel(q->num, q->den) < 0) {
        return 1;
    }
    if (qisint(q)) {
        return 1 + zlog(q->num, base);
    }
    zquo(q->num, q->den, &temp, 2);
    n = 1 + zlog(temp, base);
    zfree(temp);
    return n;
}

/*
 * Return the digit at the specified place in the expansion to specified
 * base of a rational number.  The places specified by dpos are numbered from
 * the "units" place just before the "decimal" point, so that negative
 * dpos indicates the (-dpos)th place to the right of the point.
 * Examples: qdigit(1234.5678, 1, 10) = 3, qdigit(1234.5678, -3, 10) = 7.
 * The signs of the number and the base are ignored.
 */
NUMBER *
qdigit(NUMBER *q, ZVALUE dpos, ZVALUE base)
{
    ZVALUE N, D;
    ZVALUE K;
    long k;
    ZVALUE A, B, C; /* temporary integers */
    NUMBER *res;

    /*
     * In the first stage, q is expressed as base^k * N/D where
     *      gcd(D, base) = 1
     * K is k as a ZVALUE
     */
    base.sign = 0;
    if (ziszero(base) || zisunit(base)) {
        return NULL;
    }
    if (qiszero(q) || (qisint(q) && zisneg(dpos)) || (zge31b(dpos) && !zisneg(dpos))) {
        return qlink(&_qzero_);
    }
    k = zfacrem(q->num, base, &N);
    if (k == 0) {
        zfree(N);
        k = zgcdrem(q->den, base, &D);
        if (k > 0) {
            zequo(q->den, D, &A);
            itoz(k, &K);
            zpowi(base, K, &B);
            zfree(K);
            zequo(B, A, &C);
            zfree(A);
            zfree(B);
            zmul(C, q->num, &N);
            zfree(C);
            k = -k;
        } else {
            N = q->num;
        }
    }
    if (k >= 0) {
        D = q->den;
    }

    itoz(k, &K);
    if (zrel(dpos, K) >= 0) {
        zsub(dpos, K, &A);
        zfree(K);
        zpowi(base, A, &B);
        zfree(A);
        zmul(D, B, &A);
        zfree(B);
        zquo(N, A, &B, 0);
    } else {
        if (zisunit(D)) {
            if (k != 0) {
                zfree(N);
            }
            zfree(K);
            if (k < 0) {
                zfree(D);
            }
            return qlink(&_qzero_);
        }
        zsub(K, dpos, &A);
        zfree(K);
        zpowermod(base, A, D, &C);
        zfree(A);
        zmod(N, D, &A, 0);
        zmul(C, A, &B);
        zfree(A);
        zfree(C);
        zmod(B, D, &A, 0);
        zfree(B);
        zmodinv(D, base, &B);
        zsub(base, B, &C);
        zfree(B);
        zmul(C, A, &B);
        zfree(C);
    }
    zfree(A);
    if (k != 0) {
        zfree(N);
    }
    if (k < 0) {
        zfree(D);
    }
    zmod(B, base, &A, 0);
    zfree(B);
    if (ziszero(A)) {
        zfree(A);
        return qlink(&_qzero_);
    }
    if (zisone(A)) {
        zfree(A);
        return qlink(&_qone_);
    }
    res = qalloc();
    res->num = A;
    return res;
}

/*
 * Return whether or not a bit is set at the specified bit position in a
 * number.  The lowest bit of the integral part of a number is the zeroth
 * bit position.  Negative bit positions indicate bits to the right of the
 * binary decimal point.  Examples: qdigit(17.1, 0) = 1, qdigit(17.1, -1) = 0.
 */
bool
qisset(NUMBER *q, long n)
{
    NUMBER *qtmp1, *qtmp2;
    ZVALUE ztmp;
    bool res;

    /*
     * Zero number or negative bit position place of integer is trivial.
     */
    if (qiszero(q) || (qisint(q) && (n < 0))) {
        return false;
    }
    /*
     * For non-negative bit positions, answer is easy.
     */
    if (n >= 0) {
        if (qisint(q)) {
            return zisset(q->num, n);
        }
        zquo(q->num, q->den, &ztmp, 2);
        res = zisset(ztmp, n);
        zfree(ztmp);
        return res;
    }
    /*
     * Fractional value and want negative bit position, must work harder.
     */
    qtmp1 = qscale(q, -n);
    qtmp2 = qint(qtmp1);
    qfree(qtmp1);
    res = ((qtmp2->num.v[0] & 0x01) != 0);
    qfree(qtmp2);
    return res;
}

/*
 * Compute the factorial of an integer.
 *      q2 = qfact(q1);
 */
NUMBER *
qfact(NUMBER *q)
{
    register NUMBER *r;

    if (qisfrac(q)) {
        math_error("Non-integral factorial");
        not_reached();
    }
    if (qiszero(q) || zisone(q->num)) {
        return qlink(&_qone_);
    }
    r = qalloc();
    zfact(q->num, &r->num);
    return r;
}

/*
 * Compute the product of the primes less than or equal to a number.
 *      q2 = qpfact(q1);
 */
NUMBER *
qpfact(NUMBER *q)
{
    NUMBER *r;

    if (qisfrac(q)) {
        math_error("Non-integral factorial");
        not_reached();
    }
    r = qalloc();
    zpfact(q->num, &r->num);
    return r;
}

/*
 * Compute the lcm of all the numbers less than or equal to a number.
 *      q2 = qlcmfact(q1);
 */
NUMBER *
qlcmfact(NUMBER *q)
{
    NUMBER *r;

    if (qisfrac(q)) {
        math_error("Non-integral lcmfact");
        not_reached();
    }
    r = qalloc();
    zlcmfact(q->num, &r->num);
    return r;
}

/*
 * Compute the permutation function  q1 * (q1-1) * ... * (q1-q2+1).
 */
NUMBER *
qperm(NUMBER *q1, NUMBER *q2)
{
    NUMBER *r;
    NUMBER *qtmp1, *qtmp2;
    long i;

    if (qisfrac(q2)) {
        math_error("Non-integral second arg for permutation");
        not_reached();
    }
    if (qiszero(q2)) {
        return qlink(&_qone_);
    }
    if (qisone(q2)) {
        return qlink(q1);
    }
    if (qisint(q1) && !qisneg(q1)) {
        if (qrel(q2, q1) > 0) {
            return qlink(&_qzero_);
        }
        if (qispos(q2)) {
            r = qalloc();
            zperm(q1->num, q2->num, &r->num);
            return r;
        }
    }
    if (zge31b(q2->num)) {
        math_error("Too large arg2 for permutation");
        not_reached();
    }
    i = qtoi(q2);
    if (i > 0) {
        q1 = qlink(q1);
        r = qlink(q1);
        while (--i > 0) {
            qtmp1 = qdec(q1);
            qtmp2 = qmul(r, qtmp1);
            qfree(q1);
            q1 = qtmp1;
            qfree(r);
            r = qtmp2;
        }
        qfree(q1);
        return r;
    }
    i = -i;
    qtmp1 = qinc(q1);
    r = qinv(qtmp1);
    while (--i > 0) {
        qtmp2 = qinc(qtmp1);
        qfree(qtmp1);
        qtmp1 = qqdiv(r, qtmp2);
        qfree(r);
        r = qtmp1;
        qtmp1 = qtmp2;
    }
    qfree(qtmp1);
    return r;
}

/*
 * Compute the combinatorial function  q(q - 1) ...(q - n + 1)/n!
 * n is to be a nonnegative integer
 */
NUMBER *
qcomb(NUMBER *q, NUMBER *n)
{
    NUMBER *r;
    NUMBER *q1, *q2;
    long i, j;
    ZVALUE z;

    if (!qisint(n) || qisneg(n)) {
        math_error("Bad second arg in call to qcomb!");
        not_reached();
    }
    if (qisint(q)) {
        switch (zcomb(q->num, n->num, &z)) {
        case 0:
            return qlink(&_qzero_);
        case 1:
            return qlink(&_qone_);
        case -1:
            return qlink(&_qnegone_);
        case 2:
            return qlink(q);
        case -2:
            return NULL;
        default:
            r = qalloc();
            r->num = z;
            return r;
        }
    }
    if (zge31b(n->num)) {
        return NULL;
    }
    i = ztoi(n->num);
    q = qlink(q);
    r = qlink(q);
    j = 1;
    while (--i > 0) {
        q1 = qdec(q);
        qfree(q);
        q = q1;
        q2 = qmul(r, q);
        qfree(r);
        r = qdivi(q2, ++j);
        qfree(q2);
    }
    qfree(q);
    return r;
}

/*
 * Compute the Bernoulli number with index n
 * For even positive n, newly calculated values for all even indices up
 * to n are stored in table at B_table.
 */
NUMBER *
qbern(ZVALUE z)
{
    long n, i, k, m, nn, dd;
    NUMBER **p;
    NUMBER *s, *s1, *c, *c1, *t;
    size_t sz;

    if (zisone(z)) {
        return qlink(&_qneghalf_);
    }

    if (zisodd(z) || z.sign) {
        return qlink(&_qzero_);
    }

    if (zge31b(z)) {
        return NULL;
    }

    n = ztoi(z);

    if (n == 0) {

        return qlink(&_qone_);
    }

    m = (n >> 1) - 1;

    if (m < B_num) {
        return qlink(B_table[m]);
    }

    if (m >= B_allocnum) {
        k = (m / QALLOCNUM + 1) * QALLOCNUM;
        sz = k * sizeof(NUMBER *);
        if (sz < (size_t)k) {
            return NULL;
        }
        if (B_allocnum == 0) {
            p = (NUMBER **)calloc(sz, 1);
        } else {
            p = (NUMBER **)realloc(B_table, sz);
        }
        if (p == NULL) {
            return NULL;
        }
        B_allocnum = k;
        B_table = p;
    }
    for (k = B_num; k <= m; k++) {
        nn = 2 * k + 3;
        dd = 1;
        c1 = itoq(nn);
        c = qinv(c1);
        qfree(c1);
        s = qsub(&_qonehalf_, c);
        i = k;
        for (i = 0; i < k; i++) {
            c1 = qmuli(c, nn--);
            qfree(c);
            c = qdivi(c1, dd++);
            qfree(c1);
            c1 = qmuli(c, nn--);
            qfree(c);
            c = qdivi(c1, dd++);
            qfree(c1);
            t = qmul(c, B_table[i]);
            s1 = qsub(s, t);
            qfree(t);
            qfree(s);
            s = s1;
        }
        B_table[k] = s;
        qfree(c);
    }
    B_num = k;
    return qlink(B_table[m]);
}

void
qfreebern(void)
{
    long k;

    if (B_num > 0) {
        for (k = 0; k < B_num; k++) {
            qfree(B_table[k]);
        }
        free(B_table);
    }
    B_table = NULL;
    B_allocnum = 0;
    B_num = 0;
}

/*
 * Compute the Euler number with index n = z
 * For even positive n, newly calculated values with all even indices up
 * to n are stored in E_table for later quick access.
 */
NUMBER *
qeuler(ZVALUE z)
{
    long i, k, m, n, nn, dd;
    NUMBER **p;
    NUMBER *s, *s1, *c, *c1, *t;
    size_t sz;

    if (ziszero(z)) {
        return qlink(&_qone_);
    }
    if (zisodd(z) || zisneg(z)) {
        return qlink(&_qzero_);
    }
    if (zge31b(z)) {
        return NULL;
    }
    n = ztoi(z);
    m = (n >> 1) - 1;
    if (m < E_num) {
        return qlink(E_table[m]);
    }
    sz = (m + 1) * sizeof(NUMBER *);
    if (sz < (size_t)m + 1) {
        return NULL;
    }
    if (E_num) {
        p = (NUMBER **)realloc(E_table, sz);
    } else {
        p = (NUMBER **)calloc(sz, 1);
    }
    if (p == NULL) {
        return NULL;
    }
    E_table = p;
    for (k = E_num; k <= m; k++) {
        nn = 2 * k + 2;
        dd = 1;
        c = qlink(&_qone_);
        s = qlink(&_qnegone_);
        i = k;
        for (i = 0; i < k; i++) {
            c1 = qmuli(c, nn--);
            qfree(c);
            c = qdivi(c1, dd++);
            qfree(c1);
            c1 = qmuli(c, nn--);
            qfree(c);
            c = qdivi(c1, dd++);
            qfree(c1);
            t = qmul(c, E_table[i]);
            s1 = qsub(s, t);
            qfree(t);
            qfree(s);
            s = s1;
        }
        E_table[k] = s;
        qfree(c);
    }
    E_num = k;
    return qlink(E_table[m]);
}

void
qfreeeuler(void)
{
    long k;

    if (E_num > 0) {
        for (k = 0; k < E_num; k++) {
            qfree(E_table[k]);
        }
        free(E_table);
    }
    E_table = NULL;
    E_num = 0;
}

/*
 * Catalan numbers: catalan(n) = comb(2*n, n)/(n+1)
 * To be called only with integer q
 */
NUMBER *
qcatalan(NUMBER *q)
{
    NUMBER *A, *B;
    NUMBER *res;

    if (qisneg(q)) {
        return qlink(&_qzero_);
    }
    A = qscale(q, 1);
    B = qcomb(A, q);
    if (B == NULL) {
        return NULL;
    }
    qfree(A);
    A = qinc(q);
    res = qqdiv(B, A);
    qfree(A);
    qfree(B);
    return res;
}

/*
 * Compute the Jacobi function (a / b).
 * -1 => a is not quadratic residue mod b
 * 1 => b is composite, or a is quad residue of b
 * 0 => b is even or b < 0
 */
NUMBER *
qjacobi(NUMBER *q1, NUMBER *q2)
{
    if (qisfrac(q1) || qisfrac(q2)) {
        math_error("Non-integral arguments for jacobi");
        not_reached();
    }
    return itoq((long)zjacobi(q1->num, q2->num));
}

/*
 * Compute the Fibonacci number F(n).
 */
NUMBER *
qfib(NUMBER *q)
{
    register NUMBER *r;

    if (qisfrac(q)) {
        math_error("Non-integral Fibonacci number");
        not_reached();
    }
    r = qalloc();
    zfib(q->num, &r->num);
    return r;
}

/*
 * Truncate a number to the specified number of decimal places.
 */
NUMBER *
qtrunc(NUMBER *q1, NUMBER *q2)
{
    long places;
    NUMBER *r, *e;

    if (qisfrac(q2) || !zistiny(q2->num)) {
        math_error("Bad number of places for qtrunc");
        not_reached();
    }
    places = qtoi(q2);
    e = qtenpow(-places);
    r = qmappr(q1, e, 2);
    qfree(e);
    return r;
}

/*
 * Truncate a number to the specified number of binary places.
 * Specifying zero places makes the result identical to qint.
 */
NUMBER *
qbtrunc(NUMBER *q1, NUMBER *q2)
{
    long places;
    NUMBER *r, *e;

    if (qisfrac(q2) || !zistiny(q2->num)) {
        math_error("Bad number of places for qtrunc");
        not_reached();
    }
    places = qtoi(q2);
    e = qbitvalue(-places);
    r = qmappr(q1, e, 2);
    qfree(e);
    return r;
}

/*
 * Round a number to a specified number of binary places.
 */
NUMBER *
qbround(NUMBER *q, long places, long rnd)
{
    NUMBER *e, *r;

    if (qiszero(q)) {
        return qlink(&_qzero_);
    }
    if (rnd & 32) {
        places -= qilog2(q) + 1;
    }
    e = qbitvalue(-places);
    r = qmappr(q, e, rnd & 31);
    qfree(e);
    return r;
}

/*
 * Round a number to a specified number of decimal digits.
 */
NUMBER *
qround(NUMBER *q, long places, long rnd)
{
    NUMBER *e, *r;

    if (qiszero(q)) {
        return qlink(&_qzero_);
    }
    if (rnd & 32) {
        places -= qilog10(q) + 1;
    }
    e = qtenpow(-places);
    r = qmappr(q, e, rnd & 31);
    qfree(e);
    return r;
}

/*
 * Approximate a number to nearest multiple of a given number.  Whether
 * rounding is down, up, etc. is determined by rnd.
 */
NUMBER *
qmappr(NUMBER *q, NUMBER *e, long rnd)
{
    NUMBER *r;
    ZVALUE tmp1, tmp2, mul;

    if (qiszero(e)) {
        return qlink(q);
    }
    if (qiszero(q)) {
        return qlink(&_qzero_);
    }
    zmul(q->num, e->den, &tmp1);
    zmul(q->den, e->num, &tmp2);
    zquo(tmp1, tmp2, &mul, rnd);
    zfree(tmp1);
    zfree(tmp2);
    if (ziszero(mul)) {
        zfree(mul);
        return qlink(&_qzero_);
    }
    r = qalloc();
    zreduce(mul, e->den, &tmp1, &r->den);
    zmul(tmp1, e->num, &r->num);
    zfree(tmp1);
    zfree(mul);
    return r;
}

/*
 * Determine the smallest-denominator rational number in the interval of
 * length abs(epsilon) (< 1) with center or one end at q, or to determine
 * the number nearest above or nearest below q with denominator
 * not exceeding abs(epsilon).
 * Whether the approximation is nearest above or nearest below is
 * determined by rnd and the signs of epsilon and q.
 */

NUMBER *
qcfappr(NUMBER *q, NUMBER *epsilon, long rnd)
{
    NUMBER *res, etemp, *epsilon1;
    ZVALUE num, zden, oldnum, oldden;
    ZVALUE rem, oldrem, quot;
    ZVALUE tmp1, tmp2, tmp3, tmp4;
    ZVALUE denbnd;
    ZVALUE f, g, k;
    bool esign;
    int s;
    bool bnddencase;
    bool useold = false;

    if (qiszero(epsilon) || qisint(q)) {
        return qlink(q);
    }

    esign = epsilon->num.sign;
    etemp = *epsilon;
    etemp.num.sign = 0;
    bnddencase = (zrel(etemp.num, etemp.den) >= 0);
    if (bnddencase) {
        zquo(etemp.num, etemp.den, &denbnd, 0);
        if (zrel(q->den, denbnd) <= 0) {
            zfree(denbnd);
            return qlink(q);
        }
    } else {
        if (rnd & 16) {
            epsilon1 = qscale(epsilon, -1);
        } else {
            epsilon1 = qlink(epsilon);
        }
        zreduce(q->den, epsilon1->den, &tmp1, &g);
        zmul(epsilon1->num, tmp1, &f);
        f.sign = 0;
        zfree(tmp1);
        qfree(epsilon1);
    }
    if (rnd & 16 && !zistwo(q->den)) {
        s = 0;
    } else {
        s = esign ? -1 : 1;
        if (rnd & 1) {
            s = -s;
        }
        if (rnd & 2 && q->num.sign ^ esign) {
            s = -s;
        }
        if (rnd & 4 && esign) {
            s = -s;
        }
    }
    oldnum = _one_;
    oldden = _zero_;
    zcopy(q->den, &oldrem);
    zdiv(q->num, q->den, &num, &rem, 0);
    zden = _one_;
    for (;;) {
        if (!bnddencase) {
            zmul(f, zden, &tmp1);
            zmul(g, rem, &tmp2);
            if (ziszero(rem) || (s >= 0 && zrel(tmp1, tmp2) >= 0)) {
                break;
            }
            zfree(tmp1);
            zfree(tmp2);
        }
        zdiv(oldrem, rem, &quot, &tmp1, 0);
        zfree(oldrem);
        oldrem = rem;
        rem = tmp1;
        zmul(quot, zden, &tmp1);
        zadd(tmp1, oldden, &tmp2);
        zfree(tmp1);
        zfree(oldden);
        oldden = zden;
        zden = tmp2;
        zmul(quot, num, &tmp1);
        zadd(tmp1, oldnum, &tmp2);
        zfree(tmp1);
        zfree(oldnum);
        oldnum = num;
        num = tmp2;
        zfree(quot);
        if (bnddencase) {
            if (zrel(zden, denbnd) >= 0) {
                break;
            }
        }
        s = -s;
    }
    if (bnddencase) {
        if (s > 0) {
            useold = true;
        } else {
            zsub(zden, denbnd, &tmp1);
            zquo(tmp1, oldden, &k, 1);
            zfree(tmp1);
        }
        zfree(denbnd);
    } else {
        if (s < 0) {
            zfree(tmp1);
            zfree(tmp2);
            zfree(f);
            zfree(g);
            zfree(oldnum);
            zfree(oldden);
            zfree(num);
            zfree(zden);
            zfree(oldrem);
            zfree(rem);
            return qlink(q);
        }
        zsub(tmp1, tmp2, &tmp3);
        zfree(tmp1);
        zfree(tmp2);
        zmul(f, oldden, &tmp1);
        zmul(g, oldrem, &tmp2);
        zfree(f);
        zfree(g);
        zadd(tmp1, tmp2, &tmp4);
        zfree(tmp1);
        zfree(tmp2);
        zquo(tmp3, tmp4, &k, 0);
        zfree(tmp3);
        zfree(tmp4);
    }
    if (!useold && !ziszero(k)) {
        zmul(k, oldnum, &tmp1);
        zsub(num, tmp1, &tmp2);
        zfree(tmp1);
        zfree(num);
        num = tmp2;
        zmul(k, oldden, &tmp1);
        zsub(zden, tmp1, &tmp2);
        zfree(tmp1);
        zfree(zden);
        zden = tmp2;
    }
    if (bnddencase && s == 0) {
        zmul(k, oldrem, &tmp1);
        zadd(rem, tmp1, &tmp2);
        zfree(tmp1);
        zfree(rem);
        rem = tmp2;
        zmul(rem, oldden, &tmp1);
        zmul(zden, oldrem, &tmp2);
        useold = (zrel(tmp1, tmp2) >= 0);
        zfree(tmp1);
        zfree(tmp2);
    }
    if (!bnddencase || s <= 0) {
        zfree(k);
    }
    zfree(rem);
    zfree(oldrem);
    res = qalloc();
    if (useold) {
        zfree(num);
        zfree(zden);
        res->num = oldnum;
        res->den = oldden;
        return res;
    }
    zfree(oldnum);
    zfree(oldden);
    res->num = num;
    res->den = zden;
    return res;
}

/*
 * Calculate the nearest-above, or nearest-below, or nearest, number
 * with denominator less than the given number, the choice between
 * possibilities being determined by the parameter rnd.
 */
NUMBER *
qcfsim(NUMBER *q, long rnd)
{
    NUMBER *res;
    ZVALUE tmp1, tmp2, den1, den2;
    int s;

    if (qiszero(q) && rnd & 26) {
        return qlink(&_qzero_);
    }
    if (rnd & 24) {
        s = q->num.sign;
    } else {
        s = rnd & 1;
        if (rnd & 2) {
            s ^= q->num.sign;
        }
    }
    if (qisint(q)) {
        if ((rnd & 8) && !(rnd & 16)) {
            return qlink(&_qzero_);
        }
        if (s) {
            return qinc(q);
        }
        return qdec(q);
    }
    if (zistwo(q->den)) {
        if (rnd & 16) {
            s ^= 1;
        }
        if (s) {
            zadd(q->num, _one_, &tmp1);
        } else {
            zsub(q->num, _one_, &tmp1);
        }
        res = qalloc();
        zshift(tmp1, -1, &res->num);
        zfree(tmp1);
        return res;
    }
    s = s ? 1 : -1;
    if (rnd & 24) {
        s = 0;
    }
    res = qalloc();
    zmodinv(q->num, q->den, &den1);
    if (s >= 0) {
        zsub(q->den, den1, &den2);
        if (s > 0 || ((zrel(den1, den2) < 0) ^ (!(rnd & 16)))) {
            zfree(den1);
            res->den = den2;
            zmul(den2, q->num, &tmp1);
            zadd(tmp1, _one_, &tmp2);
            zfree(tmp1);
            zequo(tmp2, q->den, &res->num);
            zfree(tmp2);
            return res;
        }
        zfree(den2);
    }
    res->den = den1;
    zmul(den1, q->num, &tmp1);
    zsub(tmp1, _one_, &tmp2);
    zfree(tmp1);
    zequo(tmp2, q->den, &res->num);
    zfree(tmp2);
    return res;
}

/*
 * Return an indication on whether or not two fractions are approximately
 * equal within the specified epsilon. Returns negative if the absolute value
 * of the difference between the two numbers is less than epsilon, zero if
 * the difference is equal to epsilon, and positive if the difference is
 * greater than epsilon.
 */
FLAG
qnear(NUMBER *q1, NUMBER *q2, NUMBER *epsilon)
{
    int res;
    NUMBER qtemp, etemp, *qq;

    etemp = *epsilon;
    etemp.num.sign = 0;
    if (q1 == q2) {
        if (qiszero(epsilon)) {
            return 0;
        }
        return -1;
    }
    if (qiszero(epsilon)) {
        return qcmp(q1, q2);
    }
    if (qiszero(q2)) {
        qtemp = *q1;
        qtemp.num.sign = 0;
        return qrel(&qtemp, &etemp);
    }
    if (qiszero(q1)) {
        qtemp = *q2;
        qtemp.num.sign = 0;
        return qrel(&qtemp, &etemp);
    }
    qq = qsub(q1, q2);
    qtemp = *qq;
    qtemp.num.sign = 0;
    res = qrel(&qtemp, &etemp);
    qfree(qq);
    return res;
}

/*
 * Compute the gcd (greatest common divisor) of two numbers.
 *      q3 = qgcd(q1, q2);
 */
NUMBER *
qgcd(NUMBER *q1, NUMBER *q2)
{
    ZVALUE z;
    NUMBER *q;

    if (q1 == q2) {
        return qqabs(q1);
    }
    if (qisfrac(q1) || qisfrac(q2)) {
        q = qalloc();
        zgcd(q1->num, q2->num, &q->num);
        zlcm(q1->den, q2->den, &q->den);
        return q;
    }
    if (qiszero(q1)) {
        return qqabs(q2);
    }
    if (qiszero(q2)) {
        return qqabs(q1);
    }
    if (qisunit(q1) || qisunit(q2)) {
        return qlink(&_qone_);
    }
    zgcd(q1->num, q2->num, &z);
    if (zisunit(z)) {
        zfree(z);
        return qlink(&_qone_);
    }
    q = qalloc();
    q->num = z;
    return q;
}

/*
 * Compute the lcm (least common multiple) of two numbers.
 *      q3 = qlcm(q1, q2);
 */
NUMBER *
qlcm(NUMBER *q1, NUMBER *q2)
{
    NUMBER *q;

    if (qiszero(q1) || qiszero(q2)) {
        return qlink(&_qzero_);
    }
    if (q1 == q2) {
        return qqabs(q1);
    }
    if (qisunit(q1)) {
        return qqabs(q2);
    }
    if (qisunit(q2)) {
        return qqabs(q1);
    }
    q = qalloc();
    zlcm(q1->num, q2->num, &q->num);
    if (qisfrac(q1) || qisfrac(q2)) {
        zgcd(q1->den, q2->den, &q->den);
    }
    return q;
}

/*
 * Remove all occurrences of the specified factor from a number.
 * Returned number is always positive or zero.
 */
NUMBER *
qfacrem(NUMBER *q1, NUMBER *q2)
{
    long count;
    ZVALUE tmp;
    NUMBER *r;

    if (qisfrac(q1) || qisfrac(q2)) {
        math_error("Non-integers for factor removal");
        not_reached();
    }
    if (qiszero(q2)) {
        return qqabs(q1);
    }
    if (qiszero(q1)) {
        return qlink(&_qzero_);
    }
    count = zfacrem(q1->num, q2->num, &tmp);
    if (zisunit(tmp)) {
        zfree(tmp);
        return qlink(&_qone_);
    }
    if (count == 0 && !qisneg(q1)) {
        zfree(tmp);
        return qlink(q1);
    }
    r = qalloc();
    r->num = tmp;
    return r;
}

/*
 * Divide one number by the gcd of it with another number repeatedly until
 * the number is relatively prime.
 */
NUMBER *
qgcdrem(NUMBER *q1, NUMBER *q2)
{
    ZVALUE tmp;
    NUMBER *r;

    if (qisfrac(q1) || qisfrac(q2)) {
        math_error("Non-integers for gcdrem");
        not_reached();
    }
    if (qiszero(q2)) {
        return qlink(&_qone_);
    }
    if (qiszero(q1)) {
        return qlink(&_qzero_);
    }
    if (zgcdrem(q1->num, q2->num, &tmp) == 0) {
        return qqabs(q1);
    }
    if (zisunit(tmp)) {
        zfree(tmp);
        return qlink(&_qone_);
    }
    if (zcmp(q1->num, tmp) == 0) {
        zfree(tmp);
        return qlink(q1);
    }
    r = qalloc();
    r->num = tmp;
    return r;
}

/*
 * Return the lowest prime factor of a number.
 * Search is conducted for the specified number of primes.
 * Returns one if no factor was found.
 */
NUMBER *
qlowfactor(NUMBER *q1, NUMBER *q2)
{
    unsigned long count;

    if (qisfrac(q1) || qisfrac(q2)) {
        math_error("Non-integers for lowfactor");
        not_reached();
    }
    count = ztoi(q2->num);
    if (count > PIX_32B) {
        math_error("lowfactor count is too large");
        not_reached();
    }
    return utoq(zlowfactor(q1->num, count));
}

/*
 * Return the number of places after the decimal point needed to exactly
 * represent the specified number as a real number.  Integers return zero,
 * and non-terminating decimals return minus one.  Examples:
 * qdecplaces(1.23) = 2, qdecplaces(3) = 0, qdecplaces(1/7) = -1.
 */
long
qdecplaces(NUMBER *q)
{
    long twopow, fivepow;
    HALF fiveval[2];
    ZVALUE five;
    ZVALUE tmp;

    if (qisint(q)) { /* no decimal places if number is integer */
        return 0;
    }
    /*
     * The number of decimal places of a fraction in lowest terms is finite
     * if an only if the denominator is of the form 2^A * 5^B, and then the
     * number of decimal places is equal to MAX(A, B).
     */
    five.sign = 0;
    five.len = 1;
    five.v = fiveval;
    fiveval[0] = 5;
    fivepow = zfacrem(q->den, five, &tmp);
    if (!zisonebit(tmp)) {
        zfree(tmp);
        return -1;
    }
    twopow = zlowbit(tmp);
    zfree(tmp);
    if (twopow < fivepow) {
        twopow = fivepow;
    }
    return twopow;
}

/*
 * Return, if possible, the minimum number of places after the decimal
 * point needed to exactly represent q with the specified base.
 * Integers return 0 and numbers with non-terminating expansions -1.
 * Returns -2 if base inadmissible
 */
long
qplaces(NUMBER *q, ZVALUE base)
{
    long count;
    ZVALUE tmp;

    if (base.len == 1 && base.v[0] == 10) {
        return qdecplaces(q);
    }
    if (ziszero(base) || zisunit(base)) {
        return -2;
    }
    if (qisint(q)) {
        return 0;
    }
    if (zisonebit(base)) {
        if (!zisonebit(q->den)) {
            return -1;
        }
        return 1 + (zlowbit(q->den) - 1) / zlowbit(base);
    }
    count = zgcdrem(q->den, base, &tmp);
    if (count == 0) {
        return -1;
    }
    if (!zisunit(tmp)) {
        count = -1;
    }
    zfree(tmp);
    return count;
}

/*
 * Perform a probabilistic primality test (algorithm P in Knuth).
 * Returns false if definitely not prime, or true if probably prime.
 *
 * The absolute value of the 2nd arg determines how many times
 * to check for primality.  If 2nd arg < 0, then the trivial
 * check is omitted.  The 3rd arg determines how tests to
 * initially skip.
 */
bool
qprimetest(NUMBER *q1, NUMBER *q2, NUMBER *q3)
{
    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3)) {
        math_error("Bad arguments for ptest");
        not_reached();
    }
    if (zge24b(q2->num)) {
        math_error("ptest count >= 2^24");
        not_reached();
    }
    return zprimetest(q1->num, ztoi(q2->num), q3->num);
}

/*
 * test if a number is an integer power of 2
 *
 * given:
 *      q       value to check if it is a power of 2
 *      qlog2   when q is an integer power of 2 (return true), set to log base 2 of q
 *              when q is NOT an integer power of 2 (return false), *qlog2 is not set
 *
 * returns:
 *      true    q is a power of 2
 *      false   q is not a power of 2
 */
bool
qispowerof2(NUMBER *q, NUMBER **qlog2)
{
    FULL log2; /* base 2 logarithm as a ZVALUE */

    /* firewall */
    if (q == NULL) {
        math_error("%s: q is NULL", __func__);
        not_reached();
    }
    if (qlog2 == NULL) {
        math_error("%s: qlog2 is NULL", __func__);
        not_reached();
    }
    if (*qlog2 == NULL) {
        math_error("%s: *qlog2 is NULL", __func__);
        not_reached();
    }

    /* zero and negative values are never integer powers of 2 */
    if (qiszero(q) || qisneg(q)) {
        /* leave *qlog2 untouched and return false */
        return false;
    }

    /*
     * case: q>0 is an integer
     */
    if (qisint(q)) {

        /*
         * check if q is an integer power of 2
         */
        if (zispowerof2(q->num, &log2)) {

            /*
             * case: q is an integer power of 2
             *
             * Set *qlog2 to base 2 logarithm of q and return true.
             */
            *qlog2 = utoq(log2);
            return true;
        }

        /*
         * case: q>0 is 1 over an integer
         */
    } else if (qisreciprocal(q)) {

        /*
         * check if q is 1 over an integer power of 2
         */
        if (zispowerof2(q->den, &log2)) {

            /*
             * case: q>0 is an integer power of 2
             *
             * Set *qlog2 to base 2 logarithm of q, which will be a negative value,
             * and return true.
             */
            **qlog2 = *utoq(log2);
            (*qlog2)->num.sign = !(*qlog2)->num.sign; /* set *qlog2 to -log2 */
            return true;
        }
    }

    /*
     * q is not an integer power of 2
     *
     * Leave *qlog2 untouched and return false.
     */
    return false;
}
