/*
 * zmath - extended precision integral arithmetic primitives
 *
 * Copyright (C) 1999-2007,2021-2023  David I. Bell, Landon Curt Noll 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:28
 * File existed as early as:    before 1990
 *
 * Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/
 */


#include <stdio.h>
#include "int.h"
#include "alloc.h"
#include "zmath.h"


#include "errtbl.h"
#include "banned.h"     /* include after system header <> includes */


HALF _zeroval_[] = { 0 };
ZVALUE _zero_ = { _zeroval_, 1, 0};

HALF _oneval_[] = { 1 };
ZVALUE _one_ = { _oneval_, 1, 0 };
ZVALUE _neg_one_ = { _oneval_, 1, 1 };

HALF _twoval_[] = { 2 };
ZVALUE _two_ = { _twoval_, 1, 0 };

HALF _tenval_[] = { 10 };
ZVALUE _ten_ = { _tenval_, 1, 0 };

HALF _sqbaseval_[] = { 0, 1 };
ZVALUE _sqbase_ = { _sqbaseval_, 2, 0 };

HALF _pow4baseval_[] = { 0, 0, 1 };
ZVALUE _pow4base_ = { _pow4baseval_, 4, 0 };

HALF _pow8baseval_[] = { 0, 0, 0, 0, 1 };
ZVALUE _pow8base_ = { _pow8baseval_, 4, 0 };

/*
 * 2^64 as a ZVALUE
 */
#if BASEB == 32
ZVALUE _b32_ = { _sqbaseval_, 2, 0 };
ZVALUE _b64_ = { _pow4baseval_, 3, 0 };
#elif BASEB == 16
ZVALUE _b32_ = { _pow4baseval_, 3, 0 };
ZVALUE _b64_ = { _pow8baseval_, 5, 0 };
#else
        -=@=- BASEB not 16 or 32 -=@=-
#endif

/*
 * ZVALUE - values that should not be freed
 */
HALF *half_tbl[] = {
    _zeroval_,
    _oneval_,
    _twoval_,
    _tenval_,
    _sqbaseval_,
    _pow4baseval_,
    _pow8baseval_,
    NULL        /* must be last */
};


/*
 * highhalf[i] - masks off the upper i bits of a HALF
 * rhighhalf[i] - masks off the upper BASEB-i bits of a HALF
 * lowhalf[i] - masks off the lower i bits of a HALF
 * rlowhalf[i] - masks off the lower BASEB-i bits of a HALF
 * bitmask[i] - (1 << i) for  0 <= i <= BASEB*2
 *
 * NOTE: In all cases 0 <= i <= BASEB
 */
HALF highhalf[BASEB+1] = {
#if BASEB == 32
        0x00000000,
        0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
        0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
        0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
        0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
        0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
        0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
        0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
        0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF
#elif BASEB == 16
        0x0000,
        0x8000, 0xC000, 0xE000, 0xF000,
        0xF800, 0xFC00, 0xFE00, 0xFF00,
        0xFF80, 0xFFC0, 0xFFE0, 0xFFF0,
        0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF
#else
        -=@=- BASEB not 16 or 32 -=@=-
#endif
};
HALF rhighhalf[BASEB+1] = {
#if BASEB == 32
        0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,
        0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,
        0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800,
        0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000,
        0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000,
        0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000,
        0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000,
        0xF0000000, 0xE0000000, 0xC0000000, 0x80000000,
        0x00000000
#elif BASEB == 16
        0xFFFF, 0xFFFE, 0xFFFC, 0xFFF8,
        0xFFF0, 0xFFE0, 0xFFC0, 0xFF80,
        0xFF00, 0xFE00, 0xFC00, 0xF800,
        0xF000, 0xE000, 0xC000, 0x8000,
        0x0000
#else
        -=@=- BASEB not 16 or 32 -=@=-
#endif
};
HALF lowhalf[BASEB+1] = {
        0x0,
        0x1,  0x3, 0x7, 0xF,
        0x1F,  0x3F, 0x7F, 0xFF,
        0x1FF,  0x3FF, 0x7FF, 0xFFF,
        0x1FFF,  0x3FFF, 0x7FFF, 0xFFFF
#if BASEB == 32
       ,0x1FFFF,  0x3FFFF, 0x7FFFF, 0xFFFFF,
        0x1FFFFF,  0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
        0x1FFFFFF,  0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
        0x1FFFFFFF,  0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
#endif
};
HALF rlowhalf[BASEB+1] = {
#if BASEB == 32
        0xFFFFFFFF, 0x7FFFFFFF, 0x3FFFFFFF, 0x1FFFFFFF,
        0xFFFFFFF, 0x7FFFFFF, 0x3FFFFFF, 0x1FFFFFF,
        0xFFFFFF, 0x7FFFFF, 0x3FFFFF, 0x1FFFFF,
        0xFFFFF, 0x7FFFF, 0x3FFFF, 0x1FFFF,
#endif
        0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF,
        0xFFF, 0x7FF, 0x3FF, 0x1FF,
        0xFF, 0x7F, 0x3F, 0x1F,
        0xF, 0x7, 0x3, 0x1,
        0x0
};
HALF bitmask[(2*BASEB)+1] = {
#if BASEB == 32
        0x00000001, 0x00000002, 0x00000004, 0x00000008,
        0x00000010, 0x00000020, 0x00000040, 0x00000080,
        0x00000100, 0x00000200, 0x00000400, 0x00000800,
        0x00001000, 0x00002000, 0x00004000, 0x00008000,
        0x00010000, 0x00020000, 0x00040000, 0x00080000,
        0x00100000, 0x00200000, 0x00400000, 0x00800000,
        0x01000000, 0x02000000, 0x04000000, 0x08000000,
        0x10000000, 0x20000000, 0x40000000, 0x80000000,
        0x00000001, 0x00000002, 0x00000004, 0x00000008,
        0x00000010, 0x00000020, 0x00000040, 0x00000080,
        0x00000100, 0x00000200, 0x00000400, 0x00000800,
        0x00001000, 0x00002000, 0x00004000, 0x00008000,
        0x00010000, 0x00020000, 0x00040000, 0x00080000,
        0x00100000, 0x00200000, 0x00400000, 0x00800000,
        0x01000000, 0x02000000, 0x04000000, 0x08000000,
        0x10000000, 0x20000000, 0x40000000, 0x80000000,
        0x00000001
#elif BASEB == 16
        0x0001, 0x0002, 0x0004, 0x0008,
        0x0010, 0x0020, 0x0040, 0x0080,
        0x0100, 0x0200, 0x0400, 0x0800,
        0x1000, 0x2000, 0x4000, 0x8000,
        0x0001, 0x0002, 0x0004, 0x0008,
        0x0010, 0x0020, 0x0040, 0x0080,
        0x0100, 0x0200, 0x0400, 0x0800,
        0x1000, 0x2000, 0x4000, 0x8000,
        0x0001
#else
        -=@=- BASEB not 16 or 32 -=@=-
#endif
};              /* actual rotation thru 8 cycles */

