/* Integer Version 2.1, TP, 5.10.94     ibit.c */

#include "iint.h"
#include "imem.h"

#define RADIXMINUSONE    ((DigitType)(-1))
#define BPDM1            (BitsPerDigit-1)
#ifdef __GNUC__
#define RADIXHALF        ((DigitType)(1UL<<BPDM1))
#else
#define RADIXHALF        ((DigitType)(1<<BPDM1))
#endif

void
IasnotI(b, a)
    pInteger b;
    const Integer *a;
{				/* b = ~a */
    register long lb, i;
    register DigitType h, r;

    if (!a->length)
    {
	Ias1(b);
	return;
    }

    IasI(b, a);
    lb = b->length;

    for (i = lb - 2; i >= 0; i--)
	b->vec[i] = (~(b->vec[i]) & RADIXMINUSONE);

    h = RADIXHALF;
    r = RADIXMINUSONE;
    while (!((b->vec[lb - 1]) & h))
    {
	h >>= 1;
	r >>= 1;
    }
    b->vec[lb - 1] = ((~(b->vec[lb - 1])) & r);

    lb = lb - 1;
    while ((lb >= 0) && (!(b->vec[lb])))
	lb--;
    b->length = lb + 1;
    b->sign = (b->sign && b->vec[0]);
}


void
IandasI(c, a)
    pInteger c;
    const Integer *a;
{				/* c &= a */
    IasIandI(c, c, a);
}

void
IasIandI(c, a, b)
    pInteger c;
    const Integer *a;
    const Integer *b;
{				/* c = a & b */
    register int la;
    register int lb;
    register int lm;
    register int i;
    register int neededlength;

    if (!a->length || !b->length)
    {
	Ias0(c);
	return;
    }

    la = a->length;
    lb = b->length;
    lm = (la > lb ? lb : la);

    neededlength = lm;
    if (neededlength > c->maxlength)
    {
	register DigitType *newv;
	register int oldlength = c->maxlength;
	c->maxlength = neededlength;
	newv = newDigitVec(&c->maxlength);
	for (i = 0; i < lm; i++)
	    newv[i] = a->vec[i] & b->vec[i];
	delDigitVec(c->vec, oldlength);
	c->vec = newv;
    }
    else
    {
	for (i = 0; i < lm; i++)
	    c->vec[i] = a->vec[i] & b->vec[i];
    }

    lm = lm - 1;
    while ((lm >= 0) && (!(c->vec[lm])))
	lm--;
    c->length = lm + 1;
    c->sign = PLUS;
}

void
IxorasI(c, a)
    pInteger c;
    const Integer *a;
{				/* c ^= a */
    IasIxorI(c, c, a);
}

void
IasIxorI(c, a, b)
    pInteger c;
    const Integer *a;
    const Integer *b;
{				/* c = a ^ b */
    register long la;
    register long lb;
    register long sm;
    register long lm;
    register long i;
    register int neededlength;

    if (!a->length)
    {
	IasI(c, b);
	c->sign = PLUS;
	return;
    }

    if (!b->length)
    {
	IasI(c, a);
	c->sign = PLUS;
	return;
    }

    la = a->length;
    lb = b->length;
    if (la > lb)
    {
	lm = la;
	sm = lb;
    }
    else
    {
	lm = lb;
	sm = la;
    }

    neededlength = lm;
    if (neededlength > c->maxlength)
    {
	register DigitType *newv;
	register int oldlength = c->maxlength;
	c->maxlength = neededlength;
	newv = newDigitVec(&c->maxlength);
	for (i = 0; i < sm; i++)
	    newv[i] = a->vec[i] ^ b->vec[i];
	if (la > lb)
	    for (; i < lm; i++)
		newv[i] = a->vec[i];
	else
	    for (; i < lm; i++)
		newv[i] = b->vec[i];

	delDigitVec(c->vec, oldlength);
	c->vec = newv;

    }
    else
    {
	for (i = 0; i < sm; i++)
	    c->vec[i] = a->vec[i] ^ b->vec[i];
	if (la > lb)
	    for (; i < lm; i++)
		c->vec[i] = a->vec[i];
	else
	    for (; i < lm; i++)
		c->vec[i] = b->vec[i];
    }
    lm = lm - 1;
    while ((lm >= 0) && (!(c->vec[lm])))
	lm--;
    c->length = lm + 1;
    c->sign = PLUS;
}

void
IorasI(c, a)
    pInteger c;
    const Integer *a;
{				/* c |= a */
    IasIorI(c, c, a);
}

void
IasIorI(c, a, b)
    pInteger c;
    const Integer *a;
    const Integer *b;
{				/* c = a | b */
    register long la;
    register long lb;
    register long sm;
    register long lm;
    register long i;
    register int neededlength;

    if (!a->length)
    {
	IasI(c, b);
	c->sign = PLUS;
	return;
    }

    if (!b->length)
    {
	IasI(c, a);
	c->sign = PLUS;
	return;
    }

    la = a->length;
    lb = b->length;
    if (la > lb)
    {
	lm = la;
	sm = lb;
    }
    else
    {
	lm = lb;
	sm = la;
    }

    neededlength = lm;
    if (neededlength > c->maxlength)
    {
	register DigitType *newv;
	register int oldlength = c->maxlength;
	c->maxlength = neededlength;
	newv = newDigitVec(&c->maxlength);
	for (i = 0; i < sm; i++)
	    newv[i] = a->vec[i] | b->vec[i];
	if (la > lb)
	    for (; i < lm; i++)
		newv[i] = a->vec[i];
	else
	    for (; i < lm; i++)
		newv[i] = b->vec[i];

	delDigitVec(c->vec, oldlength);
	c->vec = newv;

    }
    else
    {
	for (i = 0; i < sm; i++)
	    c->vec[i] = a->vec[i] | b->vec[i];
	if (la > lb)
	    for (; i < lm; i++)
		c->vec[i] = a->vec[i];
	else
	    for (; i < lm; i++)
		c->vec[i] = b->vec[i];
    }
    c->length = lm;
    c->sign = PLUS;
}
