
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                        Long number - bit operations                       //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "..\include.h"

///////////////////////////////////////////////////////////////////////////////
// bit NOT (changes sign)

void bignum::Not()
{
	// bit inverse
	this->NotStr(this->Base(-m_DecNum), m_DecNum + m_IntNum);

	// flip sign (high bits are inverted)
	m_IsNeg = !m_IsNeg;

	// data reduction
	this->Reduce();
}

void bignum::Not(const bignum& num)
{
	bint dec = num.m_DecNum;
	if (dec > m_DecMax) dec = m_DecMax;
	bint len = num.m_IntNum;
	if (len > m_IntMax) len = m_IntMax;

	// bit inverse
	this->NotStr(this->Base(-dec), num.Base(-dec), dec + len);

	// flip sign (high bits are inverted)
	m_IsNeg = !num.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND of 2 bignums, store result here (numbers may overlap)

void bignum::And(const bignum& num1, const bignum& num2)
{
	// prepare length with 2 numbers (dec1, dec2, dec, len1, len2, len)
	BIGPREP2();

	// operation on common data
	const buint* s1 = num1.Base(-dec);
	const buint* s2 = num2.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->AndStr(d, s1, s2, i);
	d += i;
	s1 += i;
	s2 += i;

	// copy rest of one number, if the other number is negative (data & 0xffff = data, data & 0 = 0)
	if ((len1 > len) && num2.m_IsNeg)
	{
		m_IntNum = len1;
		this->CopyStr(d, s1, len1 - len);
	}
	else if ((len2 > len) && num1.m_IsNeg)
	{
		m_IntNum = len2;
		this->CopyStr(d, s2, len2 - len);
	}

	// sign (0xffff & 0xffff = 0xffff)
	m_IsNeg = num1.m_IsNeg && num2.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND bignum with signed number, store result here (numbers may overlap)

void bignum::And(const bignum& num1, bint num2)
{
	// no decimal part
	m_DecNum = 0;

	// length of integer part
	bint i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;
	m_IntNum = i;

	// operation with number
	const buint* s = num1.Base();
	buint* d = this->Base();
	if (i > 0)
	{
		// positive number will cut the number
		if (num2 >= 0)
		{
			m_IntNum = 1;
			i = 1;
		}
		*d++ = *s++ & (buint)num2;
		i--;
	}

	// copy rest of integer part (only in case of negative num2)
	this->CopyStr(d, s, i);

	// sign
	m_IsNeg = num1.m_IsNeg && (num2 < 0);

	// data reduction
	this->RedInt();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND bignum with unsigned number, store result here (numbers may overlap)

void bignum::AndU(const bignum& num1, buint num2)
{
	// no decimal part
	m_DecNum = 0;

	// length of integer part
	bint i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;

	// operation with number
	if (i > 0)
	{
		i = 1;
		*this->Base() = *num1.Base() & num2;
	}
	m_IntNum = i;

	// result is always positive
	m_IsNeg = false;

	// data reduction
	this->RedInt();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND this number with bignum (numbers may overlap)

void bignum::And(const bignum& num)
{
	// prepare length with 1 number (dec1, dec2, dec, len1, len2, len)
	BIGPREP1();

	// operation on common data
	const buint* s = num.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->AndStr(d, s, i);
	d += i;
	s += i;

	// copy rest of one number, if other number is negative (data & 0xffff = data, data & 0 = 0)
	if ((len1 > len) && num.m_IsNeg)
	{
		m_IntNum = len1;
	}
	else if ((len2 > len) && m_IsNeg)
	{
		m_IntNum = len2;
		this->CopyStr(d, s, len2 - len);
	}

	// sign (0xffff & 0xffff = 0xffff)
	m_IsNeg = m_IsNeg && num.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND this number with signed number

void bignum::And(bint num)
{
	// no decimal part
	m_DecNum = 0;

	// request integral part min. 1
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		if (num >= 0) m_IntNum = 1; // pozitive number clips high bits
		*this->Base() &= (buint)num;
	}

	// sign
	m_IsNeg = m_IsNeg && (num < 0);

	// data reduction
	this->RedInt();
}

///////////////////////////////////////////////////////////////////////////////
// bit AND this number with unsigned number

void bignum::AndU(buint num)
{
	// no decimal part
	m_DecNum = 0;

	// request integral part min. 1
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		m_IntNum = 1;
		*this->Base() &= num;
	}

	// sign, always positive
	m_IsNeg = false;

	// data reduction
	this->RedInt();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR of 2 bignums, store result here (numbers may overlap)

void bignum::Or(const bignum& num1, const bignum& num2)
{
	// prepare length with 2 numbers (dec1, dec2, dec, len1, len2, len)
	BIGPREP2();

	// copy start of decimal part
	if (dec1 > dec)
	{
		m_DecNum = dec1;
		this->CopyStr(this->Base(-dec1), num1.Base(-dec1), dec1 - dec);
	}
	else if (dec2 > dec)
	{
		m_DecNum = dec2;
		this->CopyStr(this->Base(-dec2), num2.Base(-dec2), dec2 - dec);
	}

	// operation on common data
	const buint* s1 = num1.Base(-dec);
	const buint* s2 = num2.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->OrStr(d, s1, s2, i);
	d += i;
	s1 += i;
	s2 += i;

	// copy rest of one number, if other number is not negative (data | 0 = data, data | 0xffff = 0xffff)
	if ((len1 > len) && !num2.m_IsNeg)
	{
		m_IntNum = len1;
		this->CopyStr(d, s1, len1 - len);
	}
	else if ((len2 > len) && !num1.m_IsNeg)
	{
		m_IntNum = len2;
		this->CopyStr(d, s2, len2 - len);
	}

	// sign (0 | 0 = 0)
	m_IsNeg = num1.m_IsNeg || num2.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR bignum with signed number, store result here (numbers may overlap)

void bignum::Or(const bignum& num1, bint num2)
{
	// length of decimal part
	bint i = num1.m_DecNum;
	if (i > m_DecMax) i = m_DecMax;
	m_DecNum = i;

	// copy decimal part
	const buint* s = num1.Base(-i);
	buint* d = this->Base(-i);
	this->CopyStr(d, s, i);
	s += i;
	d += i;

	// length of integer part
	i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;
	m_IntNum = i;

	// operation with number
	if (i > 0)
	{
		// negative number will cut the number
		if (num2 < 0)
		{
			m_IntNum = 1;
			i = 1;
		}
		*d++ = *s++ | (buint)num2;
		i--;
	}

	// copy rest of integer part (only in case of non negative num2)
	this->CopyStr(d, s, i);

	// sign
	m_IsNeg = num1.m_IsNeg || (num2 < 0);

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR bignum with unsigned number, store result here (numbers may overlap)

void bignum::OrU(const bignum& num1, buint num2)
{
	// length of decimal part
	bint i = num1.m_DecNum;
	if (i > m_DecMax) i = m_DecMax;
	m_DecNum = i;

	// copy decimal part
	const buint* s = num1.Base(-i);
	buint* d = this->Base(-i);
	this->CopyStr(d, s, i);
	s += i;
	d += i;

	// length of integer part
	i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;
	m_IntNum = i;

	// operation with number
	if (i > 0)
	{
		*d++ = *s++ | num2;
		i--;
	}

	// copy rest of integer part
	this->CopyStr(d, s, i);

	// sign
	m_IsNeg = num1.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR this number with bignum (numbers may overlap)

void bignum::Or(const bignum& num)
{
	// prepare length with 1 number (dec1, dec2, dec, len1, len2, len)
	BIGPREP1();

	// copy start of decimal part
	if (dec1 > dec)
	{
		m_DecNum = dec1;
	}
	else if (dec2 > dec)
	{
		m_DecNum = dec2;
		this->CopyStr(this->Base(-dec2), num.Base(-dec2), dec2 - dec);
	}

	// operation on common data
	const buint* s = num.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->OrStr(d, s, i);
	d += i;
	s += i;

	// copy rest of one number, if other number is not negative (data | 0 = data, data | 0xffff = 0xffff)
	if ((len1 > len) && !num.m_IsNeg)
	{
		m_IntNum = len1;
	}
	else if ((len2 > len) && !m_IsNeg)
	{
		m_IntNum = len2;
		this->CopyStr(d, s, len2 - len);
	}

	// sign (0 | 0 = 0)
	m_IsNeg = m_IsNeg || num.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR this number with signed number

void bignum::Or(bint num)
{
	// expand to minimal size
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		if (num < 0) m_IntNum = 1; // negative number clips high bits
		*this->Base() |= (buint)num; // operation with number
	}

	// sign
	m_IsNeg = m_IsNeg || (num < 0);

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit OR this number with unsigned number

void bignum::OrU(buint num)
{
	// expand to minimal size
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		*this->Base() |= num; // operation with number
	}

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR of 2 bignums, store result here (numbers may overlap)

void bignum::Xor(const bignum& num1, const bignum& num2)
{
	// prepare length with 2 numbers (dec1, dec2, dec, len1, len2, len)
	BIGPREP2();

	// copy start of decimal part
	if (dec1 > dec)
	{
		m_DecNum = dec1;
		this->CopyStr(this->Base(-dec1), num1.Base(-dec1), dec1 - dec);
	}
	else if (dec2 > dec)
	{
		m_DecNum = dec2;
		this->CopyStr(this->Base(-dec2), num2.Base(-dec2), dec2 - dec);
	}

	// operation on common data
	const buint* s1 = num1.Base(-dec);
	const buint* s2 = num2.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->XorStr(d, s1, s2, i);
	d += i;
	s1 += i;
	s2 += i;

	// operation on rest of one number (data ^ 0xffff = ~data, data ^ 0 = data)
	if (len1 > len)
	{
		m_IntNum = len1;
		len1 -= len;
		if (num2.m_IsNeg)
			this->NotStr(d, s1, len1);
		else
			this->CopyStr(d, s1, len1);
	}
	else if (len2 > len)
	{
		m_IntNum = len2;
		len2 -= len;
		if (num1.m_IsNeg)
			this->NotStr(d, s2, len2);
		else
			this->CopyStr(d, s2, len2);
	}

	// sign
	m_IsNeg = (num1.m_IsNeg && !num2.m_IsNeg) || (!num1.m_IsNeg && num2.m_IsNeg);

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR bignum with signed number, store result here (numbers may overlap)

void bignum::Xor(const bignum& num1, bint num2)
{
	// length of decimal part
	bint i = num1.m_DecNum;
	if (i > m_DecMax) i = m_DecMax;
	m_DecNum = i;

	// copy decimal part
	const buint* s = num1.Base(-i);
	buint* d = this->Base(-i);
	this->CopyStr(d, s, i);
	s += i;
	d += i;

	// length of integer part
	i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;
	m_IntNum = i;

	// operation with number
	if (i > 0)
	{
		*d++ = *s++ ^ (buint)num2;
		i--;
	}

	// operation on rest of data (data ^ 0xffff = ~data, data ^ 0 = data)
	if (num2 < 0)
		this->NotStr(d, s, i);
	else
		this->CopyStr(d, s, i);

	// sign
	m_IsNeg = (num1.m_IsNeg && !(num2 < 0)) || (!num1.m_IsNeg && (num2 < 0));

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR bignum with unsigned number, store result here (numbers may overlap)

void bignum::XorU(const bignum& num1, buint num2)
{
	// length of decimal part
	bint i = num1.m_DecNum;
	if (i > m_DecMax) i = m_DecMax;
	m_DecNum = i;

	// copy decimal part
	const buint* s = num1.Base(-i);
	buint* d = this->Base(-i);
	this->CopyStr(d, s, i);
	s += i;
	d += i;

	// length of integer part
	i = num1.m_IntNum;
	if (i > m_IntMax) i = m_IntMax;
	m_IntNum = i;

	// operation with number
	if (i > 0)
	{
		*d++ = *s++ ^ num2;
		i--;
	}

	// copy rest of integer part
	this->CopyStr(d, s, i);

	// sign
	m_IsNeg = num1.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR this number with bignum (numbers may overlap)

void bignum::Xor(const bignum& num)
{
	// prepare length with 1 number (dec1, dec2, dec, len1, len2, len)
	BIGPREP1();

	// copy start of decimal part
	if (dec1 > dec)
	{
		m_DecNum = dec1;
	}
	else if (dec2 > dec)
	{
		m_DecNum = dec2;
		this->CopyStr(this->Base(-dec2), num.Base(-dec2), dec2 - dec);
	}

	// operation on common data
	const buint* s = num.Base(-dec);
	buint* d = this->Base(-dec);
	bint i = dec + len;
	this->XorStr(d, s, i);
	s += i;
	d += i;

	// operation on rest of one number (data ^ 0xffff = ~data, data ^ 0 = data)
	if (len1 > len)
	{
		m_IntNum = len1;
		if (num.m_IsNeg) this->NotStr(d, len1 - len);
	}
	else if (len2 > len)
	{
		m_IntNum = len2;
		len2 -= len;
		if (m_IsNeg)
			this->NotStr(d, s, len2);
		else
			this->CopyStr(d, s, len2);
	}

	// sign
	m_IsNeg = (m_IsNeg && !num.m_IsNeg) || (!m_IsNeg && num.m_IsNeg);

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR this number with signed number

void bignum::Xor(bint num)
{
	// expand to minimal size
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		*this->Base(0) ^= (buint)num;

		// invert rest of data if number is negative
		if (num < 0) this->NotStr(this->Base(1), m_IntNum - 1);
	}

	// sign
	m_IsNeg = (!m_IsNeg && (num < 0)) || (m_IsNeg && !(num < 0));

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// bit XOR this number with unsigned number

void bignum::XorU(buint num)
{
	// expand to minimal size
	this->ExpInt(1);

	// operation with number
	if (m_IntNum > 0)
	{
		*this->Base(0) ^= num;
	}

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// shift bits left, to higher bits (negative = shift bits right)

void bignum::LShift(s64 shift)
{
	// negative or none shift
	if (shift <= 0)
	{
		if (shift < 0) this->RShift(-shift);
		return; // shift = 0
	}

	// split shift to offset and bits
	bint off = (buint)(shift/(BIGSIZE*8));
	int bit = (int)(shift - off*(BIGSIZE*8));

	// expand 1 word on top to overflow bits
	this->ExpInt(m_IntNum + 1);

	// original and final positions of the string
	bint begold = m_DecMax - m_DecNum;
	bint endold = m_DecMax + m_IntNum;
	bint begnew = begold + off;
	bint endnew = endold + off;
	bint max = m_DecMax + m_IntMax;
	if (begnew > max) begnew = max;
	if (endnew > max) endnew = max;

	// shift
	this->LShiftStr(0, bit, &m_Data[begnew], &m_Data[begold], endnew - begnew);

	// lengths of parts
	m_IntNum = endnew - m_DecMax;
	bint i = m_DecMax - begnew;
	m_DecNum = i;

	// add empty integer part
	if (i < 0)
	{
		m_DecNum = 0;
		this->FillStr(this->Base(), 0, -i);
	}

	// data reduction
	this->Reduce();
}

void bignum::LShift(const bignum& num, s64 shift)
{
	// negative or none shift
	if (shift <= 0)
	{
		if (shift < 0) this->RShift(num, -shift);
		return; // shift = 0
	}

	// split shift to offset and bits
	bint off = (buint)(shift/(BIGSIZE*8));
	int bit = (int)(shift - off*(BIGSIZE*8));

	// original and final positions of the string
	bint dec = num.m_DecNum;
	if (dec > m_DecMax) dec = m_DecMax;
	bint len = num.m_IntNum;
	if (len > m_IntMax) len = m_IntMax;
	bint begold = num.m_DecMax - dec;
	bint endold = num.m_DecMax + len;
	bint begnew = m_DecMax - dec + off;
	bint endnew = m_DecMax + len + off;
	bint max = m_DecMax + m_IntMax;
	if (begnew > max) begnew = max;
	if (endnew > max) endnew = max;

	// shift
	buint c = this->LShiftStr(0, bit, &m_Data[begnew], &num.m_Data[begold], endnew - begnew);

	// lengths of parts
	m_IntNum = endnew - m_DecMax;
	if (m_IntNum < m_IntMax)
	{
		*this->Base(m_IntNum) = c;
		m_IntNum++;
	}
	bint i = m_DecMax - begnew;
	m_DecNum = i;

	// add empty integer part
	if (i < 0)
	{
		m_DecNum = 0;
		this->FillStr(this->Base(), 0, -i);
	}
	m_IsNeg = num.m_IsNeg;

	// data reduction
	this->Reduce();
}

///////////////////////////////////////////////////////////////////////////////
// shift bits right, to lower bits (negative = shift bits left)

void bignum::RShift(s64 shift)
{
	// negative or none shift
	if (shift <= 0)
	{
		if (shift < 0) this->LShift(-shift);
		return;
	}

	// split shift to offset and bits
	buint off = (buint)(shift/(BIGSIZE*8));
	int bit = (int)(shift - off*(BIGSIZE*8));

	// expand 1 word on bottom to overflow bits
	this->ExpDec(m_DecNum + 1);

	// original and final positions of the string
	bint begold = m_DecMax - m_DecNum;
	bint endold = m_DecMax + m_IntNum;
	bint begnew = begold - off;
	bint endnew = endold - off;
	if (begnew < 0) begnew = 0;
	if (endnew < 0) endnew = 0;

	// shift
	this->RShiftStr(0, bit, &m_Data[begnew], &m_Data[begnew + off], endnew - begnew);

	// lengths of parts
	m_DecNum = m_DecMax - begnew;
	bint i = endnew - m_DecMax;
	m_IntNum = i;

	// add empty decimal part
	if (i < 0)
	{
		m_IntNum = 0;
		this->FillStr(this->Base(i), this->High(), -i);
	}

	// data reduction
	this->Reduce();
}

void bignum::RShift(const bignum& num, s64 shift)
{
	// negative or none shift
	if (shift <= 0)
	{
		if (shift < 0) this->LShift(num, -shift);
		return;
	}

	// split shift to offset and bits
	buint off = (buint)(shift/(BIGSIZE*8));
	int bit = (int)(shift - off*(BIGSIZE*8));

	// original and final positions of the string
	bint dec = num.m_DecNum;
	if (dec > m_DecMax) dec = m_DecMax;
	bint len = num.m_IntNum;
	if (len > m_IntMax) len = m_IntMax;
	bint begold = num.m_DecMax - dec;
	bint endold = num.m_DecMax + len;
	bint begnew = m_DecMax - dec - off;
	bint endnew = m_DecMax + len - off;
	if (begnew < 0) begnew = 0;
	if (endnew < 0) endnew = 0;

	// shift
	buint c = this->RShiftStr(0, bit, &m_Data[begnew], &num.m_Data[begold], endnew - begnew);

	// lengths of parts
	m_DecNum = m_DecMax - begnew;
	if (m_DecNum < m_DecMax)
	{
		m_DecNum++;
		*this->Base(-m_DecNum) = (c << bit);
	}
	bint i = endnew - m_DecMax;
	m_IntNum = i;

	// add empty decimal part
	if (i < 0)
	{
		m_IntNum = 0;
		this->FillStr(this->Base(i), this->High(), -i);
	}
	m_IsNeg = num.m_IsNeg;

	// data reduction
	this->Reduce();
}