bool _math_abort_;              /* nonzero to abort calculations */


/*
 * popcnt - popcnt[x] number of 1 bits in 0 <= x < 256
 */
char popcnt[256] = {
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};



#ifdef ALLOCTEST
STATIC long nalloc = 0;
STATIC long nfree = 0;
#endif


HALF *
alloc(LEN len)
{
        HALF *hp;

        if (_math_abort_) {
                math_error("Calculation aborted");
                not_reached();
        }
        hp = (HALF *) malloc((len+1) * sizeof(HALF));
        if (hp == 0) {
                math_error("Not enough memory");
                not_reached();
        }
#ifdef ALLOCTEST
        ++nalloc;
#endif
        return hp;
}


/*
 * is_const - determine if a HALF array is an pre-allocated array
 *
 * given:
 *      h       pointer to the beginning of the HALF array
 *
 * returns:
 *      true - h is found in the half_tbl array
 *      false - is is not found in the half_tbl array
 */
int
is_const(HALF *h)
{
        HALF **h_p;     /* half_tbl array pointer */

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

        /* search the half_tbl for h */
        for (h_p = &half_tbl[0]; *h_p != NULL; ++h_p) {
                if (h == *h_p) {
                        return true;    /* found in the half_tbl array */
                }
        }

        /* not found in the half_tbl array */
        return false;
}


#ifdef ALLOCTEST
void
freeh(HALF *h)
{
        /* firewall */
        if (h == NULL) {
                math_error("%s: h NULL", __func__);
                not_reached();
        }

        /* free h is not a constant */
        if (!is_const(h)) {
                free(h);
                ++nfree;
        }
}


void
allocStat(void)
{
        fprintf(stderr, "nalloc: %ld nfree: %ld kept: %ld\n",
                nalloc, nfree, nalloc - nfree);
}
#endif


/*
 * Convert a normal integer to a number.
 */
void
itoz(long i, ZVALUE *res)
{
        long diddle, len;

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

        res->len = 1;
        res->sign = 0;
        diddle = 0;
        if (i == 0) {
                res->v = _zeroval_;
                return;
        }
        if (i < 0) {
                res->sign = 1;
                i = -i;
                if (i < 0) {    /* fix most negative number */
                        diddle = 1;
                        i--;
                }
        }
        if (i == 1) {
                res->v = _oneval_;
                return;
        }
        len = 1 + (((FULL) i) >= BASE);
        res->len = (LEN)len;
        res->v = alloc((LEN)len);
        res->v[0] = (HALF) (i + diddle);
        if (len == 2)
                res->v[1] = (HALF) (i / BASE);
}


/*
 * Convert a number to a normal integer, as far as possible.
 * If the number is out of range, the largest number is returned.
 */
long
ztoi(ZVALUE z)
{
        long i;

        if (zgtmaxlong(z)) {
                i = MAXLONG;
                return (z.sign ? -i : i);
        }
        i = ztolong(z);
        return (z.sign ? -i : i);
}


/*
 * Convert a normal unsigned integer to a number.
 */
void
utoz(FULL i, ZVALUE *res)
{
        long len;

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

        res->len = 1;
        res->sign = 0;
        if (i == 0) {
                res->v = _zeroval_;
                return;
        }
        if (i == 1) {
                res->v = _oneval_;
                return;
        }
        len = 1 + (((FULL) i) >= BASE);
        res->len = (LEN)len;
        res->v = alloc((LEN)len);
        res->v[0] = (HALF)i;
        if (len == 2)
                res->v[1] = (HALF) (i / BASE);
}


/*
 * Convert a normal signed integer to a number.
 */
void
stoz(SFULL i, ZVALUE *res)
{
        long diddle, len;

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

        res->len = 1;
        res->sign = 0;
        diddle = 0;
        if (i == 0) {
                res->v = _zeroval_;
                return;
        }
        if (i < 0) {
                res->sign = 1;
                i = -i;
                if (i < 0) {    /* fix most negative number */
                        diddle = 1;
                        i--;
                }
        }
        if (i == 1) {
                res->v = _oneval_;
                return;
        }
        len = 1 + (((FULL) i) >= BASE);
        res->len = (LEN)len;
        res->v = alloc((LEN)len);
        res->v[0] = (HALF) (i + diddle);
        if (len == 2)
                res->v[1] = (HALF) (i / BASE);
}


/*
 * Convert a number to a unsigned normal integer, as far as possible.
 * If the number is out of range, the largest number is returned.
 * The absolute value of z is converted.
 */
FULL
ztou(ZVALUE z)
{
        if (z.len > 2) {
                return MAXUFULL;
        }
        return ztofull(z);
}


/*
 * Convert a number to a signed normal integer, as far as possible.
 *
 * If the number is too large to fit into an integer, than the largest
 * positive or largest negative integer is returned depending on the sign.
 */
SFULL
ztos(ZVALUE z)
{
        FULL val;       /* absolute value of the return value */

        /* negative value processing */
        if (z.sign) {
            if (z.len > 2) {
                return MINSFULL;
            }
            val = ztofull(z);
            if (val > TOPFULL) {
                return MINSFULL;
            }
            return (SFULL)(-val);
        }

        /* positive value processing */
        if (z.len > 2) {
            return (SFULL)MAXFULL;
        }
        val = ztofull(z);
        if (val > MAXFULL) {
            return (SFULL)MAXFULL;
        }
        return (SFULL)val;
}


/*
 * Make a copy of an integer value
 */
void
zcopy(ZVALUE z, ZVALUE *res)
{
        /* firewall */
        if (res == NULL) {
                math_error("%s: res NULL", __func__);
                not_reached();
        }

        /* make copy */
        res->sign = z.sign;
        res->len = z.len;
        if (zisabsleone(z)) {   /* zero or plus or minus one are easy */
                res->v = (z.v[0] ? _oneval_ : _zeroval_);
                return;
        }
        res->v = alloc(z.len);
        zcopyval(z, *res);
}


/*
 * Add together two integers.
 */
void
zadd(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        ZVALUE dest;
        HALF *p1, *p2, *pd;
        long len;
        FULL carry;
        SIUNION sival;

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

        if (z1.sign && !z2.sign) {
                z1.sign = 0;
                zsub(z2, z1, res);
                return;
        }
        if (z2.sign && !z1.sign) {
                z2.sign = 0;
                zsub(z1, z2, res);
                return;
        }
        if (z2.len > z1.len) {
                pd = z1.v; z1.v = z2.v; z2.v = pd;
                len = z1.len; z1.len = z2.len; z2.len = (LEN)len;
        }
        dest.len = z1.len + 1;
        dest.v = alloc(dest.len);
        dest.sign = z1.sign;
        carry = 0;
        pd = dest.v;
        p1 = z1.v;
        p2 = z2.v;
        len = z2.len;
        while (len--) {
                sival.ivalue = ((FULL) *p1++) + ((FULL) *p2++) + carry;
                /* ignore Saber-C warning #112 - get ushort from uint */
                /*        OK to ignore on name zadd`sival */
                *pd++ = sival.silow;
                carry = sival.sihigh;
        }
        len = z1.len - z2.len;
        while (len--) {
                sival.ivalue = ((FULL) *p1++) + carry;
                *pd++ = sival.silow;
                carry = sival.sihigh;
        }
        *pd = (HALF)carry;
        zquicktrim(dest);
        *res = dest;
}


/*
 * Subtract two integers.
 */
void
zsub(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        register HALF *h1, *h2, *hd;
        long len1, len2;
        FULL carry;
        SIUNION sival;
        ZVALUE dest;

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

        if (z1.sign != z2.sign) {
                z2.sign = z1.sign;
                zadd(z1, z2, res);
                return;
        }
        len1 = z1.len;
        len2 = z2.len;
        if (len1 == len2) {
                h1 = z1.v + len1;
                h2 = z2.v + len2;
                while ((len1 > 0) && ((FULL)*--h1 == (FULL)*--h2)) {
                        len1--;
                }
                if (len1 == 0) {
                        *res = _zero_;
                        return;
                }
                len2 = len1;
                carry = ((FULL)*h1 < (FULL)*h2);
        } else {
                carry = (len1 < len2);
        }
        dest.sign = z1.sign;
        h1 = z1.v;
        h2 = z2.v;
        if (carry) {
                carry = len1;
                len1 = len2;
                len2 = (long)carry;
                h1 = z2.v;
                h2 = z1.v;
                dest.sign = !dest.sign;
        }
        hd = alloc((LEN)len1);
        dest.v = hd;
        dest.len = (LEN)len1;
        len1 -= len2;
        carry = 0;
        while (--len2 >= 0) {
                /* ignore Saber-C warning #112 - get ushort from uint */
                /*        OK to ignore on name zsub`sival */
                sival.ivalue = (BASE1 - ((FULL) *h1++)) + *h2++ + carry;
                *hd++ = (HALF)(BASE1 - sival.silow);
                carry = sival.sihigh;
        }
        while (--len1 >= 0) {
                sival.ivalue = (BASE1 - ((FULL) *h1++)) + carry;
                *hd++ = (HALF)(BASE1 - sival.silow);
                carry = sival.sihigh;
        }
        if (hd[-1] == 0)
                ztrim(&dest);
        *res = dest;
}


/*
 * Multiply an integer by a small number.
 */
void
zmuli(ZVALUE z, long n, ZVALUE *res)
{
        register HALF *h1, *sd;
        FULL low;
        FULL high;
        FULL carry;
        long len;
        SIUNION sival;
        ZVALUE dest;

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

        if ((n == 0) || ziszero(z)) {
                *res = _zero_;
                return;
        }
        if (n < 0) {
                n = -n;
                z.sign = !z.sign;
        }
        if (n == 1) {
                zcopy(z, res);
                return;
        }
#if LONG_BITS > BASEB
        low = ((FULL) n) & BASE1;
        high = ((FULL) n) >> BASEB;
#else
        low = (FULL)n;
        high = 0;
#endif
        dest.len = z.len + 2;
        dest.v = alloc(dest.len);
        dest.sign = z.sign;
        /*
         * Multiply by the low digit.
         */
        h1 = z.v;
        sd = dest.v;
        len = z.len;
        carry = 0;
        while (len--) {
                /* ignore Saber-C warning #112 - get ushort from uint */
                /*        OK to ignore on name zmuli`sival */
                sival.ivalue = ((FULL) *h1++) * low + carry;
                *sd++ = sival.silow;
                carry = sival.sihigh;
        }
        *sd = (HALF)carry;
        /*
         * If there was only one digit, then we are all done except
         * for trimming the number if there was no last carry.
         */
        if (high == 0) {
                dest.len--;
                if (carry == 0)
                        dest.len--;
                *res = dest;
                return;
        }
        /*
         * Need to multiply by the high digit and add it into the
         * previous value.  Clear the final word of rubbish first.
         */
        *(++sd) = 0;
        h1 = z.v;
        sd = dest.v + 1;
        len = z.len;
        carry = 0;
        while (len--) {
                sival.ivalue = ((FULL) *h1++) * high + ((FULL) *sd) + carry;
                *sd++ = sival.silow;
                carry = sival.sihigh;
        }
        *sd = (HALF)carry;
        zquicktrim(dest);
        *res = dest;
}


/*
 * Divide two numbers by their greatest common divisor.
 * This is useful for reducing the numerator and denominator of
 * a fraction to its lowest terms.
 */
void
zreduce(ZVALUE z1, ZVALUE z2, ZVALUE *z1res, ZVALUE *z2res)
{
        ZVALUE tmp;

        /* firewall */
        if (z1res == NULL) {
                math_error("%s: z1res NULL", __func__);
                not_reached();
        }
        if (z2res == NULL) {
                math_error("%s: z2res NULL", __func__);
                not_reached();
        }

        if (zisabsleone(z1) || zisabsleone(z2))
                tmp = _one_;
        else
                zgcd(z1, z2, &tmp);
        if (zisunit(tmp)) {
                zcopy(z1, z1res);
                zcopy(z2, z2res);
        } else {
                zequo(z1, tmp, z1res);
                zequo(z2, tmp, z2res);
        }
        zfree(tmp);
}



/*
 * Compute the quotient and remainder for division of an integer by an
 * integer, rounding criteria determined by rnd.  Returns the sign of
 * the remainder.
 */
long
zdiv(ZVALUE z1, ZVALUE z2, ZVALUE *quo, ZVALUE *rem, long rnd)
{
        register HALF *a, *b;
        HALF s, u;
        HALF *A, *B, *a1, *b0;
        FULL f, g, h, x;
        bool adjust, onebit;
        LEN m, n, len, i, p, j1, j2, k;
        long t, val;

        /* firewall */
        if (quo == NULL) {
                math_error("%s: quo NULL", __func__);
                not_reached();
        }
        if (rem == NULL) {
                math_error("%s: rem NULL", __func__);
                not_reached();
        }

        if (ziszero(z2)) {
                math_error("Division by zero in zdiv");
                not_reached();
        }
        m = z1.len;
        n = z2.len;
        B = z2.v;
        s = 0;
        if (m < n) {
                A = alloc(n + 1);
                memcpy(A, z1.v, m * sizeof(HALF));
                for (i = m; i <= n; i++)
                        A[i] = 0;
                a1 = A + n;
                len = 1;
                goto done;
        }
        A = alloc(m + 2);
        memcpy(A, z1.v, m * sizeof(HALF));
        A[m] = 0;
        A[m + 1] = 0;
        len = m - n + 1;        /* quotient length will be len or len +/- 1 */
        a1 = A + n;             /* start of digits for quotient */
        b0 = B;
        p = n;
        while (!*b0) {          /* b0: working start for divisor */
                ++b0;
                --p;
        }
        if (p == 1) {
                u = *b0;
                if (u == 1) {
                        for (; m >= n; m--)
                                A[m] = A[m - 1];
                        A[m] = 0;
                        goto done;
                }
                f = 0;
                a = A + m;
                i = len;
                while (i--) {
                        f = f << BASEB | *--a;
                        a[1] = (HALF)(f / u);
                        f = f % u;
                }
                *a = (HALF)f;
                m = n;
                goto done;
        }
        f = B[n - 1];
        k = 1;
        while (f >>= 1)
                k++;            /* k: number of bits in top divisor digit */
        j1 = BASEB - k;
        j2 = BASEB + j1;
        h = j1 ? ((FULL) B[n - 1] << j1 | B[n - 2] >> k) : B[n-1];
        onebit = (bool)((B[n - 2] >> (k - 1)) & 1);
        m++;
        while (m > n) {
                m--;
                f = (FULL) A[m] << j2 | (FULL) A[m - 1] << j1;
                if (j1) f |= A[m - 2] >> k;
                if (s) f = ~f;
                x = f / h;
                if (x) {
                        if (onebit && x > TOPHALF + f % h)
                                x--;
                        a = A + m - p;
                        b = b0;
                        u = 0;
                        i = p;
                        if (s) {
                                while (i--) {
                                        f = (FULL) *a + u + x * *b++;
                                        *a++ = (HALF) f;
                                        u = (HALF) (f >> BASEB);
                                }
                                s = *a + u;
                                A[m] = (HALF) (~x + !s);
                        } else {
                                while (i--) {
                                        f = (FULL) *a - u - x * *b++;
                                        *a++ = (HALF) f;
                                        u = -(HALF)(f >> BASEB);
                                }
                                s = *a - u;
                                A[m] = (HALF)(x + s);
                        }
                }
                else
                        A[m] = s;
        }
done:   while (m > 0 && A[m - 1] == 0)
                m--;
        if (m == 0 && s == 0) {
                *rem = _zero_;
                val = 0;
                if (a1[len - 1] == 0)
                        len--;
                if (len == 0) {
                        *quo = _zero_;
                } else {
                        quo->len = len;
                        quo->v = alloc(len);
                        memcpy(quo->v, a1, len * sizeof(HALF));
                        quo->sign = z1.sign ^ z2.sign;
                }
                freeh(A);
                return val;
        }
        if (rnd & 8)
                adjust = (((*a1 ^ rnd) & 1) ? true : false);
        else
                adjust = (((rnd & 1) ^ z1.sign ^ z2.sign) ? true : false);
        if (rnd & 2)
                adjust ^= z1.sign ^ z2.sign;
        if (rnd & 4)
                adjust ^= z2.sign;
        if (rnd & 16) {                 /* round-off case */
                a = A + n;
                b = B + n;
                i = n + 1;
                f = g = 0;
                t = -1;
                if (s) {
                        while (--i > 0) {
                                g = (FULL) *--a + (*--b >> 1 | f);
                                f = *b & 1 ? TOPHALF : 0;
                                if (g != BASE1)
                                        break;
                        }
                        if (g == BASE && f == 0) {
                                while ((--i > 0) && ((*--a | *--b) == 0));
                                t = (i > 0);
                        } else if (g >= BASE) {
                                t = 1;
                        }
                } else {
                        while (--i > 0) {
                                g = (FULL) *--a - (*--b >> 1 | f);
                                f = *b & 1 ? TOPHALF : 0;
                                if (g != 0)
                                        break;
                        }
                        if (g > 0 && g < BASE)
                                t = 1;
                        else if (g == 0 && f == 0)
                                t = 0;
                }
                if (t)
                        adjust = (t > 0);
        }
        if (adjust) {
                i = len;
                a = a1;
                while (i > 0 && *a == BASE1) {
                        i--;
                        *a++ = 0;
                }
                (*a)++;
                if (i == 0)
                        len++;
        }
        if (s && adjust) {
                i = 0;
                while (A[i] == 0)
                        i++;
                A[i] = -A[i];
                while (++i < n)
                        A[i] = ~A[i];
                m = n;
                while (A[m - 1] == 0)
                        m--;
        }
        if (!s && adjust) {
                a = A;
                b = B;
                i = n;
                u = 0;
                while (i--) {
                        f = (FULL) *b++ - *a - (FULL) u;
                        *a++ = (HALF) f;
                        u = -(HALF)(f >> BASEB);
                }
                m = n;
                while (A[m - 1] == 0)
                        m--;
        }
        if (s && !adjust) {
                a = A;
                b = B;
                i = n;
                f = 0;
                while (i--) {
                        f = (FULL) *b++ + *a + (f >> BASEB);
                        *a++ = (HALF) f;
                }
                m = n;
                while (A[m-1] == 0)
                        m--;
        }
        rem->len = m;
        rem->v = alloc(m);
        memcpy(rem->v, A, m * sizeof(HALF));
        rem->sign = z1.sign ^ adjust;
        val = rem->sign ? -1 : 1;
        if (a1[len - 1] == 0)
                len--;
        if (len == 0) {
                *quo = _zero_;
        } else {
                quo->len = len;
                quo->v = alloc(len);
                memcpy(quo->v, a1, len * sizeof(HALF));
                quo->sign = z1.sign ^ z2.sign;
        }
        freeh(A);
        return val;
}


/*
 * Compute and store at a specified location the integer quotient
 * of two integers, the type of rounding being determined by rnd.
 * Returns the sign of z1/z2 - calculated quotient.
 */
long
zquo(ZVALUE z1, ZVALUE z2, ZVALUE *res, long rnd)
{
        ZVALUE tmp;
        long val;

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

        val = zdiv(z1, z2, res, &tmp, rnd);
        if (z2.sign)
                val = -val;
        zfree(tmp);
        return val;
}


/*
 * Compute and store at a specified location the remainder for
 * division of an integer by an integer, the type of rounding
 * used being determined by rnd.  Returns the sign of the remainder.
 */
long
zmod(ZVALUE z1, ZVALUE z2, ZVALUE *res, long rnd)
{
        ZVALUE tmp;
        long val;

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

        val = zdiv(z1, z2, &tmp, res, rnd);
        zfree(tmp);
        return val;
}


/*
 * Computes the quotient z1/z2 on the assumption that this is exact.
 * There is no thorough check on the exactness of the division
 * so this should not be called unless z1/z2 is an integer.
 */
void
zequo(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        LEN i, j, k, len, m, n, o, p;
        HALF *a, *a0, *A, *b, *B, u, v, w, x;
        FULL f, g;

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

        if (ziszero(z1)) {
                *res = _zero_;
                return;
        }
        if (ziszero(z2)) {
                math_error("Division by zero");
                not_reached();
        }
        if (zisone(z2)) {
                zcopy(z1, res);
                return;
        }
        if (zhighbit(z1) < zhighbit(z2)) {
                math_error("Bad call to zequo");
                not_reached();
        }
        B = z2.v;
        o = 0;
        while (!*B) {
                ++B;
                ++o;
        }
        m = z1.len - o;
        n = z2.len - o;
        len = m - n + 1;                /* Maximum length of quotient */
        v = *B;
        A = alloc(len+1);
        memcpy(A, z1.v + o, len * sizeof(HALF));
        A[len] = 0;
        if (n == 1) {
                if (v > 1) {
                        a = A + len;
                        i = len;
                        f = 0;
                        while (i--) {
                                f = f << BASEB | *--a;
                                *a = (HALF)(f / v);
                                f %= v;
                        }
                }
        } else {
                k = 0;
                while (!(v & 1)) {
                        k++;
                        v >>= 1;
                }
                j = BASEB - k;
                if (n > 1 && k > 0)
                        v |= B[1] << j;
                u = v - 1;
                w = x = 1;
                while (u) {     /* To find w = inverse of v modulo BASE */
                        do {
                                v <<= 1;
                                x <<= 1;
                        }
                        while (!(u & x));
                        u += v;
                        w |= x;
                }
                a0 = A;
                p = len;
                while (p > 1) {
                        if (!*a0) {
                                while (!*++a0 && p > 1)
                                        p--;
                                --a0;
                        }
                        if (p == 1)
                                break;
                        x = k ? w * (*a0 >> k | a0[1] << j) : w * *a0;
                        g = x;
                        if (x) {
                                a = a0;
                                b = B;
                                u = 0;
                                i = n;
                                if (i > p)
                                        i = p;
                                while (i--) {
                                        f = (FULL) *a - g * *b++ - (FULL) u;
                                        *a++ = (HALF)f;
                                        u = -(HALF)(f >> BASEB);
                                }
                                if (u && p > n) {
                                        i = p - n;
                                        while (u && i--) {
                                                f = (FULL) *a - u;
                                                *a++ = (HALF) f;
                                                u = -(HALF)(f >> BASEB);
                                        }
                                }
                        }
                        *a0++ = x;
                        p--;
                }
                if (k == 0) {
                        *a0 = w * *a0;
                } else {
                        u = (HALF)(w * *a0) >> k;
                        x = (HALF)(((FULL) z1.v[z1.len - 1] << BASEB
                                | z1.v[z1.len - 2])
                                /((FULL) B[n-1] << BASEB | B[n-2]));
                        if ((x ^ u) & 1) x--;
                        *a0 = x;
                }
        }
        if (!A[len - 1]) len--;
        res->v = A;
        res->len = len;
        res->sign = z1.sign != z2.sign;
}



/*
 * Return the quotient and remainder of an integer divided by a small
 * number.  A nonzero remainder is only meaningful when both numbers
 * are positive.
 */
long
zdivi(ZVALUE z, long n, ZVALUE *res)
{
        HALF *h1, *sd;
        FULL val;
        HALF divval[2];
        ZVALUE div;
        ZVALUE dest;
        LEN len;

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

        if (n == 0) {
                math_error("Division by zero");
                not_reached();
        }
        if (ziszero(z)) {
                *res = _zero_;
                return 0;
        }
        if (n < 0) {
                n = -n;
                z.sign = !z.sign;
        }
        if (n == 1) {
                zcopy(z, res);
                return 0;
        }
        /*
         * If the division is by a large number, then call the normal
         * divide routine.
         */
        if (n & ~BASE1) {
                div.sign = 0;
                div.v = divval;
                divval[0] = (HALF) n;
#if LONG_BITS > BASEB
                divval[1] = (HALF)(((FULL) n) >> BASEB);
                div.len = 2;
#else
                div.len = 1;
#endif
                zdiv(z, div, res, &dest, 0);
                n = ztolong(dest);
                zfree(dest);
                return n;
        }
        /*
         * Division is by a small number, so we can be quick about it.
         */
        len = z.len;
        dest.sign = z.sign;
        dest.len = len;
        dest.v = alloc(len);
        h1 = z.v + len;
        sd = dest.v + len;
        val = 0;
        while (len--) {
                val = ((val << BASEB) + ((FULL) *--h1));
                *--sd = (HALF)(val / n);
                val %= n;
        }
        zquicktrim(dest);
        *res = dest;
        return (long)val;
}



/*
 * Calculate the mod of an integer by a small number.
 * This is only defined for positive moduli.
 */
long
zmodi(ZVALUE z, long n)
{
        register HALF *h1;
        FULL val;
        HALF divval[2];
        ZVALUE div;
        ZVALUE temp;
        long len;

        if (n == 0) {
                math_error("Division by zero");
                not_reached();
        }
        if (n < 0) {
                math_error("Non-positive modulus");
                not_reached();
        }
        if (ziszero(z) || (n == 1))
                return 0;
        if (zisone(z))
                return 1;
        /*
         * If the modulus is by a large number, then call the normal
         * modulo routine.
         */
        if (n & ~BASE1) {
                div.sign = 0;
                div.v = divval;
                divval[0] = (HALF) n;
#if LONG_BITS > BASEB
                divval[1] = (HALF)(((FULL) n) >> BASEB);
                div.len = 2;
#else
                div.len = 1;
#endif
                zmod(z, div, &temp, 0);
                n = ztolong(temp);
                zfree(temp);
                return n;
        }
        /*
         * The modulus is by a small number, so we can do this quickly.
         */
        len = z.len;
        h1 = z.v + len;
        val = 0;
        while (len-- > 0)
                val = ((val << BASEB) + ((FULL) *--h1)) % n;
        if (val && z.sign)
                val = n - val;
        return (long)val;
}


/*
 * Return whether or not one number exactly divides another one.
 * Returns true if division occurs with no remainder.
 * z1 is the number to be divided by z2.
 */

bool
zdivides(ZVALUE z1, ZVALUE z2)
{
        LEN i, j, k, m, n;
        HALF u, v, w, x;
        HALF *a, *a0, *A, *b, *B, *c, *d;
        FULL f;
        bool ans;

        if (zisunit(z2) || ziszero(z1)) return true;
        if (ziszero(z2)) return false;

        m = z1.len;
        n = z2.len;
        if (m < n) return false;

        c = z1.v;
        d = z2.v;

        while (!*d) {
                if (*c++) return false;
                d++;
                m--;
                n--;
        }

        j = 0;
        u = *c;
        v = *d;
        while (!(v & 1)) {      /* Counting and checking zero bits */
                if (u & 1) return false;
                u >>= 1;
                v >>= 1;
                j++;
        }

        if (n == 1 && v == 1) return true;
        if (!*c) {                      /* Removing any further zeros */
                while(!*++c)
                        m--;
                c--;
        }

        if (m < n) return false;

        if (j) {
                B = alloc((LEN)n);      /* Array for shifted z2 */
                d += n;
                b = B + n;
                i = n;
                f = 0;
                while(i--) {
                        f = f << BASEB | *--d;
                        *--b = (HALF)(f >> j);
                }
                if (!B[n - 1]) n--;
        }
        else B = d;
        u = *B;
        v = x = 1;
        w = 0;
        while (x) {                     /* Finding minv(*B, BASE) */
                if (v & x) {
                        v -= x * u;
                        w |= x;
                }
                x <<= 1;
        }

        A = alloc((LEN)(m + 2));        /* Main working array */
        memcpy(A, c, m * sizeof(HALF));
        A[m + 1] = 1;
        A[m] = 0;

        k = m - n + 1;                  /* Length of presumed quotient */

        a0 = A;

        while (k--) {
                if (*a0) {
                        x = w * *a0;
                        a = a0;
                        b = B;
                        i = n;
                        u = 0;
                        while (i--) {
                                f = (FULL) *a - (FULL) x * *b++ - u;
                                *a++ = (HALF)f;
                                u = -(HALF)(f >> BASEB);
                        }
                        f = (FULL) *a - u;
                        *a++ = (HALF)f;
                        u = -(HALF)(f >> BASEB);
                        if (u) {
                                while (*a == 0) *a++ = BASE1;
                                (*a)--;
                        }
                }
                a0++;
        }
        ans = false;
        if (A[m + 1]) {
                a = A + m;
                while (--n && !*--a);
                if (!n) ans = true;
        }
        freeh(A);
        if (j) freeh(B);
        return ans;
}


/*
 * Compute the bitwise OR of two integers
 */
void
zor(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        register HALF *sp, *dp;
        long len;
        ZVALUE bz, lz, dest;

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

        if (z1.len >= z2.len) {
                bz = z1;
                lz = z2;
        } else {
                bz = z2;
                lz = z1;
        }
        dest.len = bz.len;
        dest.v = alloc(dest.len);
        dest.sign = 0;
        zcopyval(bz, dest);
        len = lz.len;
        sp = lz.v;
        dp = dest.v;
        while (len--)
                *dp++ |= *sp++;
        *res = dest;
}


/*
 * Compute the bitwise AND of two integers
 */
void
zand(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        HALF *h1, *h2, *hd;
        LEN len;
        ZVALUE dest;

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

        len = ((z1.len <= z2.len) ? z1.len : z2.len);
        h1 = &z1.v[len-1];
        h2 = &z2.v[len-1];
        while ((len > 1) && ((*h1 & *h2) == 0)) {
                h1--;
                h2--;
                len--;
        }
        dest.len = len;
        dest.v = alloc(len);
        dest.sign = 0;
        h1 = z1.v;
        h2 = z2.v;
        hd = dest.v;
        while (len--)
                *hd++ = (*h1++ & *h2++);
        *res = dest;
}


/*
 * Compute the bitwise XOR of two integers.
 */
void
zxor(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        HALF *dp, *h1, *h2;
        LEN len, j, k;
        ZVALUE dest;

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

        h1 = z1.v;
        h2 = z2.v;
        len = z1.len;
        j = z2.len;
        if (z1.len < z2.len) {
                len = z2.len;
                j = z1.len;
                h1 = z2.v;
                h2 = z1.v;
        } else if (z1.len == z2.len) {
                while (len > 1 && z1.v[len-1] == z2.v[len-1])
                        len--;
                j = len;
        }
        k = len - j;
        dest.len = len;
        dest.v = alloc(len);
        dest.sign = 0;
        dp = dest.v;
        while (j-- > 0)
                *dp++ = *h1++ ^ *h2++;
        while (k-- > 0)
                *dp++ = *h1++;
        *res = dest;
}


/*
 * Compute the bitwise AND NOT of two integers.
 */
void
zandnot(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
        HALF *dp, *h1, *h2;
        LEN len, j, k;
        ZVALUE dest;

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

        len = z1.len;
        if (z2.len >= len) {
                while (len > 1 && (z1.v[len-1] & ~z2.v[len-1]) == 0)
                        len--;
                j = len;
                k = 0;
        } else {
                j = z2.len;
                k = len - z2.len;
        }
        dest.len = len;
        dest.v = alloc(len);
        dest.sign = 0;
        dp = dest.v;
        h1 = z1.v;
        h2 = z2.v;
        while (j-- > 0)
                *dp++ = *h1++ & ~*h2++;
        while (k-- > 0)
                *dp++ = *h1++;
        *res = dest;
}


/*
 * Shift a number left (or right) by the specified number of bits.
 * Positive shift means to the left.  When shifting right, rightmost
 * bits are lost.  The sign of the number is preserved.
 */
void
zshift(ZVALUE z, long n, ZVALUE *res)
{
        ZVALUE ans;
        LEN hc;         /* number of halfwords shift is by */

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

        if (ziszero(z)) {
                *res = _zero_;
                return;
        }
        if (n == 0) {
                zcopy(z, res);
                return;
        }
        /*
         * If shift value is negative, then shift right.
         * Check for large shifts, and handle word-sized shifts quickly.
         */
        if (n < 0) {
                n = -n;
                if ((n < 0) || (n >= (z.len * BASEB))) {
                        *res = _zero_;
                        return;
                }
                hc = (LEN)(n / BASEB);
                n %= BASEB;
                z.v += hc;
                z.len -= hc;
                ans.len = z.len;
                ans.v = alloc(ans.len);
                ans.sign = z.sign;
                zcopyval(z, ans);
                if (n > 0) {
                        zshiftr(ans, n);
                        ztrim(&ans);
                }
                if (ziszero(ans)) {
                        zfree(ans);
                        ans = _zero_;
                }
                *res = ans;
                return;
        }
        /*
         * Shift value is positive, so shift leftwards.
         * Check specially for a shift of the value 1, since this is common.
         * Also handle word-sized shifts quickly.
         */
        if (zisunit(z)) {
                zbitvalue(n, res);
                res->sign = z.sign;
                return;
        }
        hc = (LEN)(n / BASEB);
        n %= BASEB;
        ans.len = z.len + hc + 1;
        ans.v = alloc(ans.len);
        ans.sign = z.sign;
        if (hc > 0)
                memset((char *) ans.v, 0, hc * sizeof(HALF));
        memcpy((char *) (ans.v + hc),
            (char *) z.v, z.len * sizeof(HALF));
        ans.v[ans.len - 1] = 0;
        if (n > 0) {
                ans.v += hc;
                ans.len -= hc;
                zshiftl(ans, n);
                ans.v -= hc;
                ans.len += hc;
        }
        ztrim(&ans);
        *res = ans;
}


/*
 * Return the position of the lowest bit which is set in the binary
 * representation of a number (counting from zero).  This is the highest
 * power of two which evenly divides the number.
 */
long
zlowbit(ZVALUE z)
{
        register HALF *zp;
        long n;
        HALF dataval;
        HALF *bitval;

        n = 0;
        for (zp = z.v; *zp == 0; zp++)
                if (++n >= z.len)
                        return 0;
        dataval = *zp;
        bitval = bitmask;
        /* ignore Saber-C warning #530 about empty while statement */
        /*        OK to ignore in proc zlowbit */
        while ((*(bitval++) & dataval) == 0) {
        }
        return (n*BASEB)+(bitval-bitmask-1);
}


/*
 * Return the position of the highest bit which is set in the binary
 * representation of a number (counting from zero).  This is the highest power
 * of two which is less than or equal to the number (which is assumed nonzero).
 */
LEN
zhighbit(ZVALUE z)
{
        HALF dataval;
        HALF *bitval;

        dataval = z.v[z.len-1];
        if (dataval == 0) {
                return 0;
        }
        bitval = bitmask+BASEB;
        if (dataval) {
                /* ignore Saber-C warning #530 about empty while statement */
                /*        OK to ignore in proc zhighbit */
                while ((*(--bitval) & dataval) == 0) {
                }
        }
        return (z.len*BASEB)+(LEN)(bitval-bitmask-BASEB);
}


/*
 * Return whether or not the specified bit number is set in a number.
 * Rightmost bit of a number is bit 0.
 */
bool
zisset(ZVALUE z, long n)
{
        if ((n < 0) || ((n / BASEB) >= z.len))
                return false;
        return ((z.v[n / BASEB] & (((HALF) 1) << (n % BASEB))) != 0);
}


/*
 * Check whether or not a number has exactly one bit set, and
 * thus is an exact power of two.  Returns true if so.
 */
bool
zisonebit(ZVALUE z)
{
        register HALF *hp;
        register LEN len;

        if (ziszero(z) || zisneg(z))
                return false;
        hp = z.v;
        len = z.len;
        while (len > 4) {
                len -= 4;
                if (*hp++ || *hp++ || *hp++ || *hp++)
                        return false;
        }
        while (--len > 0) {
                if (*hp++)
                        return false;
        }
        return ((*hp & -*hp) == *hp);           /* NEEDS 2'S COMPLEMENT */
}


/*
 * Check whether or not a number has all of its bits set below some
 * bit position, and thus is one less than an exact power of two.
 * Returns true if so.
 */
bool
zisallbits(ZVALUE z)
{
        register HALF *hp;
        register LEN len;
        HALF digit;

        if (ziszero(z) || zisneg(z))
                return false;
        hp = z.v;
        len = z.len;
        while (len > 4) {
                len -= 4;
                if ((*hp++ != BASE1) || (*hp++ != BASE1) ||
                        (*hp++ != BASE1) || (*hp++ != BASE1))
                                return false;
        }
        while (--len > 0) {
                if (*hp++ != BASE1)
                        return false;
        }
        digit = (HALF)(*hp + 1);
        return ((digit & -digit) == digit);     /* NEEDS 2'S COMPLEMENT */
}


/*
 * Return the number whose binary representation contains only one bit which
 * is in the specified position (counting from zero).  This is equivalent
 * to raising two to the given power.
 */
void
zbitvalue(long n, ZVALUE *res)
{
        ZVALUE z;

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

        if (n < 0) n = 0;
        z.sign = 0;
        z.len = (LEN)((n / BASEB) + 1);
        z.v = alloc(z.len);
        zclearval(z);
        z.v[z.len-1] = (((HALF) 1) << (n % BASEB));
        *res = z;
}


/*
 * Compare a number against zero.
 * Returns the sgn function of the number (-1, 0, or 1).
 */
FLAG
ztest(ZVALUE z)
{
        register int sign;
        register HALF *h;
        register long len;

        sign = 1;
        if (z.sign)
                sign = -sign;
        h = z.v;
        len = z.len;
        while (len--)
                if (*h++)
                        return sign;
        return 0;
}


/*
 * Return the sign of z1 - z2, i.e. 1 if the first integer is greater,
 * 0 if they are equal, -1 otherwise.
 */
FLAG
zrel(ZVALUE z1, ZVALUE z2)
{
        HALF *h1, *h2;
        LEN len;
        int sign;

        sign = 1;
        if (z1.sign < z2.sign)
                return 1;
        if (z2.sign < z1.sign)
                return -1;
        if (z2.sign)
                sign = -1;
        if (z1.len != z2.len)
                return (z1.len > z2.len) ? sign : -sign;
        len = z1.len;
        h1 = z1.v + len;
        h2 = z2.v + len;

        while (len > 0) {
                if (*--h1 != *--h2)
                        break;
                len--;
        }
        if (len > 0)
                return (*h1 > *h2) ? sign : -sign;
        return 0;
}


/*
 * Return the sign of abs(z1) - abs(z2), i.e. 1 if the first integer
 * has greater absolute value, 0 is they have equal absolute value,
 * -1 otherwise.
 */
FLAG
zabsrel(ZVALUE z1, ZVALUE z2)
{
        HALF *h1, *h2;
        LEN len;

        if (z1.len != z2.len)
                return (z1.len > z2.len) ? 1 : -1;

        len = z1.len;
        h1 = z1.v + len;
        h2 = z2.v + len;
        while (len > 0) {
                if (*--h1 != *--h2)
                        break;
                len--;
        }
        if (len > 0)
                return (*h1 > *h2) ? 1 : -1;
        return 0;
}


/*
 * Compare two numbers to see if they are equal or not.
 * Returns true if they differ.
 */
bool
zcmp(ZVALUE z1, ZVALUE z2)
{
        register HALF *h1, *h2;
        register long len;

        if ((z1.sign != z2.sign) || (z1.len != z2.len) || (*z1.v != *z2.v))
                return true;
        len = z1.len;
        h1 = z1.v;
        h2 = z2.v;
        while (--len > 0) {
                if (*++h1 != *++h2)
                        return true;
        }
        return false;
}


/*
 * Utility to calculate the gcd of two FULL integers.
 */
FULL
uugcd(FULL f1, FULL f2)
{
        FULL temp;

        while (f1) {
                temp = f2 % f1;
                f2 = f1;
                f1 = temp;
        }
        return (FULL) f2;
}


/*
 * Utility to calculate the gcd of two small integers.
 */
long
iigcd(long i1, long i2)
{
        FULL f1, f2, temp;

        f1 = (FULL) ((i1 >= 0) ? i1 : -i1);
        f2 = (FULL) ((i2 >= 0) ? i2 : -i2);
        while (f1) {
                temp = f2 % f1;
                f2 = f1;
                f1 = temp;
        }
        return (long) f2;
}


void
ztrim(ZVALUE *z)
{
        HALF *h;
        LEN len;

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

        h = z->v + z->len - 1;
        len = z->len;
        while (*h == 0 && len > 1) {
                --h;
                --len;
        }
        z->len = len;
}


/*
 * Utility routine to shift right.
 *
 * NOTE: The ZVALUE length is not adjusted instead, the value is
 *       zero padded from the left.  One may need to call ztrim()
 *       or use zshift() instead.
 */
void
zshiftr(ZVALUE z, long n)
{
        register HALF *h, *lim;
        FULL mask, maskt;
        long len;

        if (n >= BASEB) {
                len = n / BASEB;
                h = z.v;
                lim = z.v + z.len - len;
                while (h < lim) {
                        h[0] = h[len];
                        ++h;
                }
                n -= BASEB * len;
                lim = z.v + z.len;
                while (h < lim)
                        *h++ = 0;
        }
        if (n) {
                len = z.len;
                h = z.v + len;
                mask = 0;
                while (len--) {
                        maskt = (((FULL) *--h) << (BASEB - n)) & BASE1;
                        *h = ((*h >> n) | (HALF)mask);
                        mask = maskt;
                }
        }
}


/*
 * Utility routine to shift left.
 *
 * NOTE: The ZVALUE length is not adjusted.  The bits in the upper
 *       HALF are simply tossed.  You may want to use zshift() instead.
 */
void
zshiftl(ZVALUE z, long n)
{
        register HALF *h;
        FULL mask, i;
        long len;

        if (n >= BASEB) {
                len = n / BASEB;
                h = z.v + z.len - 1;
                while (!*h)
                        --h;
                while (h >= z.v) {
                        h[len] = h[0];
                        --h;
                }
                n -= BASEB * len;
                while (len)
                        h[len--] = 0;
        }
        if (n > 0) {
                len = z.len;
                h = z.v;
                mask = 0;
                while (len--) {
                        i = (((FULL) *h) << n) | mask;
                        if (i > BASE1) {
                                mask = i >> BASEB;
                                i &= BASE1;
                        } else {
                                mask = 0;
                        }
                        *h = (HALF) i;
                        ++h;
                }
        }
}


/*
 * popcnt - count the number of 0 or 1 bits in an integer
 *
 * We ignore all 0 bits above the highest bit.
 */
long
zpopcnt(ZVALUE z, int bitval)
{
        long cnt = 0;   /* number of times found */
        HALF h;         /* HALF to count */
        int i;

        /*
         * count 1's
         */
        if (bitval) {

                /*
                 * count each HALF
                 */
                for (i=0; i < z.len; ++i) {
                        /* count each octet */
                        for (h = z.v[i]; h; h >>= 8) {
                                cnt += (long)popcnt[h & 0xff];
                        }
                }

        /*
         * count 0's
         */
        } else {

                /*
                 * count each HALF up until the last
                 */
                for (i=0; i < z.len-1; ++i) {

                        /* count each octet */
                        cnt += BASEB;
                        for (h = z.v[i]; h; h >>= 8) {
                                cnt -= (long)popcnt[h & 0xff];
                        }
                }

                /*
                 * count the last octet up until the highest 1 bit
                 */
                for (h = z.v[z.len-1]; h; h>>=1) {
                        /* count each 0 bit */
                        if ((h & 0x1) == 0) {
                                ++cnt;
                        }
                }
        }

        /*
         * return count
         */
        return cnt;
}
