
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                        Quadruple Integer (uint256)                        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

/* Note: In some cases you can get "ambiguous call to overloaded function" error.
It will appear if you use constant, but compiler will have more variants of functions
(example: uint128 n.Div(2)). Solution: specify constant type (n.Div(2UL) or
n.Div((u32)2)) or use variable (u32 k=2; n.Div(k)) or disable unused functions. */

/*
typedef char				s8;
typedef short				s16;
typedef long				s32;
typedef long long			s64;

typedef unsigned char		u8;
typedef unsigned short		u16;
typedef unsigned long		u32;
typedef unsigned long long	u64;
*/

#ifndef QUADUINT

#define QUADUINT uint256	// quadruple integer class unsigned
#define DBLUINT uint128		// double integer class unsigned
#define BASEUINT u64		// base integer unsigned
#define HALFUINT u32		// half integer unsigned

#define QUADSINT sint256	// quadruple integer class signed
#define DBLSINT sint128		// double integer class signed
#define BASESINT s64		// base integer signed
#define HALFSINT s32		// half integer signed

#define QUADFIX fix256		// quadruple fixed point class
#define DBLFIX fix128		// double fixed point class

#define USEASM				// can use assembler

#endif // QUADUINT


#define BASEBITS (sizeof(BASEUINT)*8)	// number of bits of base integer
#define BASELAST ((BASEUINT)1 << (BASEBITS-1)) // highest bit of base integer
#define HALFBITS (sizeof(HALFUINT)*8)	// number of bits of half integer
#define HALFMASK (((BASEUINT)1 << HALFBITS)-1) // mask of half integer
#define BASENOT  (~(BASEUINT)0)			// all bits '1' (or ((BASEUINT)-1) )

#define QUADFIX_MAX ((double)(BASELAST-1)*BASELAST*2 + (double)BASENOT + \
	(double)BASENOT/BASELAST/2 + (double)BASENOT/BASELAST/2/BASELAST/2) // max. decimal number as double
#define QUADFIX_MIN (-(double)BASELAST*BASELAST*2) // min. decimal number as double
#define QUADFIX_DEC ((int)(BASEBITS*2*0.301)) // default number of decimal places

#ifndef WIN64
#undef USEASM				// can use assembler
#endif WIN64

class QUADSINT;

// quadruple integer unsigned
class QUADUINT
{
protected:

	BASEUINT		m_N[4];		// data

// --- low level math

	// multiply 2 base entries, r1:r0 = a * b1:b0
	static void MulBB(BASEUINT* r0, BASEUINT* r1, BASEUINT a, HALFUINT b0, HALFUINT b1);

	// multiply base entry by half entry, r1:r0 = a * 0:b0
	static void MulBH(BASEUINT* r0, BASEUINT* r1, BASEUINT a, HALFUINT b0);

	// square base entry, r1:r0 = a * a
	static void SqrB(BASEUINT* r0, BASEUINT* r1, BASEUINT a);

	// factorial table
	static QUADUINT* Fact_;

	// initialize factorial table
	static bool FactOK;
	static bool FactInit();

public:

	// max. factorial
	static BASEUINT FactMax;

// --- constructor

	inline QUADUINT() {}

	inline QUADUINT(const QUADUINT& num)
		{ this->Set(num); }

	inline QUADUINT(const DBLUINT& num)
		{ this->Set(num); }

	inline QUADUINT(BASEUINT num)
		{ this->Set(num); }

// --- access to value

	inline BASEUINT& N0() { return m_N[0]; }
	inline BASEUINT& N1() { return m_N[1]; }
	inline BASEUINT& N2() { return m_N[2]; }
	inline BASEUINT& N3() { return m_N[3]; }

	inline const BASEUINT& N0() const { return m_N[0]; }
	inline const BASEUINT& N1() const { return m_N[1]; }
	inline const BASEUINT& N2() const { return m_N[2]; }
	inline const BASEUINT& N3() const { return m_N[3]; }

	// check if number is negative (if highest bit is set)
	inline bool IsNeg() const { return (this->N3() >= BASELAST); }
	inline bool IsNotNeg() const { return (this->N3() < BASELAST); }

// --- SET =

	// this = 0
	inline void Set0()
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

	// this = 1
	inline void Set1()
		{	this->N0() = 1;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

	// this = all bits '1'
	inline void SetAll()
		{	this->N0() = BASENOT;
			this->N1() = BASENOT;
			this->N2() = BASENOT;
			this->N3() = BASENOT; }

	// this = -1
	inline void SetM1() { this->SetAll(); }

	// this = max (max. value)
	inline void SetMax() { this->SetAll(); }

	// this = min (min. value)
	inline void SetMin() { this->Set0(); }

	// this = num
	inline void Set(const QUADUINT& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1();
			this->N2() = num.N2();
			this->N3() = num.N3(); }

	inline void Set(const QUADSINT& num) { this->Set(*(const QUADUINT*)&num); }

	// this = 0:num
	inline void Set(const DBLUINT& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1();
			this->N2() = 0;
			this->N3() = 0; }

	// this = 0:0:0:num
	inline void Set(BASEUINT num)
		{	this->N0() = num;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

	// this = num3:num2:num1:num0
	inline void Set(BASEUINT num0, BASEUINT num1, BASEUINT num2, BASEUINT num3)
		{	this->N0() = num0;
			this->N1() = num1;
			this->N2() = num2;
			this->N3() = num3; }

	// factorial this = num!
	void Fact(BASEUINT num);
	void Fact();

	// exchange two numbers
	void Exchange(QUADUINT& num);

// --- ADD +=

	// this += num
	void Add(const QUADUINT& num);

	// this += 0:num
	void Add(const DBLUINT& num);

	// this += 0:0:0:num
	void Add(BASEUINT num);

// --- ADD +

	// this = num1 + num2
	void Add(const QUADUINT& num1, const QUADUINT& num2);

	// this = num1 + 0:num2
	void Add(const QUADUINT& num1, const DBLUINT& num2);

	// this = 0:num1 + num2
	inline void Add(const DBLUINT& num1, const QUADUINT& num2)
		{ this->Add(num2, num1); }

	// this = num1 + 0:0:0:num2
	void Add(const QUADUINT& num1, BASEUINT num2);

	// this = 0:0:0:num1 + num2
	inline void Add(BASEUINT num1, const QUADUINT& num2)
		{ this->Add(num2, num1); }

// --- SUB -=

	// this -= num
	void Sub(const QUADUINT& num);

	// this -= 0:num
	void Sub(const DBLUINT& num);

	// this -= 0:0:0:num
	void Sub(BASEUINT num);

// --- SUB -

	// this = num1 - num2
	void Sub(const QUADUINT& num1, const QUADUINT& num2);

	// this = num1 - 0:num2
	void Sub(const QUADUINT& num1, const DBLUINT& num2);

	// this = 0:num1 - num2
	void Sub(const DBLUINT& num1, const QUADUINT& num2);

	// this = num1 - 0:0:0:num2
	void Sub(const QUADUINT& num1, BASEUINT num2);

	// this = 0:0:0:num1 - num2
	void Sub(BASEUINT num1, const QUADUINT& num2);

// --- INV SUB =-

	// this = num - this
	void InvSub(const QUADUINT& num);

	// this = 0:num - this
	void InvSub(const DBLUINT& num);

	// this = 0:0:0:num - this
	void InvSub(BASEUINT num);

// --- increment ++

	// this++
	void Inc();

	// this = num + 1
	void Inc(const QUADUINT& num);

// --- decrement --

	// this--
	void Dec();

	// this = num - 1
	void Dec(const QUADUINT& num);

// --- MUL *=

	// this *= num
	inline void Mul(const QUADUINT& num)
		{ this->Mul(*this, num); }

	// this *= 0:num
	inline void Mul(const DBLUINT& num)
		{ this->Mul(*this, num); }

	// this *= 0:0:0:num
	inline void Mul(BASEUINT num)
		{ this->Mul(*this, num); }

	// this *= 10, returns high carry (0..9)
	inline int Mul10()
		{ return this->Mul10(*this); }

// --- MUL *

	// this = num1 * num2
	void Mul(const QUADUINT& num1, const QUADUINT& num2);

	// this = num1 * 0:num2
	void Mul(const QUADUINT& num1, const DBLUINT& num2);

	// this = 0:num1 * num2
	inline void Mul(const DBLUINT& num1, const QUADUINT& num2)
		{ this->Mul(num2, num1); }

	// this = num1 * 0:0:0:num2
	void Mul(const QUADUINT& num1, BASEUINT num2);

	// this = 0:0:0:num1 * num2
	inline void Mul(BASEUINT num1, const QUADUINT& num2)
		{ this->Mul(num2, num1); }

	// this = 0:num1 * 0:num2
	void Mul(const DBLUINT& num1, const DBLUINT& num2);

	// this = 0:num1 * 0:0:0:num2
	void Mul(const DBLUINT& num1, BASEUINT num2);

	// this = 0:0:0:num1 * 0:num2
	inline void Mul(BASEUINT num1, const DBLUINT& num2)
		{ this->Mul(num2, num1); }

	// this = 0:0:0:num1 * 0:0:0:num2
	void Mul(BASEUINT num1, BASEUINT num2);

	// this = num1 * num2, with full range of result (high = destination of high part of result)
	void MulHigh(const QUADUINT& num1, const QUADUINT& num2, QUADUINT* high);

	// this = num * 10, returns high carry (0..9)
	int Mul10(const QUADUINT& num);

// --- SQR

	// this *= this
	inline void Sqr()
		{ this->Sqr(*this); }

	// this = num * num
	void Sqr(const QUADUINT& num);

	// this = 0:num * 0:num
	void Sqr(const DBLUINT& num);

	// this = 0:0:0:num * 0:0:0:num
	void Sqr(BASEUINT num);

// --- DIV /=

	// this = this / num, with optional destination remainder
	inline void Div(const QUADUINT& num, QUADUINT* rem = NULL)
		{ this->Div(*this, num, rem); }

	// this = this / 0:num, with optional destination remainder
	inline void Div(const DBLUINT& num, QUADUINT* rem = NULL)
		{ this->Div(*this, num, rem); }

	// this = this / 0:0:0:num, returns remainder
	inline BASEUINT Div(BASEUINT num)
		{ return this->Div(*this, num); }

	// this = this / 0:0:0:0:0:0:0:num, returns remainder
	inline HALFUINT Div(HALFUINT num)
		{ return this->Div(*this, num); }

	// this = num / this, with optional destination remainder
	inline void InvDiv(const QUADUINT& num, QUADUINT* rem = NULL)
		{ this->Div(num, *this, rem); }

	// this = num / 10, returns remainder 0..9
	inline int Div10()
		{ return this->Div10(*this); }

// --- DIV /

	// this = num1 / num2, with optional destination remainder (sources and destinations can be mixed)
	void Div(const QUADUINT& num1, const QUADUINT& num2, QUADUINT* rem = NULL);

	// this = num1 / 0:num2, with optional destination remainder (sources and destinations can be mixed)
	void Div(const QUADUINT& num1, const DBLUINT& num2, QUADUINT* rem = NULL);

	// this = num1 / 0:0:0:num2, returns remainder
	BASEUINT Div(const QUADUINT& num1, BASEUINT num2);

	// this = num1 / 0:0:0:0:0:0:0:num2, returns remainder
	HALFUINT Div(const QUADUINT& num1, HALFUINT num2);

	// this = num1H:num1L / num2, with full range of dividend
	void DivHigh(const QUADUINT& num1L, const QUADUINT& num1H, const QUADUINT& num2, QUADUINT* rem = NULL);

	// this = num / 10, returns remainder 0..9
	int Div10(const QUADUINT& num);

// --- MOD %=

	// this = this % num
	inline void Mod(const QUADUINT& num)
		{ QUADUINT n; n.Div(*this, num, this); }

	// this = this % 0:num
	inline void Mod(const DBLUINT& num)
		{ QUADUINT n; n.Div(*this, num, this); }

	// this = this % 0:0:0:num
	inline void Mod(BASEUINT num)
		{ this->Set(this->Div(*this, num)); }

	// this = this % 0:0:0:0:0:0:0:num
	inline void Mod(HALFUINT num)
		{ this->Set(this->Div(*this, num)); }

	// this = this % 10
	inline void Mod10()
		{ this->Set(this->Div10()); }

// --- MOD %

	// this = num1 % num2
	inline void Mod(const QUADUINT& num1, const QUADUINT& num2)
		{ QUADUINT n; n.Div(num1, num2, this); }

	// this = num1 % 0:num2
	inline void Mod(const QUADUINT& num1, const DBLUINT& num2)
		{ QUADUINT n; n.Div(num1, num2, this); }

	// this = num1 % 0:0:0:num2
	inline void Mod(const QUADUINT& num1, BASEUINT num2)
		{ this->Set(this->Div(num1, num2)); }

	// this = num1 % 0:0:0:0:0:0:0:num2
	inline void Mod(const QUADUINT& num1, HALFUINT num2)
		{ this->Set(this->Div(num1, num2)); }

	// get remainder from result of division (rem = num - res*div)
	inline void GetMod(const QUADUINT& num, const QUADUINT& res, const QUADUINT& div)
		{	this->Mul(res, div);
			this->InvSub(num); }

	// this = num % 10
	inline void Mod10(const QUADUINT& num)
		{ this->Set(this->Div10(num)); }

// --- fast division (Division by invariant integers using multiplication by reciprocal value)

	// precalculate multiplier for fast division, returns flags FASTDIV_*
	// Divisor and "this" cannot be the same variables!
	int PreFastDiv(const QUADUINT& div);

	// fast divide using precalculated multiplier with flags
	// Dividend "num" and "this" cannot be the same variables!
	void FastDiv(const QUADUINT& num, const QUADUINT& mul, int flags);

	// test fast division and remainder (res = num1/num2 + rem)
	inline void TestFastDiv(const QUADUINT& num1, const QUADUINT& num2, QUADUINT* rem = NULL)
		{	QUADUINT mul;
			int flags = mul.PreFastDiv(num2);
			this->FastDiv(num1, mul, flags);
			if (rem != NULL) rem->GetMod(num1, *this, num2); }

	// test fast remainder (rem = num1 - res*num2)
	inline void TestFastMod(const QUADUINT& num1, const QUADUINT& num2)
		{	QUADUINT mul;
			int flags = mul.PreFastDiv(num2);
			mul.FastDiv(num1, mul, flags);
			this->GetMod(num1, mul, num2);}

// --- EQU ==

	// this == 0
	inline bool Equ0() const
		{ return (this->N0() == 0) &&
				(this->N1() == 0) &&
				(this->N2() == 0) &&
				(this->N3() == 0); }

	inline bool IsZero() const { return this->Equ0(); }
	
	// this == 1
	inline bool Equ1() const
		{ return (this->N0() == 1) &&
				(this->N1() == 0) &&
				(this->N2() == 0) &&
				(this->N3() == 0); }

	// this == all bits '1'
	inline bool EquAll()
		{ return (this->N0() == BASENOT) &&
				(this->N1() == BASENOT) &&
				(this->N2() == BASENOT) &&
				(this->N3() == BASENOT); }

	// this == -1
	inline bool EquM1() { return this->EquAll(); }

	// this == max (max. value)
	inline bool EquMax() { return this->EquAll(); }

	// this == min (min. value)
	inline bool EquMin() { return this->Equ0(); }

	// this == num
	inline bool Equ(const QUADUINT& num) const
		{ return (this->N0() == num.N0()) &&
				(this->N1() == num.N1()) &&
				(this->N2() == num.N2()) &&
				(this->N3() == num.N3()); }

	// this == 0:num
	inline bool Equ(const DBLUINT& num) const
		{ return (this->N0() == num.N0()) &&
				(this->N1() == num.N1()) &&
				(this->N2() == 0) &&
				(this->N3() == 0); }

	// this == 0:0:0:num
	inline bool Equ(BASEUINT num) const
		{ return (this->N0() == num) &&
				(this->N1() == 0) &&
				(this->N2() == 0) &&
				(this->N3() == 0); }

// --- NEQU !=

	// this != 0
	inline bool NEqu0() const
		{ return (this->N0() != 0) ||
				(this->N1() != 0) ||
				(this->N2() != 0) ||
				(this->N3() != 0); }

	inline bool IsNotZero() const { return this->NEqu0(); }

	// this != 1
	inline bool NEqu1() const
		{ return (this->N0() != 1) ||
				(this->N1() != 0) ||
				(this->N2() != 0) ||
				(this->N3() != 0); }

	// this != all bits '1'
	inline bool NEquAll()
		{ return (this->N0() != BASENOT) ||
				(this->N1() != BASENOT) ||
				(this->N2() != BASENOT) ||
				(this->N3() != BASENOT); }

	// this != -1
	inline bool NEquM1() { return this->NEquAll(); }

	// this != max (max. value)
	inline bool NEquMax() { return this->NEquAll(); }

	// this != min (min. value)
	inline bool NEquMin() { return this->NEqu0(); }

	// this != num
	inline bool NEqu(const QUADUINT& num) const
		{ return (this->N0() != num.N0()) ||
				(this->N1() != num.N1()) ||
				(this->N2() != num.N2()) ||
				(this->N3() != num.N3()); }

	// this != 0:num
	inline bool NEqu(const DBLUINT& num) const
		{ return (this->N0() != num.N0()) ||
				(this->N1() != num.N1()) ||
				(this->N2() != 0) ||
				(this->N3() != 0); }

	// this != 0:0:0:num
	inline bool NEqu(BASEUINT num) const
		{ return (this->N0() != num) ||
				(this->N1() != 0) ||
				(this->N2() != 0) ||
				(this->N3() != 0); }

// --- LESS <

	// this < num
	inline bool Less(const QUADUINT& num) const
		{ return (this->N3() < num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() < num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() < num.N0())))))); }

	// this < 0:num
	inline bool Less(const DBLUINT& num) const
		{ return (this->N3() == 0) &&
				(this->N2() == 0) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() < num.N0()))); }

	// this < 0:0:0:num
	inline bool Less(BASEUINT num) const
		{ return (this->N3() == 0) &&
				(this->N2() == 0) &&
				(this->N1() == 0) &&
				(this->N0() < num); }

// --- LESS EQU <=

	// this <= num
	inline bool LessEqu(const QUADUINT& num) const
		{ return (this->N3() < num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() < num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() <= num.N0())))))); }

	// this <= 0:num
	inline bool LessEqu(const DBLUINT& num) const
		{ return (this->N3() == 0) &&
				(this->N2() == 0) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() <= num.N0()))); }

	// this <= 0:0:0:num
	inline bool LessEqu(BASEUINT num) const
		{ return (this->N3() == 0) &&
				(this->N2() == 0) &&
				(this->N1() == 0) &&
				(this->N0() <= num); }

// --- GREATER >

	// this > num
	inline bool Greater(const QUADUINT& num) const
		{ return (this->N3() > num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() > num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() > num.N0())))))); }

	// this > 0:num
	inline bool Greater(const DBLUINT& num) const
		{ return (this->N3() > 0) ||
				(this->N2() > 0) ||
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() > num.N0()))); }

	// this > 0:0:0:num
	inline bool Greater(BASEUINT num) const
		{ return (this->N3() > 0) ||
				(this->N2() > 0) ||
				(this->N1() > 0) ||
				(this->N0() > num); }

// --- GREATER EQU >=

	// this >= num
	inline bool GreaterEqu(const QUADUINT& num) const
		{ return (this->N3() > num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() > num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() >= num.N0())))))); }

	// this >= 0:num
	inline bool GreaterEqu(const DBLUINT& num) const
		{ return (this->N3() > 0) ||
				(this->N2() > 0) ||
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() >= num.N0()))); }

	// this >= 0:0:0:num
	inline bool GreaterEqu(BASEUINT num) const
		{ return (this->N3() > 0) ||
				(this->N2() > 0) ||
				(this->N1() > 0) ||
				(this->N0() >= num); }

// --- NEG

	// this = -this
	void Neg();

	// this = -num
	void Neg(const QUADUINT& num);

	// this = -0:num
	void Neg(const DBLUINT& num);

	// this = -0:0:0:num
	void Neg(BASEUINT num);

// --- ABS

	// this = abs(this)
	inline void Abs()
		{ if (this->IsNeg()) this->Neg(); }

	// this = abs(num)
	inline void Abs(const QUADUINT& num)
		{ if (num.IsNeg()) this->Neg(num); else this->Set(num); }

// --- NOT ~

	// this = ~this
	inline void Not()
		{	this->N0() = ~this->N0();
			this->N1() = ~this->N1();
			this->N2() = ~this->N2();
			this->N3() = ~this->N3(); }

	// this = ~num
	inline void Not(const QUADUINT& num)
		{	this->N0() = ~num.N0();
			this->N1() = ~num.N1();
			this->N2() = ~num.N2();
			this->N3() = ~num.N3(); }

	// this = ~0:num
	inline void Not(DBLUINT num)
		{	this->N0() = ~num.N0();
			this->N1() = ~num.N1();
			this->N2() = BASENOT;
			this->N3() = BASENOT; }

	// this = ~0:0:0:num
	inline void Not(BASEUINT num)
		{	this->N0() = ~num;
			this->N1() = BASENOT;
			this->N2() = BASENOT;
			this->N3() = BASENOT; }

// --- AND &=

	// this &= num
	inline void And(const QUADUINT& num)
		{	this->N0() &= num.N0();
			this->N1() &= num.N1();
			this->N2() &= num.N2();
			this->N3() &= num.N3(); }

	// this &= 0:num
	inline void And(const DBLUINT& num)
		{	this->N0() &= num.N0();
			this->N1() &= num.N1();
			this->N2() = 0;
			this->N3() = 0; }

	// this &= 0:0:0:num
	inline void And(BASEUINT num)
		{	this->N0() &= num;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

// --- AND &

	// this = num1 & num2
	inline void And(const QUADUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() & num2.N0();
			this->N1() = num1.N1() & num2.N1();
			this->N2() = num1.N2() & num2.N2();
			this->N3() = num1.N3() & num2.N3(); }

	// this = num1 & 0:num2
	inline void And(const QUADUINT& num1, const DBLUINT& num2)
		{	this->N0() = num1.N0() & num2.N0();
			this->N1() = num1.N1() & num2.N1();
			this->N2() = 0;
			this->N3() = 0; }

	// this = 0:num1 & num2
	inline void And(const DBLUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() & num2.N0();
			this->N1() = num1.N1() & num2.N1();
			this->N2() = 0;
			this->N3() = 0; }

	// this = num1 & 0:0:0:num2
	inline void And(const QUADUINT& num1, BASEUINT num2)
		{	this->N0() = num1.N0() & num2;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

	// this = 0:0:0:num1 & num2
	inline void And(BASEUINT num1, const QUADUINT& num2)
		{	this->N0() = num1 & num2.N0();
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = 0; }

// --- OR |=

	// this |= num
	inline void Or(const QUADUINT& num)
		{	this->N0() |= num.N0();
			this->N1() |= num.N1();
			this->N2() |= num.N2();
			this->N3() |= num.N3(); }

	// this |= 0:num
	inline void Or(const DBLUINT& num)
		{	this->N0() |= num.N0();
			this->N1() |= num.N1(); }

	// this |= 0:0:0:num
	inline void Or(BASEUINT num)
		{ this->N0() |= num; }

// --- OR |

	// this = num1 | num2
	inline void Or(const QUADUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() | num2.N0();
			this->N1() = num1.N1() | num2.N1();
			this->N2() = num1.N2() | num2.N2();
			this->N3() = num1.N3() | num2.N3(); }

	// this = num1 | 0:num2
	inline void Or(const QUADUINT& num1, const DBLUINT& num2)
		{	this->N0() = num1.N0() | num2.N0();
			this->N1() = num1.N1() | num2.N1();
			this->N2() = num1.N2();
			this->N3() = num1.N3(); }

	// this = 0:num1 | num2
	inline void Or(const DBLUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() | num2.N0();
			this->N1() = num1.N1() | num2.N1();
			this->N2() = num2.N2();
			this->N3() = num2.N3(); }

	// this = num1 | 0:0:0:num2
	inline void Or(const QUADUINT& num1, BASEUINT num2)
		{	this->N0() = num1.N0() | num2;
			this->N1() = num1.N1();
			this->N2() = num1.N2();
			this->N3() = num1.N3(); }

	// this = 0:0:0:num1 | num2
	inline void Or(BASEUINT num1, const QUADUINT& num2)
		{	this->N0() = num1 | num2.N0();
			this->N1() = num2.N1();
			this->N2() = num2.N2();
			this->N3() = num2.N3(); }

// --- XOR ^=

	// this ^= num
	inline void Xor(const QUADUINT& num)
		{	this->N0() ^= num.N0();
			this->N1() ^= num.N1();
			this->N2() ^= num.N2();
			this->N3() ^= num.N3(); }

	// this ^= 0:num
	inline void Xor(const DBLUINT& num)
		{	this->N0() ^= num.N0();
			this->N1() ^= num.N1(); }

	// this ^= 0:0:0:num
	inline void Xor(BASEUINT num)
		{ this->N0() ^= num; }

// --- XOR ^

	// this = num1 ^ num2
	inline void Xor(const QUADUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() ^ num2.N0();
			this->N1() = num1.N1() ^ num2.N1();
			this->N2() = num1.N2() ^ num2.N2();
			this->N3() = num1.N3() ^ num2.N3(); }

	// this = num1 ^ 0:num2
	inline void Xor(const QUADUINT& num1, const DBLUINT& num2)
		{	this->N0() = num1.N0() ^ num2.N0();
			this->N1() = num1.N1() ^ num2.N1();
			this->N2() = num1.N2();
			this->N3() = num1.N3(); }

	// this = 0:num1 ^ num2
	inline void Xor(const DBLUINT& num1, const QUADUINT& num2)
		{	this->N0() = num1.N0() ^ num2.N0();
			this->N1() = num1.N1() ^ num2.N1();
			this->N2() = num2.N2();
			this->N3() = num2.N3(); }

	// this = num1 ^ 0:0:0:num2
	inline void Xor(const QUADUINT& num1, BASEUINT num2)
		{	this->N0() = num1.N0() ^ num2;
			this->N1() = num1.N1();
			this->N2() = num1.N2();
			this->N3() = num1.N3(); }

	// this = 0:0:0:num1 ^ num2
	inline void Xor(BASEUINT num1, const QUADUINT& num2)
		{	this->N0() = num1 ^ num2.N0();
			this->N1() = num2.N1();
			this->N2() = num2.N2();
			this->N3() = num2.N3(); }

// --- set/clear/get bit

	// set bit
	void SetBit(int bit);

	// reset bit
	void ResBit(int bit);

	// flip bit
	void FlipBit(int bit);

	// get bit (returns 0 or 1)
	int GetBit(int bit) const;

	// get number of valid bits (=logarithm+1, returns position of highest bit + 1, 0..4*BASEBITS)
	int Bits() const;

	// check if number is power of 2 (use Bits()-1 to determine 2nd logarithm)
	bool IsPwr2() const;

// --- LShift <<=

	// this <<= 1
	void LShift1();

	// this <<= shift
	void LShift(int shift);

// --- LShift <<

	// this = num << 1
	void LShift1(const QUADUINT& num);

	// this = num << shift
	void LShift(const QUADUINT& num, int shift);

	// this = 0:0:0:num << 1
	void LShift1(BASEUINT num);

	// this = 0:0:0:num << shift
	void LShift(BASEUINT num, int shift);

// --- RShift >>=

	// this >>= 1
	void RShift1();

	// this >>= shift
	void RShift(int shift);

// --- RShift >>

	// this = num >> 1
	void RShift1(const QUADUINT& num);

	// this = num >> shift
	void RShift(const QUADUINT& num, int shift);

	// this = 0:0:0:num >> 1
	void RShift1(BASEUINT num);

	// this = 0:0:0:num >> shift
	void RShift(BASEUINT num, int shift);

// --- text conversion

	// convert to ASCIIZ text into buffer of size approx. 1 + 2.41*size in bytes
	// (uint256: 78+1, uint128: 39+1, uin64: 20+1, uint32: 10+1), returns number of digits
	// sign = convert number as signed, with extra '-' character (reserve one more place in buffer)
	int ToTextBuf(char* buf, int bufsize, bool sign = false) const;
	CText ToText(bool sign = false) const;

	// convert number from text (len=text length, -1=unlimited or terminated by 0, returns number of processed characters)
	int FromTextBuf(const char* text, int len = -1);

	// convert number from text (returns new position)
	int FromText(const CText& text, int pos = 0);

// --- functions

	// integer square root with optional remainder, this = sqrt(num)
	void Sqrt(const QUADUINT& num, QUADUINT* rem = NULL);
	inline void Sqrt() { this->Sqrt(*this, NULL); }

// --- "in class" operators

	// =
	inline QUADUINT& operator= (const QUADUINT& num)
		{ this->Set(num); return *this; }

	inline QUADUINT& operator= (const QUADSINT& num)
		{ this->Set(num); return *this; }

	inline QUADUINT& operator= (const DBLUINT& num)
		{ this->Set(num); return *this; }

	inline QUADUINT& operator= (BASEUINT num)
		{ this->Set(num); return *this; }

	// +=
	inline QUADUINT& operator+= (const QUADUINT& num)
		{ this->Add(num); return *this; }

	inline QUADUINT& operator+= (const DBLUINT& num)
		{ this->Add(num); return *this; }

	inline QUADUINT& operator+= (BASEUINT num)
		{ this->Add(num); return *this; }

	// -=
	inline QUADUINT& operator-= (const QUADUINT& num)
		{ this->Sub(num); return *this; }

	inline QUADUINT& operator-= (const DBLUINT& num)
		{ this->Sub(num); return *this; }

	inline QUADUINT& operator-= (BASEUINT num)
		{ this->Sub(num); return *this; }

	// ++
	inline QUADUINT& operator++ () // prefix
		{ this->Inc(); return *this; }

	inline QUADUINT operator++ (int)// postfix
		{ QUADUINT num(*this); this->Inc(); return num; }

	// --
	inline QUADUINT& operator-- () // prefix
		{ this->Dec(); return *this; }

	inline QUADUINT operator-- (int) // postfix
		{ QUADUINT num(*this); this->Dec(); return num; }

	// -
	inline QUADUINT operator- () const // prefix
		{ QUADUINT num; num.Neg(*this); return num; }

	// *=
	inline QUADUINT& operator*= (const QUADUINT& num)
		{ this->Mul(num); return *this; }

	inline QUADUINT& operator*= (const DBLUINT& num)
		{ this->Mul(num); return *this; }

	inline QUADUINT& operator*= (BASEUINT num)
		{ this->Mul(num); return *this; }

	// /=
	inline QUADUINT& operator/= (const QUADUINT& num)
		{ this->Div(num); return *this; }

	inline QUADUINT& operator/= (const DBLUINT& num)
		{ this->Div(num); return *this; }

	inline QUADUINT& operator/= (BASEUINT num)
		{ this->Div(num); return *this; }

	// %=
	inline QUADUINT& operator%= (const QUADUINT& num)
		{ this->Mod(num); return *this; }

	inline QUADUINT& operator%= (const DBLUINT& num)
		{ this->Mod(num); return *this; }

	inline QUADUINT& operator%= (BASEUINT num)
		{ this->Mod(num); return *this; }

	// ~
	inline QUADUINT operator~ () const // prefix
		{ QUADUINT num; num.Not(*this); return num; }

	// &=
	inline QUADUINT& operator&= (const QUADUINT& num)
		{ this->And(num); return *this; }

	inline QUADUINT& operator&= (const DBLUINT& num)
		{ this->And(num); return *this; }

	inline QUADUINT& operator&= (BASEUINT num)
		{ this->And(num); return *this; }

	// |=
	inline QUADUINT& operator|= (const QUADUINT& num)
		{ this->Or(num); return *this; }

	inline QUADUINT& operator|= (const DBLUINT& num)
		{ this->Or(num); return *this; }

	inline QUADUINT& operator|= (BASEUINT num)
		{ this->Or(num); return *this; }

	// ^=
	inline QUADUINT& operator^= (const QUADUINT& num)
		{ this->Xor(num); return *this; }

	inline QUADUINT& operator^= (const DBLUINT& num)
		{ this->Xor(num); return *this; }

	inline QUADUINT& operator^= (BASEUINT num)
		{ this->Xor(num); return *this; }

	// <<=
	inline QUADUINT& operator<<= (int shift)
		{ this->LShift(shift); return *this; }

	// >>=
	inline QUADUINT& operator>>= (int shift)
		{ this->RShift(shift); return *this; }
};

// +
inline QUADUINT operator+ (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Add(num1, num2); return num; }

inline QUADUINT operator+ (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Add(num1, num2); return num; }

inline QUADUINT operator+ (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Add(num1, num2); return num; }

inline QUADUINT operator+ (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Add(num1, num2); return num; }

inline QUADUINT operator+ (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.Add(num1, num2); return num; }

// -
inline QUADUINT operator- (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Sub(num1, num2); return num; }

inline QUADUINT operator- (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Sub(num1, num2); return num; }

inline QUADUINT operator- (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Sub(num1, num2); return num; }

inline QUADUINT operator- (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Sub(num1, num2); return num; }

inline QUADUINT operator- (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.Sub(num1, num2); return num; }

// *
inline QUADUINT operator* (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Mul(num1, num2); return num; }

inline QUADUINT operator* (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Mul(num1, num2); return num; }

inline QUADUINT operator* (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Mul(num1, num2); return num; }

inline QUADUINT operator* (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Mul(num1, num2); return num; }

inline QUADUINT operator* (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.Mul(num1, num2); return num; }

// /
inline QUADUINT operator/ (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Div(num1, num2); return num; }

inline QUADUINT operator/ (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Div(num1, num2); return num; }

inline QUADUINT operator/ (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Div(num1, num2); return num; }

inline QUADUINT operator/ (const QUADUINT& num1, HALFUINT num2)
	{ QUADUINT num; num.Div(num1, num2); return num; }

// %
inline QUADUINT operator% (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Mod(num1, num2); return num; }

inline QUADUINT operator% (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Mod(num1, num2); return num; }

inline QUADUINT operator% (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Mod(num1, num2); return num; }

inline QUADUINT operator% (const QUADUINT& num1, HALFUINT num2)
	{ QUADUINT num; num.Mod(num1, num2); return num; }

// ==
inline bool operator== (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.Equ(num1); }

inline bool operator== (const QUADUINT& num1, BASEUINT num2)
	{ return num1.Equ(num2); }

inline bool operator== (BASEUINT num1, const QUADUINT& num2)
	{ return num2.Equ(num1); }

// !=
inline bool operator!= (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.NEqu(num1); }

inline bool operator!= (const QUADUINT& num1, BASEUINT num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (BASEUINT num1, const QUADUINT& num2)
	{ return num2.NEqu(num1); }

// <
inline bool operator< (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.Less(num2); }

inline bool operator< (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.Less(num2); }

inline bool operator< (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.Greater(num1); }

inline bool operator< (const QUADUINT& num1, BASEUINT num2)
	{ return num1.Less(num2); }

inline bool operator< (BASEUINT num1, const QUADUINT& num2)
	{ return num2.Greater(num1); }

// <=
inline bool operator<= (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.GreaterEqu(num1); }

inline bool operator<= (const QUADUINT& num1, BASEUINT num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (BASEUINT num1, const QUADUINT& num2)
	{ return num2.GreaterEqu(num1); }

// >
inline bool operator> (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.Less(num1); }

inline bool operator> (const QUADUINT& num1, BASEUINT num2)
	{ return num1.Greater(num2); }

inline bool operator> (BASEUINT num1, const QUADUINT& num2)
	{ return num2.Less(num1); }

// >=
inline bool operator>= (const QUADUINT& num1, const QUADUINT& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const QUADUINT& num1, const DBLUINT& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const DBLUINT& num1, const QUADUINT& num2)
	{ return num2.LessEqu(num1); }

inline bool operator>= (const QUADUINT& num1, BASEUINT num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (BASEUINT num1, const QUADUINT& num2)
	{ return num2.LessEqu(num1); }

// &
inline QUADUINT operator& (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.And(num1, num2); return num; }

inline QUADUINT operator& (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.And(num1, num2); return num; }

inline QUADUINT operator& (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.And(num1, num2); return num; }

inline QUADUINT operator& (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.And(num1, num2); return num; }

inline QUADUINT operator& (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.And(num1, num2); return num; }

// |
inline QUADUINT operator| (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Or(num1, num2); return num; }

inline QUADUINT operator| (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Or(num1, num2); return num; }

inline QUADUINT operator| (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Or(num1, num2); return num; }

inline QUADUINT operator| (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Or(num1, num2); return num; }

inline QUADUINT operator| (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.Or(num1, num2); return num; }

// ^
inline QUADUINT operator^ (const QUADUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Xor(num1, num2); return num; }

inline QUADUINT operator^ (const QUADUINT& num1, const DBLUINT& num2)
	{ QUADUINT num; num.Xor(num1, num2); return num; }

inline QUADUINT operator^ (const DBLUINT& num1, const QUADUINT& num2)
	{ QUADUINT num; num.Xor(num1, num2); return num; }

inline QUADUINT operator^ (const QUADUINT& num1, BASEUINT num2)
	{ QUADUINT num; num.Xor(num1, num2); return num; }

inline QUADUINT operator^ (BASEUINT num1, const QUADUINT& num2)
	{ QUADUINT num; num.Xor(num1, num2); return num; }

// <<
inline QUADUINT operator<< (const QUADUINT& num, int shift)
	{ QUADUINT n; n.LShift(num, shift); return n; }

// >>
inline QUADUINT operator>> (const QUADUINT& num, int shift)
	{ QUADUINT n; n.RShift(num, shift); return n; }


// quadruple integer signed
class QUADSINT : protected QUADUINT
{
protected:

	// factorial table
	static QUADSINT* Fact_;

	// initialize factorial table
	static bool FactOK;
	static bool FactInit();

public:

	// max. factorial
	static BASEUINT FactMax;

// --- constructor

	inline QUADSINT() {}

	inline QUADSINT(const QUADSINT& num)
		{ this->Set(num); }

	inline QUADSINT(const DBLSINT& num)
		{ this->Set(num); }

	inline QUADSINT(BASESINT num)
		{ this->Set(num); }

// --- access to value

	inline BASEUINT& N0() { return m_N[0]; }
	inline BASEUINT& N1() { return m_N[1]; }
	inline BASEUINT& N2() { return m_N[2]; }
	inline BASESINT& N3() { return *(BASESINT*)&m_N[3]; }

	inline const BASEUINT& N0() const { return m_N[0]; }
	inline const BASEUINT& N1() const { return m_N[1]; }
	inline const BASEUINT& N2() const { return m_N[2]; }
	inline const BASESINT& N3() const { return *(const BASESINT*)&m_N[3]; }

	// check if number is negative
	inline bool IsNeg() const { return this->N3() < 0; }
	inline bool IsNotNeg() const { return this->N3() >= 0; }

// --- SET =

	// this = 0
	inline void Set0() { QUADUINT::Set0(); }

	// this = 1
	inline void Set1() { QUADUINT::Set1(); }

	// this = all '1' (= -1)
	inline void SetAll() { QUADUINT::SetAll(); }

	// this = -1
	inline void SetM1() { QUADUINT::SetAll(); }

	// this = max (max. positive value)
	inline void SetMax()
		{	this->N0() = BASENOT;
			this->N1() = BASENOT;
			this->N2() = BASENOT;
			this->N3() = BASELAST-1; }

	// this = -min (min. negative value)
	//  be aware - negation of this number will stay negative
	inline void SetMin()
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = 0;
			this->N3() = (BASESINT)BASELAST; }

	// this = num
	inline void Set(const QUADSINT& num) { QUADUINT::Set(*(const QUADUINT*)&num); }
	inline void Set(const QUADUINT& num) { QUADUINT::Set(num); }

	// this = s:num (signed)
	inline void Set(const DBLSINT& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1();
			BASESINT k = (num.IsNeg() ? -1 : 0);
			this->N2() = k;
			this->N3() = k; }

	// this = s:s:s:num (signed)
	inline void Set(BASESINT num)
		{	this->N0() = num;
			BASESINT k = (num < 0) ? -1 : 0;
			this->N1() = k;
			this->N2() = k;
			this->N3() = k; }

	// this = num3:num2:num1:num0
	inline void Set(BASEUINT num0, BASEUINT num1, BASEUINT num2, BASESINT num3)
		{ QUADUINT::Set(num0, num1, num2, (BASEUINT)num3); }

	// factorial this = num!
	void Fact(BASEUINT num);
	void Fact();

	// exchange two numbers
	inline void Exchange(QUADSINT& num) { QUADUINT::Exchange(*(QUADUINT*)&num); }

// --- ADD +=

	// this += num
	inline void Add(const QUADSINT& num) { QUADUINT::Add(*(const QUADUINT*)&num); }

	// this += s:num (signed)
	inline void Add(const DBLSINT& num)
		{	if (num.IsNeg())
			{
				DBLUINT n;
				n.Neg(*(const DBLUINT*)&num);
				QUADUINT::Sub(n);
			}
			else
				QUADUINT::Add(*(const DBLUINT*)&num); }

	// this += s:s:s:num (signed)
	inline void Add(BASESINT num)
		{	if (num < 0)
				QUADUINT::Sub((BASEUINT)-num); 
			else
				QUADUINT::Add((BASEUINT)num); }

// --- ADD +

	// this = num1 + num2
	inline void Add(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADUINT::Add(*(const QUADUINT*)&num1, *(const QUADUINT*)&num2); }

	// this = num1 + s:num2 (signed)
	void Add(const QUADSINT& num1, const DBLSINT& num2)
		{	if (num2.IsNeg())
			{
				DBLUINT n;
				n.Neg(*(const DBLUINT*)&num2);
				QUADUINT::Sub(*(const QUADUINT*)&num1, n);
			}
			else
				QUADUINT::Add(*(const QUADUINT*)&num1, *(const DBLUINT*)&num2);
		}

	// this = s:num1 + num2 (signed)
	inline void Add(const DBLSINT& num1, const QUADSINT& num2)
		{ this->Add(num2, num1); }

	// this = num1 + s:s:s:num2 (signed)
	inline void Add(const QUADSINT& num1, BASESINT num2)
		{	if (num2 < 0)
				QUADUINT::Sub(*(const QUADUINT*)&num1, (BASEUINT)-num2);
			else
				QUADUINT::Add(*(const QUADUINT*)&num1, (BASEUINT)num2); }

	// this = s:s:s:num1 + num2 (signed)
	inline void Add(BASESINT num1, const QUADSINT& num2)
		{ this->Add(num2, num1); }

// --- SUB -=

	// this -= num
	inline void Sub(const QUADSINT& num) { QUADUINT::Sub(*(const QUADUINT*)&num); }

	// this -= s:num (signed)
	inline void Sub(const DBLSINT& num)
		{	if (num.IsNeg())
			{
				DBLUINT n;
				n.Neg(*(const DBLUINT*)&num);
				QUADUINT::Add(n);
			}
			else
				QUADUINT::Sub(*(const DBLUINT*)&num); }

	// this -= s:s:s:num (signed)
	inline void Sub(BASESINT num)
		{	if (num < 0)
				QUADUINT::Add((BASEUINT)-num);
			else
				QUADUINT::Sub((BASEUINT)num); }

// --- SUB -

	// this = num1 - num2
	inline void Sub(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADUINT::Sub(*(const QUADUINT*)&num1, *(const QUADUINT*)&num2); }

	// this = num1 - s:num2 (signed)
	inline void Sub(const QUADSINT& num1, const DBLSINT& num2)
		{	if (num2.IsNeg())
			{
				DBLUINT n;
				n.Neg(*(const DBLUINT*)&num2);
				QUADUINT::Add(*(const QUADUINT*)&num1, n);
			}
			else
				QUADUINT::Sub(*(const QUADUINT*)&num1, *(const DBLUINT*)&num2); }

	// this = s:num1 - num2
	inline void Sub(const DBLSINT& num1, const QUADSINT& num2)
		{	QUADSINT n;
			n.Set(num1);
			this->Sub(n, num2); }

	// this = num1 - s:s:s:num2 (signed)
	inline void Sub(const QUADSINT& num1, BASESINT num2)
		{	if (num2 < 0)
				QUADUINT::Add(*(const QUADUINT*)&num1, (BASEUINT)-num2);
			else
				QUADUINT::Sub(*(const QUADUINT*)&num1, (BASEUINT)num2); }

	// this = s:s:s:num1 - num2 (signed)
	inline void Sub(BASESINT num1, const QUADSINT& num2)
		{	QUADUINT::Neg(*(const QUADUINT*)&num2);
			this->Add(num1); }

// --- INV SUB =-

	// this = num - this
	inline void InvSub(const QUADSINT& num)
		{ QUADUINT::InvSub(*(const QUADUINT*)&num); }

	// this = s:num - this (signed)
	inline void InvSub(const DBLSINT& num)
		{	QUADSINT n;
			n.Set(num);
			this->Sub(n, *this); }

	// this = s:s:s:num - this (signed)
	inline void InvSub(BASESINT num)
		{	QUADUINT::Neg();
			this->Add(num); }

// --- increment ++

	// this++
	inline void Inc() { QUADUINT::Inc(); }

	// this = num + 1
	inline void Inc(const QUADSINT& num)
		{ QUADUINT::Inc(*(const QUADUINT*)&num); }

// --- decrement --

	// this--
	inline void Dec() { QUADUINT::Dec(); }

	// this = num - 1
	inline void Dec(const QUADSINT& num)
		{ QUADUINT::Dec(*(const QUADUINT*)&num); }

// --- MUL *= (signed)

	// this *= num
	inline void Mul(const QUADSINT& num)
		{ this->Mul(*this, num); }

	// this *= s:num
	inline void Mul(const DBLSINT& num)
		{ this->Mul(*this, num); }

	// this *= s:s:s:num
	inline void Mul(BASESINT num)
		{ this->Mul(*this, num); }

	// this *= 10, returns high carry (+-0..9)
	inline int Mul10()
		{ return this->Mul10(*this); }

// --- MUL * (signed)

	// this = num1 * num2
	void Mul(const QUADSINT& num1, const QUADSINT& num2);

	// this = num1 * s:num2
	void Mul(const QUADSINT& num1, const DBLSINT& num2);

	// this = s:num1 * num2
	inline void Mul(const DBLSINT& num1, const QUADSINT& num2)
		{ this->Mul(num2, num1); }

	// this = num1 * s:s:s:num2
	void Mul(const QUADSINT& num1, BASESINT num2);

	// this = s:s:s:num1 * num2
	inline void Mul(BASESINT num1, const QUADSINT& num2)
		{ this->Mul(num2, num1); }

	// this = s:num1 * s:num2
	void Mul(const DBLSINT& num1, const DBLSINT& num2);

	// this = s:num1 * s:s:s:num2
	void Mul(const DBLSINT& num1, BASESINT num2);

	// this = s:s:s:num1 * s:num2
	inline void Mul(BASESINT num1, const DBLSINT& num2)
		{ this->Mul(num2, num1); }

	// this = s:s:s:num1 * s:s:s:num2
	void Mul(BASESINT num1, BASESINT num2);

	// this = num1 * num2, with full range of result (high = destination of high part of result)
	// "this" result is unsigned! (sign is in high part of result)
	void MulHigh(const QUADSINT& num1, const QUADSINT& num2, QUADSINT* high);

	// this = num * 10, returns high carry (+-0..9)
	int Mul10(const QUADSINT& num);

// --- SQR (signed)

	// this *= this
	inline void Sqr()
		{ this->Sqr(*this); }

	// this = num * num
	void Sqr(const QUADSINT& num);

	// this = s:num * s:num
	void Sqr(const DBLSINT& num);

	// this = s:s:s:num * s:s:s:num
	inline void Sqr(BASESINT num)
		{	if (num < 0)
				QUADUINT::Sqr((BASEUINT)-num);
			else
				QUADUINT::Sqr((BASEUINT)num); }

// --- DIV /= (signed)
// remainder will have the same sign as dividend

	// this = this / num, with optional destination remainder
	inline void Div(const QUADSINT& num, QUADSINT* rem = NULL)
		{ this->Div(*this, num, rem); }

	// this = this / s:num, with optional destination remainder
	inline void Div(const DBLSINT& num, QUADSINT* rem = NULL)
		{ this->Div(*this, num, rem); }

	// this = this / s:s:s:num, returns remainder
	inline BASESINT Div(BASESINT num)
		{ return this->Div(*this, num); }

	// this = this / s:s:s:s:s:s:s:num, returns remainder
	inline HALFSINT Div(HALFSINT num)
		{ return this->Div(*this, num); }

	// this = num / this, with optional destination remainder
	inline void InvDiv(const QUADSINT& num, QUADSINT* rem = NULL)
		{ this->Div(num, *this, rem); }

	// this = num / 10, returns remainder +-0..9
	inline int Div10()
		{ return this->Div10(*this); }

// --- DIV / (signed)
// remainder will have the same sign as dividend

	// this = num1 / num2, with optional destination remainder (sources and destinations can be mixed)
	void Div(const QUADSINT& num1, const QUADSINT& num2, QUADSINT* rem = NULL);

	// this = num1 / s:num2, with optional destination remainder (sources and destinations can be mixed)
	void Div(const QUADSINT& num1, const DBLSINT& num2, QUADSINT* rem = NULL);

	// this = num1 / s:s:s:num2, returns remainder
	BASESINT Div(const QUADSINT& num1, BASESINT num2);

	// this = num1 / s:s:s:s:s:s:s:num2, returns remainder
	HALFSINT Div(const QUADSINT& num1, HALFSINT num2);

	// this = num1H:num1L / num2, with full range of dividend
	void DivHigh(const QUADUINT& num1L, const QUADSINT& num1H, const QUADSINT& num2, QUADSINT* rem = NULL);

	// this = num / 10, returns remainder +-0..9
	int Div10(const QUADSINT& num);

// --- MOD %= (signed)
// remainder will have the same sign as dividend

	// this = this % num
	inline void Mod(const QUADSINT& num)
		{ QUADSINT n; n.Div(*this, num, this); }

	// this = this % s:num
	inline void Mod(const DBLSINT& num)
		{ QUADSINT n; n.Div(*this, num, this); }

	// this = this % s:s:s:num
	inline void Mod(BASESINT num)
		{ this->Set(this->Div(*this, num)); }

	// this = this % s:s:s:s:s:s:s:num
	inline void Mod(HALFSINT num)
		{ this->Set(this->Div(*this, num)); }

	// this = this % 10
	inline void Mod10()
		{ this->Set(this->Div10()); }

// --- MOD % (signed)
// remainder will have the same sign as dividend

	// this = num1 % num2
	inline void Mod(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADSINT n; n.Div(num1, num2, this); }

	// this = num1 % s:num2
	inline void Mod(const QUADSINT& num1, const DBLSINT& num2)
		{ QUADSINT n; n.Div(num1, num2, this); }

	// this = num1 % s:s:s:num2
	inline void Mod(const QUADSINT& num1, BASESINT num2)
		{ this->Set(this->Div(num1, num2)); }

	// this = num1 % s:s:s:s:s:s:s:num2
	inline void Mod(const QUADSINT& num1, HALFSINT num2)
		{ this->Set(this->Div(num1, num2)); }

	// get remainder from result of division (rem = num - res*div)
	inline void GetMod(const QUADSINT& num, const QUADSINT& res, const QUADSINT& div)
		{	this->Mul(res, div);
			this->InvSub(num); }

	// this = num % 10
	inline void Mod10(const QUADSINT& num)
		{ this->Set(this->Div10(num)); }

// --- fast division (Division by invariant integers using multiplication by reciprocal value)

	// precalculate multiplier for fast division, returns flags FASTDIV_*
	// Divisor and "this" cannot be the same variables!
	int PreFastDiv(const QUADSINT& div);

	// fast divide using precalculated multiplier with flags
	// Dividend "num" and "this" cannot be the same variables!
	void FastDiv(const QUADSINT& num, const QUADSINT& mul, int flags);

	// test fast division and remainder (res = num1/num2 + rem)
	inline void TestFastDiv(const QUADSINT& num1, const QUADSINT& num2, QUADSINT* rem = NULL)
		{	QUADSINT mul;
			int flags = mul.PreFastDiv(num2);
			this->FastDiv(num1, mul, flags);
			if (rem != NULL) rem->GetMod(num1, *this, num2); }

	// test fast remainder (rem = num1 - res*num2)
	inline void TestFastMod(const QUADSINT& num1, const QUADSINT& num2)
		{	QUADSINT mul;
			int flags = mul.PreFastDiv(num2);
			mul.FastDiv(num1, mul, flags);
			this->GetMod(num1, mul, num2); }

// --- EQU ==

	// this == 0
	inline bool Equ0() const
		{ return QUADUINT::Equ0(); }

	inline bool IsZero() const { return this->Equ0(); }
	
	// this == 1
	inline bool Equ1() const
		{ return QUADUINT::Equ1(); }

	// this == all '1' (= -1)
	inline bool EquAll() { return QUADUINT::EquAll(); }

	// this == -1
	inline bool EquM1() { return QUADUINT::EquM1(); }

	// this == max (max. positive value)
	inline bool EquMax()
		{ return (this->N0() == BASENOT) &&
				(this->N1() == BASENOT) &&
				(this->N2() == BASENOT) &&
				(this->N3() == BASELAST-1); }

	// this == -min (min. negative value)
	inline bool EquMin()
		{ return (this->N0() == 0) &&
				(this->N1() == 0) &&
				(this->N2() == 0) &&
				(this->N3() == (BASESINT)BASELAST); }

	// this == num
	inline bool Equ(const QUADSINT& num) const
		{ return QUADUINT::Equ(*(const QUADUINT*)&num); }

	// this == s:num
	inline bool Equ(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N0() == num.N0()) &&
				(this->N1() == (BASEUINT)num.N1()) &&
				(this->N2() == (BASEUINT)k) &&
				(this->N3() == k); }

	// this == s:s:s:num
	inline bool Equ(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N0() == (BASEUINT)num) &&
				(this->N1() == (BASEUINT)k) &&
				(this->N2() == (BASEUINT)k) &&
				(this->N3() == k); }

// --- NEQU !=

	// this != 0
	inline bool NEqu0() const
		{ return QUADUINT::NEqu0(); }

	inline bool IsNotZero() const { return this->NEqu0(); }

	// this != 1
	inline bool NEqu1() const
		{ return QUADUINT::NEqu1(); }

	// this != all '1' (= -1)
	inline bool NEquAll() { return QUADUINT::NEquAll(); }

	// this != -1
	inline bool NEquM1() { return QUADUINT::NEquM1(); }

	// this != max (max. positive value)
	inline bool NEquMax()
		{ return (this->N0() != BASENOT) ||
				(this->N1() != BASENOT) ||
				(this->N2() != BASENOT) ||
				(this->N3() != BASELAST-1); }

	// this == -min (min. negative value)
	inline bool NEquMin()
		{ return (this->N0() != 0) ||
				(this->N1() != 0) ||
				(this->N2() != 0) ||
				(this->N3() != (BASESINT)BASELAST); }

	// this != num
	inline bool NEqu(const QUADSINT& num) const
		{ return QUADUINT::NEqu(*(const QUADUINT*)&num); }

	// this != s:num
	inline bool NEqu(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N0() != num.N0()) ||
				(this->N1() != (BASEUINT)num.N1()) ||
				(this->N2() != (BASEUINT)k) ||
				(this->N3() != k); }

	// this != s:s:s:num
	inline bool NEqu(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N0() != (BASEUINT)num) ||
				(this->N1() != (BASEUINT)k) ||
				(this->N2() != (BASEUINT)k) ||
				(this->N3() != k); }

// --- LESS <

	// this < num
	inline bool Less(const QUADSINT& num) const
		{ return (this->N3() < num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() < num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() < num.N0())))))); }

	// this < s:num
	inline bool Less(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() < (BASEUINT)num.N1()) || ((this->N1() == (BASEUINT)num.N1()) &&
				(this->N0() < num.N0())))))); }

	// this < s:s:s:num
	inline bool Less(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() < (BASEUINT)k) || ((this->N1() == (BASEUINT)k) &&
				(this->N0() < (BASEUINT)num)))))); }

// --- LESS EQU <=

	// this <= num
	inline bool LessEqu(const QUADSINT& num) const
		{ return (this->N3() < num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() < num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() < num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() <= num.N0())))))); }

	// this <= s:num
	inline bool LessEqu(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() < (BASEUINT)num.N1()) || ((this->N1() == (BASEUINT)num.N1()) &&
				(this->N0() <= num.N0())))))); }

	// this <= s:s:s:num
	inline bool LessEqu(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() < (BASEUINT)k) || ((this->N1() == (BASEUINT)k) &&
				(this->N0() <= (BASEUINT)num)))))); }

// --- GREATER >

	// this > num
	inline bool Greater(const QUADSINT& num) const
		{ return (this->N3() > num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() > num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() > num.N0())))))); }

	// this > s:num
	inline bool Greater(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() > (BASEUINT)num.N1()) || ((this->N1() == (BASEUINT)num.N1()) &&
				(this->N0() > num.N0())))))); }

	// this > s:s:s:num
	inline bool Greater(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() > (BASEUINT)k) || ((this->N1() == (BASEUINT)k) &&
				(this->N0() > (BASEUINT)num)))))); }

// --- GREATER EQU >=

	// this >= num
	inline bool GreaterEqu(const QUADSINT& num) const
		{ return (this->N3() > num.N3()) || ((this->N3() == num.N3()) &&
				((this->N2() > num.N2()) || ((this->N2() == num.N2()) &&
				((this->N1() > num.N1()) || ((this->N1() == num.N1()) &&
				(this->N0() >= num.N0())))))); }

	// this >= s:num
	inline bool GreaterEqu(const DBLSINT& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() > (BASEUINT)num.N1()) || ((this->N1() == (BASEUINT)num.N1()) &&
				(this->N0() >= num.N0())))))); }

	// this >= s:s:s:num
	inline bool GreaterEqu(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)k) || ((this->N2() == (BASEUINT)k) &&
				((this->N1() > (BASEUINT)k) || ((this->N1() == (BASEUINT)k) &&
				(this->N0() >= (BASEUINT)num)))))); }

// --- NEG

	// this = -this
	inline void Neg()
		{ QUADUINT::Neg(); }

	// this = -num
	inline void Neg(const QUADSINT& num)
		{ QUADUINT::Neg(*(const QUADUINT*)&num); }

	// this = -s:num
	inline void Neg(const DBLSINT& num)
		{	this->Set(num);
			this->Neg(); }

	// this = -s:s:s:num
	inline void Neg(BASESINT num)
		{	this->Set(num);
			this->Neg(); }

// --- ABS

	// this = abs(this)
	inline void Abs() { QUADUINT::Abs(); }

	// this = abs(num)
	inline void Abs(const QUADSINT& num)
		{ QUADUINT::Abs(*(const QUADUINT*)&num); }

	// this = abs(s:num)
	inline void Abs(const DBLSINT& num)
		{ if (num.IsNeg()) this->Neg(num); else this->Set(num); }

	// this = abs(s:s:s:num)
	inline void Abs(BASESINT num)
		{ if (num < 0) this->Neg(num); else this->Set(num); }

// --- NOT ~

	// this = ~this
	inline void Not()
		{ QUADUINT::Not(); }

	// this = ~num
	inline void Not(const QUADSINT& num)
		{ QUADUINT::Not(*(const QUADUINT*)&num); }

	// this = ~s:num
	inline void Not(DBLSINT num)
		{	this->N0() = ~num.N0();
			this->N1() = ~(BASEUINT)num.N1();
			BASESINT k = num.IsNeg() ? 0 : -1;
			this->N2() = (BASEUINT)k;
			this->N3() = k; }

	// this = ~s:s:s:num
	inline void Not(BASESINT num)
		{	this->N0() = ~(BASEUINT)num;
			BASESINT k = (num < 0) ? 0 : -1;
			this->N1() = (BASEUINT)k;
			this->N2() = (BASEUINT)k;
			this->N3() = k; }

// --- AND &=

	// this &= num
	inline void And(const QUADSINT& num)
		{ QUADUINT::And(*(const QUADUINT*)&num); }

	// this &= s:num
	inline void And(const DBLSINT& num)
		{	this->N0() &= num.N0();
			this->N1() &= (BASEUINT)num.N1();
			if (num.IsNotNeg())
			{	this->N2() = 0;
				this->N3() = 0; }}

	// this &= s:s:s:num
	inline void And(BASESINT num)
		{	this->N0() &= (BASEUINT)num;
			if (num >= 0)
			{	this->N1() = 0;
				this->N2() = 0;
				this->N3() = 0; }}

// --- AND &

	// this = num1 & num2
	inline void And(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADUINT::And(*(const QUADUINT*)&num1, *(const QUADUINT*)&num2); }

	// this = num1 & s:num2
	inline void And(const QUADSINT& num1, const DBLSINT& num2)
		{	this->N0() = num1.N0() & num2.N0();
			this->N1() = num1.N1() & (BASEUINT)num2.N1();
			if (num2.IsNeg())
			{	this->N2() = num1.N2();
				this->N3() = num1.N3(); }
			else
			{	this->N2() = 0;
				this->N3() = 0; }}

	// this = s:num1 & num2
	inline void And(const DBLSINT& num1, const QUADSINT& num2)
		{	this->N0() = num1.N0() & num2.N0();
			this->N1() = (BASEUINT)num1.N1() & num2.N1();
			if (num1.IsNeg())
			{	this->N2() = num2.N2();
				this->N3() = num2.N3(); }
			else
			{	this->N2() = 0;
				this->N3() = 0; }}

	// this = num1 & s:s:s:num2
	inline void And(const QUADSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() & (BASEUINT)num2;
			if (num2 < 0)
			{	this->N1() = num1.N1();
				this->N2() = num1.N2();
				this->N3() = num1.N3(); }
			else
			{	this->N1() = 0;
				this->N2() = 0;
				this->N3() = 0; }}

	// this = 0:0:0:num1 & num2
	inline void And(BASESINT num1, const QUADSINT& num2)
		{	this->N0() = (BASEUINT)num1 & num2.N0();
			if (num1 < 0)
			{	this->N1() = num2.N1();
				this->N2() = num2.N2();
				this->N3() = num2.N3(); }
			else
			{	this->N1() = 0;
				this->N2() = 0;
				this->N3() = 0; }}

// --- OR |=

	// this |= num
	inline void Or(const QUADSINT& num)
		{ QUADUINT::Or(*(const QUADUINT*)&num); }

	// this |= s:num
	inline void Or(const DBLSINT& num)
		{	this->N0() |= num.N0();
			this->N1() |= (BASEUINT)num.N1();
			if (num.IsNeg())
			{	this->N2() = BASENOT;
				this->N3() = -1; } }

	// this |= s:s:s:num
	inline void Or(BASESINT num)
		{	this->N0() |= (BASEUINT)num;
			if (num < 0)
			{	this->N1() = BASENOT;
				this->N2() = BASENOT;
				this->N3() = -1; } }

// --- OR |

	// this = num1 | num2
	inline void Or(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADUINT::Or(*(const QUADUINT*)&num1, *(const QUADUINT*)&num2); }

	// this = num1 | s:num2
	inline void Or(const QUADSINT& num1, const DBLSINT& num2)
		{	this->N0() = num1.N0() | num2.N0();
			this->N1() = num1.N1() | (BASEUINT)num2.N1();
			if (num2.IsNeg())
			{	this->N2() = BASENOT;
				this->N3() = -1; }
			else
			{	this->N2() = num1.N2();
				this->N3() = num1.N3(); } }

	// this = s:num1 | num2
	inline void Or(const DBLSINT& num1, const QUADSINT& num2)
		{	this->N0() = num1.N0() | num2.N0();
			this->N1() = (BASEUINT)num1.N1() | num2.N1();
			if (num1.IsNeg())
			{	this->N2() = BASENOT;
				this->N3() = -1; }
			else
			{	this->N2() = num2.N2();
				this->N3() = num2.N3(); } }

	// this = num1 | s:s:s:num2
	inline void Or(const QUADSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() | (BASEUINT)num2;
			if (num2 < 0)
			{	this->N1() = BASENOT;
				this->N2() = BASENOT;
				this->N3() = -1; }
			else
			{	this->N1() = num1.N1();
				this->N2() = num1.N2();
				this->N3() = num1.N3(); } }

	// this = s:s:s:num1 | num2
	inline void Or(BASESINT num1, const QUADSINT& num2)
		{	this->N0() = num2.N0() | (BASEUINT)num1;
			if (num1 < 0)
			{	this->N1() = BASENOT;
				this->N2() = BASENOT;
				this->N3() = -1; }
			else
			{	this->N1() = num2.N1();
				this->N2() = num2.N2();
				this->N3() = num2.N3(); } }

// --- XOR ^=

	// this ^= num
	inline void Xor(const QUADSINT& num)
		{ QUADUINT::Xor(*(const QUADUINT*)&num); }

	// this ^= s:num
	inline void Xor(const DBLSINT& num)
		{	this->N0() ^= num.N0();
			this->N1() ^= (BASEUINT)num.N1();
			if (num.IsNeg())
			{	this->N2() = ~this->N2();
				this->N3() = ~this->N3(); } }

	// this ^= s:s:s:num
	inline void Xor(BASESINT num)
		{	this->N0() ^= (BASEUINT)num;
			if (num < 0)
			{	this->N1() = ~this->N1();
				this->N2() = ~this->N2();
				this->N3() = ~this->N3(); } }

// --- XOR ^

	// this = num1 ^ num2
	inline void Xor(const QUADSINT& num1, const QUADSINT& num2)
		{ QUADUINT::Xor(*(const QUADUINT*)&num1, *(const QUADUINT*)&num2); }

	// this = num1 ^ s:num2
	inline void Xor(const QUADSINT& num1, const DBLSINT& num2)
		{	this->N0() = num1.N0() ^ num2.N0();
			this->N1() = num1.N1() ^ (BASEUINT)num2.N1();
			if (num2.IsNeg())
			{	this->N2() = ~num1.N2();
				this->N3() = ~num1.N3(); }
			else
			{	this->N2() = num1.N2();
				this->N3() = num1.N3(); } }

	// this = s:num1 ^ num2
	inline void Xor(const DBLSINT& num1, const QUADSINT& num2)
		{	this->N0() = num1.N0() ^ num2.N0();
			this->N1() = (BASEUINT)num1.N1() ^ num2.N1();
			if (num1.IsNeg())
			{	this->N2() = ~num2.N2();
				this->N3() = ~num2.N3(); }
			else
			{	this->N2() = num2.N2();
				this->N3() = num2.N3(); } }

	// this = num1 ^ s:s:s:num2
	inline void Xor(const QUADSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() ^ (BASEUINT)num2;
			if (num2 < 0)
			{	this->N1() = ~num1.N1();
				this->N2() = ~num1.N2();
				this->N3() = ~num1.N3(); }
			else
			{	this->N1() = num1.N1();
				this->N2() = num1.N2();
				this->N3() = num1.N3(); } }

	// this = s:s:s:num1 ^ num2
	inline void Xor(BASESINT num1, const QUADSINT& num2)
		{	this->N0() = num2.N0() ^ (BASEUINT)num1;
			if (num1 < 0)
			{	this->N1() = ~num2.N1();
				this->N2() = ~num2.N2();
				this->N3() = ~num2.N3(); }
			else
			{	this->N1() = num2.N1();
				this->N2() = num2.N2();
				this->N3() = num2.N3(); } }

// --- set/clear/get bit

	// set bit
	inline void SetBit(int bit)
		{ QUADUINT::SetBit(bit); }

	// reset bit
	inline void ResBit(int bit)
		{ QUADUINT::ResBit(bit); }

	// flip bit
	inline void FlipBit(int bit)
		{ QUADUINT::FlipBit(bit); }

	// get bit (returns 0 or 1)
	inline int GetBit(int bit) const
		{ return QUADUINT::GetBit(bit); }

	// get number of valid bits of absolute value (=logarithm+1, returns position of highest bit + 1, 0..4*BASEBITS)
	int Bits() const;

	// check if absolute value of number is power of 2 (use Bits()-1 to determine 2nd logarithm)
	bool IsPwr2() const;

// --- LShift <<=

	// this <<= 1
	inline void LShift1()
		{ QUADUINT::LShift1(); }

	// this <<= shift
	void LShift(int shift);

// --- LShift <<

	// this = num << 1
	inline void LShift1(const QUADSINT& num)
		{ QUADUINT::LShift1(*(const QUADUINT*)&num); }

	// this = num << shift
	void LShift(const QUADSINT& num, int shift);

	// this = s:s:s:num << 1
	void LShift1(BASESINT num);

	// this = s:s:s:num << shift
	void LShift(BASESINT num, int shift);

// --- RShift >>=

	// this >>= 1
	void RShift1();

	// this >>= shift
	void RShift(int shift);

// --- RShift >>

	// this = num >> 1
	void RShift1(const QUADSINT& num);

	// this = num >> shift
	void RShift(const QUADSINT& num, int shift);

	// this = s:s:s:num >> 1
	void RShift1(BASESINT num);

	// this = s:s:s:num >> shift
	void RShift(BASESINT num, int shift);

// --- text conversion

	// convert to ASCIIZ text into buffer of size approx. 1 + 2.41*size in bytes
	// (uint256: 78+1, uint128: 39+1, uin64: 20+1, uint32: 10+1), returns number of digits
	// sign = convert number as signed, with extra '-' character (reserve one more place in buffer)
	inline int ToTextBuf(char* buf, int bufsize, bool sign = true) const
		{ return QUADUINT::ToTextBuf(buf, bufsize, sign); }

	inline CText ToText(bool sign = true) const
		{ return QUADUINT::ToText(sign); }

	// convert number from text (len=text length, -1=unlimited or terminated by 0, returns number of processed characters)
	inline int FromTextBuf(const char* text, int len = -1)
		{ return QUADUINT::FromTextBuf(text, len); }

	// convert number from text (returns new position)
	inline int FromText(const CText& text, int pos = 0)
		{ return QUADUINT::FromText(text, pos); }

// --- functions

	// integer square root with optional remainder, this = sqrt(num)
	inline void Sqrt(const QUADSINT& num, QUADSINT* rem = NULL)
		{	if (num.IsNotNeg())
				QUADUINT::Sqrt(*(const QUADUINT*)&num, (QUADUINT*)rem);
			else
				this->Set0(); }
	inline void Sqrt() { this->Sqrt(*this, NULL); }

// --- "in class" operators

	// =
	inline QUADSINT& operator= (const QUADSINT& num)
		{ this->Set(num); return *this; }

	inline QUADSINT& operator= (const DBLSINT& num)
		{ this->Set(num); return *this; }

	inline QUADSINT& operator= (BASESINT num)
		{ this->Set(num); return *this; }

	// +=
	inline QUADSINT& operator+= (const QUADSINT& num)
		{ this->Add(num); return *this; }

	inline QUADSINT& operator+= (const DBLSINT& num)
		{ this->Add(num); return *this; }

	inline QUADSINT& operator+= (BASESINT num)
		{ this->Add(num); return *this; }

	// -=
	inline QUADSINT& operator-= (const QUADSINT& num)
		{ this->Sub(num); return *this; }

	inline QUADSINT& operator-= (const DBLSINT& num)
		{ this->Sub(num); return *this; }

	inline QUADSINT& operator-= (BASESINT num)
		{ this->Sub(num); return *this; }

	// ++
	inline QUADSINT& operator++ () // prefix
		{ this->Inc(); return *this; }

	inline QUADSINT operator++ (int)// postfix
		{ QUADSINT num(*this); this->Inc(); return num; }

	// --
	inline QUADSINT& operator-- () // prefix
		{ this->Dec(); return *this; }

	inline QUADSINT operator-- (int) // postfix
		{ QUADSINT num(*this); this->Dec(); return num; }

	// -
	inline QUADSINT operator- () const // prefix
		{ QUADSINT num; num.Neg(*this); return num; }

	// *=
	inline QUADSINT& operator*= (const QUADSINT& num)
		{ this->Mul(num); return *this; }

	inline QUADSINT& operator*= (const DBLSINT& num)
		{ this->Mul(num); return *this; }

	inline QUADSINT& operator*= (BASESINT num)
		{ this->Mul(num); return *this; }

	// /=
	inline QUADSINT& operator/= (const QUADSINT& num)
		{ this->Div(num); return *this; }

	inline QUADSINT& operator/= (const DBLSINT& num)
		{ this->Div(num); return *this; }

	inline QUADSINT& operator/= (BASESINT num)
		{ this->Div(num); return *this; }

	// %=
	inline QUADSINT& operator%= (const QUADSINT& num)
		{ this->Mod(num); return *this; }

	inline QUADSINT& operator%= (const DBLSINT& num)
		{ this->Mod(num); return *this; }

	inline QUADSINT& operator%= (BASESINT num)
		{ this->Mod(num); return *this; }

	// ~
	inline QUADSINT operator~ () const // prefix
		{ QUADSINT num; num.Not(*this); return num; }

	// &=
	inline QUADSINT& operator&= (const QUADSINT& num)
		{ this->And(num); return *this; }

	inline QUADSINT& operator&= (const DBLSINT& num)
		{ this->And(num); return *this; }

	inline QUADSINT& operator&= (BASESINT num)
		{ this->And(num); return *this; }

	// |=
	inline QUADSINT& operator|= (const QUADSINT& num)
		{ this->Or(num); return *this; }

	inline QUADSINT& operator|= (const DBLSINT& num)
		{ this->Or(num); return *this; }

	inline QUADSINT& operator|= (BASESINT num)
		{ this->Or(num); return *this; }

	// ^=
	inline QUADSINT& operator^= (const QUADSINT& num)
		{ this->Xor(num); return *this; }

	inline QUADSINT& operator^= (const DBLSINT& num)
		{ this->Xor(num); return *this; }

	inline QUADSINT& operator^= (BASESINT num)
		{ this->Xor(num); return *this; }

	// <<=
	inline QUADSINT& operator<<= (int shift)
		{ this->LShift(shift); return *this; }

	// >>=
	inline QUADSINT& operator>>= (int shift)
		{ this->RShift(shift); return *this; }
};

// +
inline QUADSINT operator+ (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Add(num1, num2); return num; }

inline QUADSINT operator+ (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Add(num1, num2); return num; }

inline QUADSINT operator+ (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Add(num1, num2); return num; }

inline QUADSINT operator+ (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Add(num1, num2); return num; }

inline QUADSINT operator+ (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.Add(num1, num2); return num; }

// -
inline QUADSINT operator- (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Sub(num1, num2); return num; }

inline QUADSINT operator- (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Sub(num1, num2); return num; }

inline QUADSINT operator- (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Sub(num1, num2); return num; }

inline QUADSINT operator- (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Sub(num1, num2); return num; }

inline QUADSINT operator- (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.Sub(num1, num2); return num; }

// *
inline QUADSINT operator* (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Mul(num1, num2); return num; }

inline QUADSINT operator* (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Mul(num1, num2); return num; }

inline QUADSINT operator* (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Mul(num1, num2); return num; }

inline QUADSINT operator* (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Mul(num1, num2); return num; }

inline QUADSINT operator* (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.Mul(num1, num2); return num; }

// /
inline QUADSINT operator/ (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Div(num1, num2); return num; }

inline QUADSINT operator/ (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Div(num1, num2); return num; }

inline QUADSINT operator/ (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Div(num1, num2); return num; }

inline QUADSINT operator/ (const QUADSINT& num1, HALFSINT num2)
	{ QUADSINT num; num.Div(num1, num2); return num; }

// %
inline QUADSINT operator% (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Mod(num1, num2); return num; }

inline QUADSINT operator% (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Mod(num1, num2); return num; }

inline QUADSINT operator% (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Mod(num1, num2); return num; }

inline QUADSINT operator% (const QUADSINT& num1, HALFSINT num2)
	{ QUADSINT num; num.Mod(num1, num2); return num; }

// ==
inline bool operator== (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.Equ(num1); }

inline bool operator== (const QUADSINT& num1, BASESINT num2)
	{ return num1.Equ(num2); }

inline bool operator== (BASESINT num1, const QUADSINT& num2)
	{ return num2.Equ(num1); }

// !=
inline bool operator!= (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.NEqu(num1); }

inline bool operator!= (const QUADSINT& num1, BASESINT num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (BASESINT num1, const QUADSINT& num2)
	{ return num2.NEqu(num1); }

// <
inline bool operator< (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.Less(num2); }

inline bool operator< (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.Less(num2); }

inline bool operator< (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.Greater(num1); }

inline bool operator< (const QUADSINT& num1, BASESINT num2)
	{ return num1.Less(num2); }

inline bool operator< (BASESINT num1, const QUADSINT& num2)
	{ return num2.Greater(num1); }

// <=
inline bool operator<= (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.GreaterEqu(num1); }

inline bool operator<= (const QUADSINT& num1, BASESINT num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (BASESINT num1, const QUADSINT& num2)
	{ return num2.GreaterEqu(num1); }

// >
inline bool operator> (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.Less(num1); }

inline bool operator> (const QUADSINT& num1, BASESINT num2)
	{ return num1.Greater(num2); }

inline bool operator> (BASESINT num1, const QUADSINT& num2)
	{ return num2.Less(num1); }

// >=
inline bool operator>= (const QUADSINT& num1, const QUADSINT& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const QUADSINT& num1, const DBLSINT& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const DBLSINT& num1, const QUADSINT& num2)
	{ return num2.LessEqu(num1); }

inline bool operator>= (const QUADSINT& num1, BASESINT num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (BASESINT num1, const QUADSINT& num2)
	{ return num2.LessEqu(num1); }

// &
inline QUADSINT operator& (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.And(num1, num2); return num; }

inline QUADSINT operator& (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.And(num1, num2); return num; }

inline QUADSINT operator& (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.And(num1, num2); return num; }

inline QUADSINT operator& (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.And(num1, num2); return num; }

inline QUADSINT operator& (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.And(num1, num2); return num; }

// |
inline QUADSINT operator| (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Or(num1, num2); return num; }

inline QUADSINT operator| (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Or(num1, num2); return num; }

inline QUADSINT operator| (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Or(num1, num2); return num; }

inline QUADSINT operator| (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Or(num1, num2); return num; }

inline QUADSINT operator| (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.Or(num1, num2); return num; }

// ^
inline QUADSINT operator^ (const QUADSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Xor(num1, num2); return num; }

inline QUADSINT operator^ (const QUADSINT& num1, const DBLSINT& num2)
	{ QUADSINT num; num.Xor(num1, num2); return num; }

inline QUADSINT operator^ (const DBLSINT& num1, const QUADSINT& num2)
	{ QUADSINT num; num.Xor(num1, num2); return num; }

inline QUADSINT operator^ (const QUADSINT& num1, BASESINT num2)
	{ QUADSINT num; num.Xor(num1, num2); return num; }

inline QUADSINT operator^ (BASESINT num1, const QUADSINT& num2)
	{ QUADSINT num; num.Xor(num1, num2); return num; }

// <<
inline QUADSINT operator<< (const QUADSINT& num, int shift)
	{ QUADSINT n; n.LShift(num, shift); return n; }

// >>
inline QUADSINT operator>> (const QUADSINT& num, int shift)
	{ QUADSINT n; n.RShift(num, shift); return n; }

class DBLFIX;

// quadruple integer signed
class QUADFIX : protected QUADSINT
{
protected:

	// factorial table
	static QUADFIX* Fact_;
	static QUADFIX* FactRec_;

	// initialize factorial table
	static bool FactOK;
	static bool FactInit();

	// this = arctan(num), result in radians
	void ATan0(const QUADFIX& num, bool cotg);

	// this = arcsin(num), input -1..+1, result in radians
	void ASin0(const QUADFIX& num, bool arccos);

public:

	// max. factorial
	static BASEUINT FactMax;

// --- static constants

	// Euler's constant
	static QUADFIX Eul;
	static CText EulTxt;

	// Euler's constant ^2
	static QUADFIX Eul2;
	static CText Eul2Txt;

	// Euler's constant ^4
	static QUADFIX Eul4;
	static CText Eul4Txt;

	// Euler's constant ^8
	static QUADFIX Eul8;
	static CText Eul8Txt;

	// 1/Euler's constant
	static QUADFIX Eul1;
	static CText Eul1Txt;

	// 1/Euler's constant ^2
	static QUADFIX Eul12;
	static CText Eul12Txt;

	// 1/Euler's constant ^4
	static QUADFIX Eul14;
	static CText Eul14Txt;

	// 1/Euler's constant ^8
	static QUADFIX Eul18;
	static CText Eul18Txt;

	// Pi constant
	static QUADFIX Pi;
	static CText PiTxt;

	// Pi*2 constant
	static QUADFIX Pi2;
	static CText Pi2Txt;

	// Pi/2 constant
	static QUADFIX Pi12;
	static CText Pi12Txt;

	// Pi/4 constant
	static QUADFIX Pi14;
	static CText Pi14Txt;

	// Pi/180 constant
	static QUADFIX Pi180;
	static CText Pi180Txt;

	// 180/Pi constant
	static QUADFIX Pi180R;
	static CText Pi180RTxt;

	// ln(10) constant
	static QUADFIX Ln10;
	static CText Ln10Txt;

	// 1/ln(10) constant
	static QUADFIX Ln110;
	static CText Ln110Txt;

	// ln(2) constant
	static QUADFIX Ln2;
	static CText Ln2Txt;

	// 16*ln(2) constant
	static QUADFIX Ln2_16;
	static CText Ln2_16Txt;

	// sqrt(2) constant
	static QUADFIX Sqrt2;
	static CText Sqrt2Txt;

	// 1/sqrt(2) constant
	static QUADFIX Sqrt12;
	static CText Sqrt12Txt;

	// initialize static constants
	static bool InitOK;
	static bool ConstInit();

// --- constructor

	inline QUADFIX() {}

	inline QUADFIX(const QUADFIX& num)
		{ this->Set(num); }

	inline QUADFIX(const DBLFIX& num)
		{ this->Set(num); }

	inline QUADFIX(const DBLSINT& num)
		{ this->Set(num); }

	inline QUADFIX(BASESINT num)
		{ this->Set(num); }

	inline QUADFIX(double num)
		{ this->Set(num); }

	inline QUADFIX(float num)
		{ this->Set(num); }

// --- access to value

	// lower half (fractional)
	inline BASEUINT& N0() { return m_N[0]; }
	inline BASEUINT& N1() { return m_N[1]; }

	inline const BASEUINT& N0() const { return m_N[0]; }
	inline const BASEUINT& N1() const { return m_N[1]; }

	// upper half (integer)
	inline BASEUINT& N2() { return m_N[2]; }
	inline BASESINT& N3() { return *(BASESINT*)&m_N[3]; }

	inline const BASEUINT& N2() const { return m_N[2]; }
	inline const BASESINT& N3() const { return *(const BASESINT*)&m_N[3]; }

	// check if number is negative
	inline bool IsNeg() const { return QUADSINT::IsNeg(); }
	inline bool IsNotNeg() const { return QUADSINT::IsNotNeg(); }

	// export to double number
	double Double();

	// export to float number
	float Float();

	// export to integer (round down)
	s64 Integer() { return (s64)this->N3()*BASELAST*2 + this->N2(); }

	inline void Integer(DBLSINT* num)
		{	num->N0() = this->N2();
			num->N1() = this->N3(); }

// --- SET =

	// this = 0
	inline void Set0() { QUADSINT::Set0(); }

	// this = 1
	inline void Set1()
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = 1;
			this->N3() = 0; }

	// this = all '1'
	inline void SetAll() { QUADSINT::SetAll(); }

	// this = -1
	inline void SetM1()
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = BASENOT;
			this->N3() = BASENOT; }

	// this = max (max. positive value)
	inline void SetMax() { QUADSINT::SetMax(); }

	// this = -min (min. negative value)
	//  be aware - negation of this number will stay negative
	inline void SetMin() { QUADSINT::SetMin(); }

	// this = num
	inline void Set(const QUADFIX& num) { QUADSINT::Set(*(const QUADSINT*)&num); }

	// this = dblfix
	void Set(const DBLFIX& num);

	// this = quadsint
	inline void Set(const QUADSINT& num)
		{	this->N3() = num.N1();
			this->N2() = num.N0();
			this->N1() = 0;
			this->N0() = 0; }

	// this = s:num (signed)
	inline void Set(const DBLSINT& num)
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = num.N0();
			this->N3() = num.N1(); }

	// this = s:s:s:num (signed)
	inline void Set(BASESINT num)
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = num;
			this->N3() = (num < 0) ? -1 : 0; }

	// this = s:s:s:s:s:s:s:num (signed)
	inline void Set(HALFSINT num)
		{ this->Set((BASESINT)num); }

	// this = num3:num2:num1:num0
	inline void Set(BASEUINT num0, BASEUINT num1, BASEUINT num2, BASESINT num3)
		{ QUADSINT::Set(num0, num1, num2, (BASEUINT)num3); }

	// factorial this = num!
	void Fact(BASEUINT num);
	void Fact();

	// reciprocal factorial this = 1/num!
	void FactRec(BASEUINT num);
	void FactRec();

	// exchange two numbers
	inline void Exchange(QUADFIX& num) { QUADSINT::Exchange(*(QUADSINT*)&num); }

	// this = double
	void Set(double num);

	// this = double, with modulo overflow
	void SetMod(double num);

	// this = float
	inline void Set(float num)
		{ this->Set((double)num); }

// --- round

	// round to integer towards down
	inline void Floor()
		{	this->N0() = 0;
			this->N1() = 0; }

	inline void Floor(const QUADFIX& num)
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = num.N2();
			this->N3() = num.N3(); }

	// round to integer towards up
	inline void Ceil()
		{	if ((this->N0() != 0) || (this->N1() != 0))
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	inline void Ceil(const QUADFIX& num)
		{	this->N2() = num.N2();
			this->N3() = num.N3();			
			if ((num.N0() != 0) || (num.N1() != 0))
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	// round to integer towards nearest
	inline void Round()
		{	if (this->N1() >= BASELAST)
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	inline void Round(const QUADFIX& num)
		{	this->N2() = num.N2();
			this->N3() = num.N3();			
			if (num.N1() >= BASELAST)
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	// cut integer part (round to integer towards zero)
	inline void Int()
		{	if (this->IsNeg() && ((this->N0() != 0) || (this->N1() != 0)))
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	inline void Int(const QUADFIX& num)
		{	this->N2() = num.N2();
			this->N3() = num.N3();			
			if (num.IsNeg() && ((num.N0() != 0) || (num.N1() != 0)))
			{
				this->N2()++;
				if (this->N2() == 0) this->N3()++;
			}
			this->N0() = 0;
			this->N1() = 0; }

	// cut fractional part
	inline void Fract()
		{	BASEUINT k = this->IsNeg() ? -1 : 0;
			this->N2() = k;
			this->N3() = k; }

	inline void Fract(const QUADFIX& num)
		{	BASEUINT k = num.IsNeg() ? -1 : 0;
			this->N2() = k;
			this->N3() = k;
			this->N0() = num.N0();
			this->N1() = num.N1(); }

// --- ADD +=

	// this += num
	inline void Add(const QUADFIX& num) { QUADSINT::Add(*(const QUADSINT*)&num); }

	// this += s:num (signed)
	inline void Add(const DBLFIX& num)
		{	QUADFIX n;
			n.Set(num);
			this->Add(n); }

	// this += s:s:s:num (signed)
	inline void Add(BASESINT num)
		{	QUADFIX n;
			n.Set(num);
			this->Add(n); }

	// this += double
	inline void Add(double num)
		{	QUADFIX n;
			n.Set(num);
			this->Add(n); }

// --- ADD +

	// this = num1 + num2
	inline void Add(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT::Add(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2); }

	// this = num1 + s:num2 (signed)
	inline void Add(const QUADFIX& num1, const DBLFIX& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Add(num1, n); }

	// this = s:num1 + num2 (signed)
	inline void Add(const DBLFIX& num1, const QUADFIX& num2)
		{ this->Add(num2, num1); }

	// this = num1 + s:s:s:num2 (signed)
	inline void Add(const QUADFIX& num1, BASESINT num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Add(num1, n); }

	// this = s:s:s:num1 + num2 (signed)
	inline void Add(BASESINT num1, const QUADFIX& num2)
		{ this->Add(num2, num1); }

	// this = num1 + double
	inline void Add(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Add(num1, n); }

	// this = double + num2
	inline void Add(double num1, const QUADFIX& num2)
		{ this->Add(num2, num1); }

// --- SUB -=

	// this -= num
	inline void Sub(const QUADFIX& num) { QUADSINT::Sub(*(const QUADSINT*)&num); }

	// this -= s:num (signed)
	inline void Sub(const DBLFIX& num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n); }

	// this -= s:s:s:num (signed)
	inline void Sub(BASESINT num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n); }

	// this -= double
	inline void Sub(double num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n); }

// --- SUB -

	// this = num1 - num2
	inline void Sub(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT::Sub(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2); }

	// this = num1 - s:num2 (signed)
	inline void Sub(const QUADFIX& num1, const DBLFIX& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Sub(num1, n); }

	// this = s:num1 - num2
	inline void Sub(const DBLFIX& num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Sub(n, num2); }

	// this = num1 - s:s:s:num2 (signed)
	inline void Sub(const QUADFIX& num1, BASESINT num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Sub(num1, n); }

	// this = s:s:s:num1 - num2 (signed)
	inline void Sub(BASESINT num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Sub(n, num2); }

	// this = num1 - double
	inline void Sub(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Sub(num1, n); }

	// this = double - num2 (signed)
	inline void Sub(double num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Sub(n, num2); }

// --- INV SUB =-

	// this = num - this
	inline void InvSub(const QUADFIX& num)
		{ QUADSINT::InvSub(*(const QUADSINT*)&num); }

	// this = s:num - this (signed)
	inline void InvSub(const DBLFIX& num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n, *this); }

	// this = s:s:s:num - this (signed)
	inline void InvSub(BASESINT num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n, *this); }

	// this = double - this
	inline void InvSub(double num)
		{	QUADFIX n;
			n.Set(num);
			this->Sub(n, *this); }

// --- increment ++

	// this++
	inline void Inc()
		{	BASEUINT r = this->N2() + 1;
			this->N2() = r;
			if (r == 0) this->N3()++; }

	// this = num + 1
	inline void Inc(const QUADFIX& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1();
			BASEUINT r = num.N2() + 1;
			this->N2() = r;
			this->N3() = num.N3() + ((r == 0) ? 1 : 0); }

// --- decrement --

	// this--
	inline void Dec()
		{	BASEUINT r = this->N2();
			if (r == 0) this->N3()--;
			this->N2() = r - 1; }

	// this = num - 1
	inline void Dec(const QUADFIX& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1();
			BASEUINT r = num.N2();
			this->N3() = num.N3() - ((r == 0) ? 1 : 0);
			this->N2() = r - 1; }

// --- MUL *= (signed)

	// this *= num
	inline void Mul(const QUADFIX& num)
		{ this->Mul(*this, num); }

	// this *= quadsint
	inline void Mul(const QUADSINT& num)
		{ this->Mul(*this, num); }

	// this *= s:num
	inline void Mul(const DBLFIX& num)
		{ this->Mul(*this, num); }

	// this *= s:s:s:num
	inline void Mul(BASESINT num)
		{ this->Mul(*this, num); }

	// this *= double
	inline void Mul(double num)
		{ this->Mul(*this, num); }

	// this *= 10, returns high carry (+-0..9)
	inline int Mul10()
		{ return this->Mul10(*this); }

// --- MUL * (signed)

	// this = num1 * num2
	void Mul(const QUADFIX& num1, const QUADFIX& num2);

	// this = num1 * quadsint
	inline void Mul(const QUADFIX& num1, const QUADSINT& num2)
		{ QUADSINT::Mul(*(const QUADSINT*)&num1, num2); }

	// this = quadsint * num2
	inline void Mul(const QUADSINT& num1, const QUADFIX& num2)
		{ QUADSINT::Mul(num1, *(const QUADSINT*)&num2); }

	// this = num1 * s:num2
	inline void Mul(const QUADFIX& num1, const DBLFIX& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mul(num1, n); }

	// this = s:num1 * num2
	inline void Mul(const DBLFIX& num1, const QUADFIX& num2)
		{ this->Mul(num2, num1); }

	// this = num1 * s:s:s:num2
	inline void Mul(const QUADFIX& num1, BASESINT num2)
		{ QUADSINT::Mul(*(const QUADSINT*)&num1, num2); }

	// this = s:s:s:num1 * num2
	inline void Mul(BASESINT num1, const QUADFIX& num2)
		{ this->Mul(num2, num1); }

	// this = s:num1 * s:num2
	void Mul(const DBLFIX& num1, const DBLFIX& num2);

	// this = s:num1 * s:s:s:num2
	inline void Mul(const DBLFIX& num1, BASESINT num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Mul(n, num2); }

	// this = s:s:s:num1 * s:num2
	inline void Mul(BASESINT num1, const DBLFIX& num2)
		{ this->Mul(num2, num1); }

	// this = s:s:s:num1 * s:s:s:num2
	inline void Mul(BASESINT num1, BASESINT num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Mul(n, num2); }

	// this = num1 * double
	inline void Mul(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mul(num1, n); }
			
	// this = double * num2
	inline void Mul(double num1, const QUADFIX& num2)
		{ this->Mul(num2, num1); }

	// high:this = num1 * num2, with full range of result
	// (high = destination of signed integer part of result,
	//  this = destination of fractional unsigned part)
	inline void MulHigh(const QUADFIX& num1, const QUADFIX& num2, QUADSINT* high)
		{ QUADSINT::MulHigh(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2, high); }

	// this = num * 10, returns high carry (+-0..9)
	inline int Mul10(const QUADFIX& num)
		{ return QUADSINT::Mul10(*(const QUADSINT*)&num); }

// --- SQR (signed)

	// this *= this
	inline void Sqr()
		{ this->Sqr(*this); }

	// this = num * num
	inline void Sqr(const QUADFIX& num)
		{ this->Mul(num, num); }

	// this = s:num * s:num
	inline void Sqr(const DBLFIX& num)
		{ this->Mul(num, num); }

	// this = s:s:s:num * s:s:s:num
	inline void Sqr(BASESINT num)
		{ this->Mul(num, num); }

// --- POW ^

	// this = pow(base, num), power base^num
	inline void Pow(const QUADFIX& base, const QUADFIX& num)
		{	QUADFIX n;
			n.Log(base);
			this->Mul(n, num);
			this->Exp(); }
	inline void Pow(const QUADFIX& num) { this->Pow(*this, num); }

// --- DIV /= (signed)

	// this = this / num
	inline void Div(const QUADFIX& num)
		{ this->Div(*this, num); }

	// this = this / quadsint
	inline void Div(const QUADSINT& num)
		{ this->Div(*this, num); }

	// this = this / s:num
	inline void Div(const DBLFIX& num)
		{ this->Div(*this, num); }

	// this = this / s:s:s:num
	inline void Div(BASESINT num)
		{ this->Div(*this, num); }

	// this = this / s:s:s:s:s:s:s:num
	inline void Div(HALFSINT num)
		{ this->Div(*this, num); }

	// this = this / double
	inline void Div(double num)
		{ this->Div(*this, num); }

	// this = num / this
	inline void InvDiv(const QUADFIX& num)
		{ this->Div(num, *this); }

	// this = double / this
	inline void InvDiv(double num)
		{ this->Div(num, *this); }

	// this = num / 10
	inline void Div10()
		{ this->Div10(*this); }

	// this = 1 / this (reciprocal value)
	inline void Recip()
		{	QUADFIX n;
			n.Set1();
			this->Div(n, *this); }

// --- DIV / (signed)

	// this = num1 / num2
	void Div(const QUADFIX& num1, const QUADFIX& num2);

	// this = num1 / quadsint
	inline void Div(const QUADFIX& num1, const QUADSINT& num2)
		{ QUADSINT::Div(*(const QUADSINT*)&num1, num2); }

	// this = num1 / s:num2
	inline void Div(const QUADFIX& num1, const DBLFIX& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Div(num1, n); }

	// this = num1 / s:s:s:num2
	inline void Div(const QUADFIX& num1, BASESINT num2)
		{ QUADSINT::Div(*(const QUADSINT*)&num1, num2); }

	// this = num1 / s:s:s:s:s:s:s:num2
	inline void Div(const QUADFIX& num1, HALFSINT num2)
		{ QUADSINT::Div(*(const QUADSINT*)&num1, num2); }

	// this = num1 / double
	inline void Div(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Div(num1, n); }

	// this = double / num2
	inline void Div(double num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Div(n, num2); }

	// this = num1H:num1L / num2, with full range of dividend
	inline void DivHigh(const QUADUINT& num1L, const QUADSINT& num1H, const QUADFIX& num2, QUADFIX* rem = NULL)
		{ QUADSINT::DivHigh(num1L, num1H, *(const QUADSINT*)&num2, (QUADSINT*)rem); }

	// this = num / 10
	inline void Div10(const QUADFIX& num)
		{ QUADSINT::Div10(*(const QUADSINT*)&num); }

	// this = 1 / num (reciprocal value)
	inline void Recip(const QUADFIX& num)
		{	QUADFIX n;
			n.Set1();
			this->Div(n, num); }

	// this = 1 / s:num (reciprocal value)
	inline void Recip(const DBLFIX& num)
		{	QUADFIX n;
			n.Set1();
			this->Div(n, num); }

	// this = 1 / s:s:s:num (reciprocal value)
	inline void Recip(BASESINT num)
		{	this->Set1();
			this->Div(num); }

	// this = 1 / double (reciprocal value)
	inline void Recip(double num)
		{	this->Set1();
			this->Div(num); }

// --- DIV INT / (integer division)

	// this = num1 / num2 (integer divide)
	inline void DivInt(const QUADFIX& num1, const QUADFIX& num2)
		{	QUADSINT::Div(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2);
			this->N3() = this->N1();
			this->N2() = this->N0();
			this->N1() = 0;
			this->N0() = 0; }

	// this = num1 / s:num2 (integer divide)
	inline void DivInt(const QUADFIX& num1, DBLFIX num2)
		{	QUADSINT::Div(*(const QUADSINT*)&num1, *(const DBLSINT*)&num2);
			this->N3() = this->N2();
			this->N2() = this->N1();
			this->N1() = 0;
			this->N0() = 0; }

	// this = num1 / s:s:s:num2 (integer divide)
	inline void DivInt(const QUADFIX& num1, BASESINT num2)
		{	QUADSINT::Div(*(const QUADSINT*)&num1, num2);
			this->N1() = 0;
			this->N0() = 0; }

	// this = num1 / s:s:s:s:s:s:s:num2 (integer divide)
	inline void DivInt(const QUADFIX& num1, HALFSINT num2)
		{	QUADSINT::Div(*(const QUADSINT*)&num1, num2);
			this->N1() = 0;
			this->N0() = 0; }

	// this = num1 / double (integer divide)
	inline void DivInt(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->DivInt(num1, n); }

	// this = double / num2 (integer divide)
	inline void DivInt(double num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->DivInt(n, num2); }

	// this = num / 10 (integer divide)
	inline void DivInt10(const QUADFIX& num)
		{ this->DivInt(num, (HALFSINT)10); }

// --- MOD %= (signed)
// remainder will have the same sign as dividend

	// this = this % num
	inline void Mod(const QUADFIX& num)
		{ this->Mod(*this, num); }

	// this = this % quadsint
	inline void Mod(const QUADSINT& num)
		{ this->Mod(*this, num); }

	// this = this % s:num
	inline void Mod(const DBLFIX& num)
		{ this->Mod(*this, num); }

	// this = this % s:s:s:num
	inline void Mod(BASESINT num)
		{ this->Mod(*this, num); }

	// this = this % s:s:s:s:s:s:s:num
	inline void Mod(HALFSINT num)
		{ this->Mod(*this, num); }

	// this = this % double
	inline void Mod(double num)
		{ this->Mod(*this, num); }

	// this = this % 10
	inline void Mod10()
		{ this->Mod10(*this); }

// --- MOD % (signed)
// remainder will have the same sign as dividend

	// this = num1 % num2
	inline void Mod(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT n; n.Div(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2, this); }

	// this = num1 % quadsint
	inline void Mod(const QUADFIX& num1, const QUADSINT& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mod(num1, n); }

	// this = num1 % s:num2
	inline void Mod(const QUADFIX& num1, const DBLFIX& num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mod(num1, n); }

	// this = num1 % s:s:s:num2
	inline void Mod(const QUADFIX& num1, BASESINT num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mod(num1, n); }

	// this = num1 % s:s:s:s:s:s:s:num2
	inline void Mod(const QUADFIX& num1, HALFSINT num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mod(num1, n); }

	// this = num1 % double
	inline void Mod(const QUADFIX& num1, double num2)
		{	QUADFIX n;
			n.Set(num2);
			this->Mod(num1, n); }

	// this = double % num2
	inline void Mod(double num1, const QUADFIX& num2)
		{	QUADFIX n;
			n.Set(num1);
			this->Mod(n, num2); }

	// this = num % 10
	inline void Mod10(const QUADFIX& num)
		{ this->Mod(num, (HALFSINT)10); }

// --- fast division (Division by invariant integers using multiplication by reciprocal value)

	// precalculate multiplier for fast division, returns flags FASTDIV_*
	// Divisor and "this" cannot be the same variables!
	inline int PreFastDiv(const QUADSINT& div)
		{ return QUADSINT::PreFastDiv(div); }

	// fast divide using precalculated multiplier with flags
	// Dividend "num" and "this" cannot be the same variables!
	inline void FastDiv(const QUADFIX& num, const QUADFIX& mul, int flags)
		{ QUADSINT::FastDiv(*(const QUADSINT*)&num, *(const QUADSINT*)&mul, flags); }

	// test fast division (res = num1/num2)
	// num1, num2 and "this" cannot be the same variables!
	inline void TestFastDiv(const QUADFIX& num1, const QUADSINT& num2)
		{	QUADFIX mul;
			int flags = mul.PreFastDiv(num2);
			this->FastDiv(num1, mul, flags); }

// --- EQU ==

	// this == 0
	inline bool Equ0() const
		{ return QUADSINT::Equ0(); }

	inline bool IsZero() const { return this->Equ0(); }
	
	// this == 1
	inline bool Equ1() const
		{ return (this->N0() == 0) &&
				(this->N1() == 0) &&
				(this->N2() == 1) &&
				(this->N3() == 0); }

	// this == all '1'
	inline bool EquAll() { return QUADSINT::EquAll(); }

	// this == -1
	inline bool EquM1()
		{ return (this->N0() == 0) &&
				(this->N1() == 0) &&
				(this->N2() == BASENOT) &&
				(this->N3() == BASENOT); }

	// this == max (max. positive value)
	inline bool EquMax() { return QUADSINT::EquMax(); }

	// this == -min (min. negative value)
	inline bool EquMin() { return QUADSINT::EquMin(); }

	// this == num
	inline bool Equ(const QUADFIX& num) const
		{ return QUADSINT::Equ(*(const QUADSINT*)&num); }

	// this == s:num
	inline bool Equ(const DBLFIX& num) const
		{	return (this->N0() == 0) &&
				(this->N1() == num.N0()) &&
				(this->N2() == (BASEUINT)num.N1()) &&
				(this->N3() == (num.IsNeg() ? -1 : 0)); }

	// this == s:s:s:num
	inline bool Equ(BASESINT num) const
		{	return (this->N0() == 0) &&
				(this->N1() == 0) &&
				(this->N2() == (BASEUINT)num) &&
				(this->N3() == ((num < 0) ? -1 : 0)); }

	// this == num, with difference
	inline bool EquEps(const QUADFIX& num, BASEUINT eps) const
		{	QUADFIX n;
			n.Sub(*this, num);
			n.Abs();
			return (n.N3() == 0) && (n.N2() == 0) && (n.N1() == 0) && (n.N0() <= eps); }	

// --- NEQU !=

	// this != 0
	inline bool NEqu0() const
		{ return QUADSINT::NEqu0(); }

	inline bool IsNotZero() const { return this->NEqu0(); }

	// this != 1
	inline bool NEqu1() const
		{ return (this->N0() != 0) ||
				(this->N1() != 0) ||
				(this->N2() != 1) ||
				(this->N3() != 0); }

	// this != all '1'
	inline bool NEquAll() { return QUADSINT::NEquAll(); }

	// this != -1
	inline bool NEquM1()
		{ return (this->N0() != 0) ||
				(this->N1() != 0) ||
				(this->N2() != BASENOT) ||
				(this->N3() != BASENOT); }

	// this != max (max. positive value)
	inline bool NEquMax() { return QUADSINT::NEquMax(); }

	// this != -min (min. negative value)
	inline bool NEquMin() { return QUADSINT::NEquMin(); }

	// this != num
	inline bool NEqu(const QUADFIX& num) const
		{ return QUADSINT::NEqu(*(const QUADSINT*)&num); }

	// this != s:num
	inline bool NEqu(const DBLFIX& num) const
		{	return (this->N0() != 0) ||
				(this->N1() != num.N0()) ||
				(this->N2() != (BASEUINT)num.N1()) ||
				(this->N3() != (num.IsNeg() ? -1 : 0)); }

	// this != s:s:s:num
	inline bool NEqu(BASESINT num) const
		{	return (this->N0() != 0) ||
				(this->N1() != 0) ||
				(this->N2() != (BASEUINT)num) ||
				(this->N3() != ((num < 0) ? -1 : 0)); }

	// this != num, with difference
	inline bool NEquEps(const QUADFIX& num, BASEUINT eps) const
		{	QUADFIX n;
			n.Sub(*this, num);
			n.Abs();
			return (n.N3() != 0) || (n.N2() != 0) || (n.N1() != 0) || (n.N0() > eps); }	

// --- LESS <

	// this < num
	inline bool Less(const QUADFIX& num) const
		{ return QUADSINT::Less(*(const QUADSINT*)&num); }

	// this < s:num
	inline bool Less(const DBLFIX& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)num.N1()) || ((this->N2() == (BASEUINT)num.N1()) &&
				(this->N1() < num.N0())))); }

	// this < s:s:s:num
	inline bool Less(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)num))); }

// --- LESS EQU <=

	// this <= num
	inline bool LessEqu(const QUADFIX& num) const
		{ return QUADSINT::LessEqu(*(const QUADSINT*)&num); }

	// this <= s:num
	inline bool LessEqu(const DBLFIX& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)num.N1()) || ((this->N2() == (BASEUINT)num.N1()) &&
				((this->N1() < num.N0()) || ((this->N1() == num.N0()) &&
				(this->N0() == 0)))))); }

	// this <= s:s:s:num
	inline bool LessEqu(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() < k) || ((this->N3() == k) &&
				((this->N2() < (BASEUINT)num) || ((this->N2() == (BASEUINT)num) &&
				((this->N1() == 0) && (this->N0() == 0))))); }

// --- GREATER >

	// this > num
	inline bool Greater(const QUADFIX& num) const
		{ return QUADSINT::Greater(*(const QUADSINT*)&num); }

	// this > s:num
	inline bool Greater(const DBLFIX& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)num.N1()) || ((this->N2() == (BASEUINT)num.N1()) &&
				((this->N1() > num.N0()) || ((this->N1() == num.N0()) &&
				(this->N0() > 0)))))); }

	// this > s:s:s:num
	inline bool Greater(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)num) || ((this->N2() == (BASEUINT)num) &&
				((this->N1() > 0) || ((this->N1() == 0) &&
				(this->N0() > 0)))))); }

// --- GREATER EQU >=

	// this >= num
	inline bool GreaterEqu(const QUADFIX& num) const
		{ return QUADSINT::GreaterEqu(*(const QUADSINT*)&num); }

	// this >= s:num
	inline bool GreaterEqu(const DBLFIX& num) const
		{	BASESINT k = num.IsNeg() ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)num.N1()) || ((this->N2() == (BASEUINT)num.N1()) &&
				((this->N1() > num.N0()) || ((this->N1() == num.N0()) &&
				(this->N0() >= 0)))))); }

	// this >= s:s:s:num
	inline bool GreaterEqu(BASESINT num) const
		{	BASESINT k = (num < 0) ? -1 : 0;
			return (this->N3() > k) || ((this->N3() == k) &&
				((this->N2() > (BASEUINT)num) || ((this->N2() == (BASEUINT)num) &&
				((this->N1() > 0) || ((this->N1() == 0) &&
				(this->N0() >= 0)))))); }

// --- NEG

	// this = -this
	inline void Neg()
		{ QUADSINT::Neg(); }

	// this = -num
	inline void Neg(const QUADFIX& num)
		{ QUADSINT::Neg(*(const QUADSINT*)&num); }

	// this = -s:num
	inline void Neg(const DBLFIX& num)
		{	this->Set(num);
			this->Neg(); }

	// this = -s:s:s:num
	inline void Neg(BASESINT num)
		{	this->Set(num);
			this->Neg(); }

// --- ABS

	// this = abs(this)
	inline void Abs()
		{ QUADSINT::Abs(); }

	// this = abs(num)
	inline void Abs(const QUADFIX& num)
		{ QUADSINT::Abs(*(const QUADSINT*)&num); }

	// this = abs(num)
	inline void Abs(const DBLFIX& num)
		{ if (num.IsNeg()) this->Neg(num); else this->Set(num); }

	// this = abs(s:num)
	inline void Abs(BASESINT num)
		{ if (num < 0) this->Neg(num); else this->Set(num); }

// --- NOT ~

	// this = ~this
	inline void Not()
		{ QUADSINT::Not(); }

	// this = ~num
	inline void Not(const QUADFIX& num)
		{ QUADSINT::Not(*(const QUADSINT*)&num); }

	// this = ~s:num
	inline void Not(DBLFIX num)
		{	this->N0() = BASENOT;
			this->N1() = ~num.N0();
			this->N2() = ~(BASEUINT)num.N1();
			this->N3() = num.IsNeg() ? 0 : -1; }

	// this = ~s:s:s:num
	inline void Not(BASESINT num)
		{	this->N0() = BASENOT;
			this->N1() = BASENOT;
			this->N2() = ~(BASEUINT)num;
			this->N3() = (num < 0) ? 0 : -1; }

// --- AND &=

	// this &= num
	inline void And(const QUADFIX& num)
		{ QUADSINT::And(*(const QUADSINT*)&num); }

	// this &= s:num
	inline void And(const DBLFIX& num)
		{	this->N0() = 0;
			this->N1() &= num.N0();
			this->N2() &= (BASEUINT)num.N1();
			if (num.IsNotNeg()) this->N3() = 0; }

	// this &= s:s:s:num
	inline void And(BASESINT num)
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() &= (BASEUINT)num;
			if (num >= 0) this->N3() = 0; }

// --- AND &

	// this = num1 & num2
	inline void And(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT::And(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2); }

	// this = num1 & s:num2
	inline void And(const QUADFIX& num1, const DBLFIX& num2)
		{	this->N0() = 0;
			this->N1() = num1.N1() & num2.N0();
			this->N2() = num1.N2() & (BASEUINT)num2.N1();
			if (num2.IsNeg())
				this->N3() = num1.N3();
			else
				this->N3() = 0; }

	// this = s:num1 & num2
	inline void And(const DBLFIX& num1, const QUADFIX& num2)
		{ this->And(num2, num1); }

	// this = num1 & s:s:s:num2
	inline void And(const QUADFIX& num1, BASESINT num2)
		{	this->N0() = 0;
			this->N1() = 0;
			this->N2() = num1.N2() & (BASEUINT)num2;
			if (num2 < 0)
				this->N3() = num1.N3();
			else
				this->N3() = 0; }

	// this = 0:0:0:num1 & num2
	inline void And(BASESINT num1, const QUADFIX& num2)
		{ this->And(num2, num1); }

// --- OR |=

	// this |= num
	inline void Or(const QUADFIX& num)
		{ QUADSINT::Or(*(const QUADSINT*)&num); }

	// this |= s:num
	inline void Or(const DBLFIX& num)
		{	this->N1() |= num.N0();
			this->N2() |= (BASEUINT)num.N1();
			if (num.IsNeg()) this->N3() = BASENOT; }

	// this |= s:s:s:num
	inline void Or(BASESINT num)
		{	this->N2() |= (BASEUINT)num;
			if (num < 0) this->N3() = -1; }

// --- OR |

	// this = num1 | num2
	inline void Or(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT::Or(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2); }

	// this = num1 | s:num2
	inline void Or(const QUADFIX& num1, const DBLFIX& num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1() | num2.N0();
			this->N2() = num1.N2() | (BASEUINT)num2.N1();
			if (num2.IsNeg())
				this->N3() = -1;
			else
				this->N3() = num1.N3(); }

	// this = s:num1 | num2
	inline void Or(const DBLFIX& num1, const QUADFIX& num2)
		{ this->Or(num2, num1); }

	// this = num1 | s:s:s:num2
	inline void Or(const QUADFIX& num1, BASESINT num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1();
			this->N2() = num1.N2() | (BASEUINT)num2;
			if (num2 < 0)
				this->N3() = -1;
			else
				this->N3() = num1.N3(); }

	// this = s:s:s:num1 | num2
	inline void Or(BASESINT num1, const QUADFIX& num2)
		{ this->Or(num2, num1); }

// --- XOR ^=

	// this ^= num
	inline void Xor(const QUADFIX& num)
		{ QUADSINT::Xor(*(const QUADSINT*)&num); }

	// this ^= s:num
	inline void Xor(const DBLFIX& num)
		{	this->N1() ^= num.N0();
			this->N2() ^= (BASEUINT)num.N1();
			if (num.IsNeg()) this->N3() = ~this->N3(); }

	// this ^= s:s:s:num
	inline void Xor(BASESINT num)
		{	this->N2() ^= (BASEUINT)num;
			if (num < 0) this->N3() = ~this->N3(); }

// --- XOR ^

	// this = num1 ^ num2
	inline void Xor(const QUADFIX& num1, const QUADFIX& num2)
		{ QUADSINT::Xor(*(const QUADSINT*)&num1, *(const QUADSINT*)&num2); }

	// this = num1 ^ s:num2
	inline void Xor(const QUADFIX& num1, const DBLFIX& num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1() ^ num2.N0();
			this->N2() = num1.N2() ^ (BASEUINT)num2.N1();
			if (num2.IsNeg())
				this->N3() = ~num1.N3();
			else
				this->N3() = num1.N3(); }

	// this = s:num1 ^ num2
	inline void Xor(const DBLFIX& num1, const QUADFIX& num2)
		{ this->Xor(num2, num1); }

	// this = num1 ^ s:s:s:num2
	inline void Xor(const QUADFIX& num1, BASESINT num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1();
			this->N2() = num1.N2() ^ (BASEUINT)num2;
			if (num2 < 0)
				this->N3() = ~num1.N3();
			else
				this->N3() = num1.N3(); }

	// this = s:s:s:num1 ^ num2
	inline void Xor(BASESINT num1, const QUADFIX& num2)
		{ this->Xor(num2, num1); }

// --- set/clear/get bit

	// set bit
	inline void SetBit(int bit)
		{ QUADSINT::SetBit(bit); }

	// reset bit
	inline void ResBit(int bit)
		{ QUADSINT::ResBit(bit); }

	// flip bit
	inline void FlipBit(int bit)
		{ QUADSINT::FlipBit(bit); }

	// get bit (returns 0 or 1)
	inline int GetBit(int bit) const
		{ return QUADSINT::GetBit(bit); }

	// get number of valid bits of absolute value (=logarithm+1, returns position of highest bit + 1, 0..4*BASEBITS)
	inline int Bits() const
		{ return QUADSINT::Bits(); }

	// check if absolute value of number is power of 2 (use Bits()-1 to determine 2nd logarithm)
	inline bool IsPwr2() const
		{ return QUADSINT::IsPwr2(); }

// --- LShift <<=

	// this <<= 1
	inline void LShift1()
		{ QUADSINT::LShift1(); }

	// this <<= shift
	inline void LShift(int shift)
		{ QUADSINT::LShift(shift); }

// --- LShift <<

	// this = num << 1
	inline void LShift1(const QUADFIX& num)
		{ QUADSINT::LShift1(*(const QUADSINT*)&num); }

	// this = num << shift
	inline void LShift(const QUADFIX& num, int shift)
		{ QUADSINT::LShift(*(const QUADSINT*)&num, shift); }

	// this = s:s:s:num << 1
	inline void LShift1(BASESINT num)
	{	this->N0() = 0;
		this->N1() = 0;
		this->N2() = num << 1;
		this->N3() = num >> (BASEBITS-1); }

	// this = s:s:s:num << shift
	inline void LShift(BASESINT num, int shift)
		{	this->Set(num);
			this->LShift(shift); }

// --- RShift >>=

	// this >>= 1
	inline void RShift1()
		{ QUADSINT::RShift1(); }

	// this >>= shift
	inline void RShift(int shift)
		{ QUADSINT::RShift(shift); }

// --- RShift >>

	// this = num >> 1
	inline void RShift1(const QUADFIX& num)
		{ QUADSINT::RShift1(*(const QUADSINT*)&num); }

	// this = num >> shift
	inline void RShift(const QUADFIX& num, int shift)
		{ QUADSINT::RShift(*(const QUADSINT*)&num, shift); }

	// this = s:s:s:num >> 1
	void RShift1(BASESINT num)
		{	this->Set(num);
			this->RShift1(); }

	// this = s:s:s:num >> shift
	void RShift(BASESINT num, int shift)
		{	this->Set(num);
			this->RShift(shift); }

// --- text conversion

	// convert to ASCIIZ text into buffer of size approx. 3 + 2.41*size in bytes
	// (fix256: 1+38+1+39+1=80, fix128: 1+19+1+20+1=43, fix64: 1+9+1+10+1=23, returns number of characters
	// dec = max. number of decimal places (max. QUADFIX_DEC+1)
	//   default precision: fix256: 38, fix128: 19, fix64: 9
	//   max. precision: fix256: 39, fix128: 20, fix64: 10 (last digit can be incorrect, previous one can be incorrectly rounded)
	int ToTextBuf(char* buf, int bufsize, int dec = QUADFIX_DEC) const;

	CText ToText(int dec = QUADFIX_DEC) const;

	// convert number from text (len=text length, -1=unlimited or terminated by 0, returns number of processed characters)
	int FromTextBuf(const char* text, int len = -1);

	// convert number from text (returns new position)
	int FromText(const CText& text, int pos = 0);

// --- functions

	// square root, this = sqrt(num)
	void Sqrt(const QUADFIX& num);
	inline void Sqrt() { this->Sqrt(*this); }

	// convert radians to degrees, this = num*180/Pi
	inline void RadDeg(const QUADFIX& num)
		{ this->Mul(num, QUADFIX::Pi180R); }
	inline void RadDeg()
		{ this->Mul(QUADFIX::Pi180R); }

	// convert degrees to radians, this = num*Pi/180
	inline void DegRad(const QUADFIX& num)
		{ this->Mul(num, QUADFIX::Pi180); }
	inline void DegRad()
		{ this->Mul(QUADFIX::Pi180); }

	// normalize angle in radians into range 0..Pi*2 (including 0, excluding Pi*2)
	void NormRad(const QUADFIX& num);
	inline void NormRad()
		{ this->NormRad(*this); }

	// normalize angle in degrees into range 0..360 (including 0, excluding 360)
	void NormDeg(const QUADFIX& num);
	inline void NormDeg()
		{ this->NormDeg(*this); }

	// this = sin(num), sine in radiands, result -1..+1
	void Sin(const QUADFIX& num);
	inline void Sin() { this->Sin(*this); }

	// this = arcsin(num), input -1..+1, result in radians
	inline void ASin(const QUADFIX& num) { this->ASin0(num, false); }
	inline void ASin() { this->ASin(*this); }

	// this = cos(num), cosine in radians, result -1..+1
	inline void Cos(const QUADFIX& num)
		{	this->Add(num, QUADFIX::Pi12);
			this->Sin(); }
	inline void Cos() { this->Cos(*this); }

	// this = arccos(num), input -1..+1, result in radians
	inline void ACos(const QUADFIX& num) { this->ASin0(num, true); }
	inline void ACos() { this->ACos(*this); }

	// this = tan(num), tangent in radians (tan = sin/cos)
	inline void Tan(const QUADFIX& num)
		{	QUADFIX s;
			s.Sin(num);
			this->Cos(num);
			this->Div(s, *this); }
	inline void Tan() { this->Tan(*this); }

	// this = arctan(num), result in radians
	inline void ATan(const QUADFIX& num)
		{ this->ATan0(num, false); }
	inline void ATan() { this->ATan(*this); }

	// this = cotan(num), cotangent in radians (cotan = cos/sin)
	inline void CoTan(const QUADFIX& num)
		{	QUADFIX s;
			s.Sin(num);
			this->Cos(num);
			this->Div(*this, s); }
	inline void CoTan() { this->CoTan(*this); }

	// this = arccotan(num), result in radians
	inline void ACoTan(const QUADFIX& num)
		{ this->ATan0(num, true); }
	inline void ACoTan() { this->ACoTan(*this); }

	// this = log(num), natural logarithm
	void Log(const QUADFIX& num);
	inline void Log() { this->Log(*this); }

	// this = log10(num), decadic logarithm
	inline void Log10(const QUADFIX& num)
		{	this->Log(num);
			this->Mul(QUADFIX::Ln110); }
	inline void Log10() { this->Log10(*this); }

	// this = exp(num), natural exponent
	void Exp(const QUADFIX& num);
	inline void Exp() { this->Exp(*this); }

	// this = exp10(num), decadic exponent
	inline void Exp10(const QUADFIX& num)
		{	this->Mul(QUADFIX::Ln10, num);
			this->Exp(); }
	inline void Exp10() { this->Exp10(*this); }

// --- "in class" operators

	// =
	inline QUADFIX& operator= (const QUADFIX& num)
		{ this->Set(num); return *this; }

	inline QUADFIX& operator= (const DBLFIX& num)
		{ this->Set(num); return *this; }

	inline QUADFIX& operator= (BASESINT num)
		{ this->Set(num); return *this; }

	inline QUADFIX& operator= (double num)
		{ this->Set(num); return *this; }

	inline QUADFIX& operator= (float num)
		{ this->Set(num); return *this; }

	// +=
	inline QUADFIX& operator+= (const QUADFIX& num)
		{ this->Add(num); return *this; }

	inline QUADFIX& operator+= (const DBLFIX& num)
		{ this->Add(num); return *this; }

	inline QUADFIX& operator+= (BASESINT num)
		{ this->Add(num); return *this; }

	inline QUADFIX& operator+= (double num)
		{ this->Add(num); return *this; }

	// -=
	inline QUADFIX& operator-= (const QUADFIX& num)
		{ this->Sub(num); return *this; }

	inline QUADFIX& operator-= (const DBLFIX& num)
		{ this->Sub(num); return *this; }

	inline QUADFIX& operator-= (BASESINT num)
		{ this->Sub(num); return *this; }

	inline QUADFIX& operator-= (double num)
		{ this->Sub(num); return *this; }

	// ++
	inline QUADFIX& operator++ () // prefix
		{ this->Inc(); return *this; }

	inline QUADFIX operator++ (int)// postfix
		{ QUADFIX num(*this); this->Inc(); return num; }

	// --
	inline QUADFIX& operator-- () // prefix
		{ this->Dec(); return *this; }

	inline QUADFIX operator-- (int) // postfix
		{ QUADFIX num(*this); this->Dec(); return num; }

	// -
	inline QUADFIX operator- () const // prefix
		{ QUADFIX num; num.Neg(*this); return num; }

	// *=
	inline QUADFIX& operator*= (const QUADFIX& num)
		{ this->Mul(num); return *this; }

	inline QUADFIX& operator*= (const DBLFIX& num)
		{ this->Mul(num); return *this; }

	inline QUADFIX& operator*= (BASESINT num)
		{ this->Mul(num); return *this; }

	inline QUADFIX& operator*= (double num)
		{ this->Mul(num); return *this; }

	// /=
	inline QUADFIX& operator/= (const QUADFIX& num)
		{ this->Div(num); return *this; }

	inline QUADFIX& operator/= (const DBLFIX& num)
		{ this->Div(num); return *this; }

	inline QUADFIX& operator/= (BASESINT num)
		{ this->Div(num); return *this; }

	inline QUADFIX& operator/= (double num)
		{ this->Div(num); return *this; }

	// %=
	inline QUADFIX& operator%= (const QUADFIX& num)
		{ this->Mod(num); return *this; }

	inline QUADFIX& operator%= (const DBLFIX& num)
		{ this->Mod(num); return *this; }

	inline QUADFIX& operator%= (BASESINT num)
		{ this->Mod(num); return *this; }

	inline QUADFIX& operator%= (double num)
		{ this->Mod(num); return *this; }

	// ~
	inline QUADFIX operator~ () const // prefix
		{ QUADFIX num; num.Not(*this); return num; }

	// &=
	inline QUADFIX& operator&= (const QUADFIX& num)
		{ this->And(num); return *this; }

	inline QUADFIX& operator&= (const DBLFIX& num)
		{ this->And(num); return *this; }

	inline QUADFIX& operator&= (BASESINT num)
		{ this->And(num); return *this; }

	// |=
	inline QUADFIX& operator|= (const QUADFIX& num)
		{ this->Or(num); return *this; }

	inline QUADFIX& operator|= (const DBLFIX& num)
		{ this->Or(num); return *this; }

	inline QUADFIX& operator|= (BASESINT num)
		{ this->Or(num); return *this; }

	// ^=
	inline QUADFIX& operator^= (const QUADFIX& num)
		{ this->Xor(num); return *this; }

	inline QUADFIX& operator^= (const DBLFIX& num)
		{ this->Xor(num); return *this; }

	inline QUADFIX& operator^= (BASESINT num)
		{ this->Xor(num); return *this; }

	// <<=
	inline QUADFIX& operator<<= (int shift)
		{ this->LShift(shift); return *this; }

	// >>=
	inline QUADFIX& operator>>= (int shift)
		{ this->RShift(shift); return *this; }
};

// +
inline QUADFIX operator+ (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (const QUADFIX& num1, double num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

inline QUADFIX operator+ (double num1, const QUADFIX& num2)
	{ QUADFIX num; num.Add(num1, num2); return num; }

// -
inline QUADFIX operator- (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (const QUADFIX& num1, double num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

inline QUADFIX operator- (double num1, const QUADFIX& num2)
	{ QUADFIX num; num.Sub(num1, num2); return num; }

// *
inline QUADFIX operator* (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (const QUADFIX& num1, double num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

inline QUADFIX operator* (double num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mul(num1, num2); return num; }

// /
inline QUADFIX operator/ (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

inline QUADFIX operator/ (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

inline QUADFIX operator/ (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

inline QUADFIX operator/ (const QUADFIX& num1, HALFSINT num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

inline QUADFIX operator/ (const QUADFIX& num1, double num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

inline QUADFIX operator/ (double num1, const QUADFIX& num2)
	{ QUADFIX num; num.Div(num1, num2); return num; }

// %
inline QUADFIX operator% (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

inline QUADFIX operator% (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

inline QUADFIX operator% (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

inline QUADFIX operator% (const QUADFIX& num1, HALFSINT num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

inline QUADFIX operator% (const QUADFIX& num1, double num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

inline QUADFIX operator% (double num1, const QUADFIX& num2)
	{ QUADFIX num; num.Mod(num1, num2); return num; }

// ==
inline bool operator== (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.Equ(num2); }

inline bool operator== (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.Equ(num1); }

inline bool operator== (const QUADFIX& num1, BASESINT num2)
	{ return num1.Equ(num2); }

inline bool operator== (BASESINT num1, const QUADFIX& num2)
	{ return num2.Equ(num1); }

// !=
inline bool operator!= (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.NEqu(num1); }

inline bool operator!= (const QUADFIX& num1, BASESINT num2)
	{ return num1.NEqu(num2); }

inline bool operator!= (BASESINT num1, const QUADFIX& num2)
	{ return num2.NEqu(num1); }

// <
inline bool operator< (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.Less(num2); }

inline bool operator< (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.Less(num2); }

inline bool operator< (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.Greater(num1); }

inline bool operator< (const QUADFIX& num1, BASESINT num2)
	{ return num1.Less(num2); }

inline bool operator< (BASESINT num1, const QUADFIX& num2)
	{ return num2.Greater(num1); }

// <=
inline bool operator<= (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.GreaterEqu(num1); }

inline bool operator<= (const QUADFIX& num1, BASESINT num2)
	{ return num1.LessEqu(num2); }

inline bool operator<= (BASESINT num1, const QUADFIX& num2)
	{ return num2.GreaterEqu(num1); }

// >
inline bool operator> (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.Greater(num2); }

inline bool operator> (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.Less(num1); }

inline bool operator> (const QUADFIX& num1, BASESINT num2)
	{ return num1.Greater(num2); }

inline bool operator> (BASESINT num1, const QUADFIX& num2)
	{ return num2.Less(num1); }

// >=
inline bool operator>= (const QUADFIX& num1, const QUADFIX& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const QUADFIX& num1, const DBLFIX& num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (const DBLFIX& num1, const QUADFIX& num2)
	{ return num2.LessEqu(num1); }

inline bool operator>= (const QUADFIX& num1, BASESINT num2)
	{ return num1.GreaterEqu(num2); }

inline bool operator>= (BASESINT num1, const QUADFIX& num2)
	{ return num2.LessEqu(num1); }

// &
inline QUADFIX operator& (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.And(num1, num2); return num; }

inline QUADFIX operator& (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.And(num1, num2); return num; }

inline QUADFIX operator& (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.And(num1, num2); return num; }

inline QUADFIX operator& (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.And(num1, num2); return num; }

inline QUADFIX operator& (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.And(num1, num2); return num; }

// |
inline QUADFIX operator| (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Or(num1, num2); return num; }

inline QUADFIX operator| (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Or(num1, num2); return num; }

inline QUADFIX operator| (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Or(num1, num2); return num; }

inline QUADFIX operator| (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Or(num1, num2); return num; }

inline QUADFIX operator| (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.Or(num1, num2); return num; }

// ^
inline QUADFIX operator^ (const QUADFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Xor(num1, num2); return num; }

inline QUADFIX operator^ (const QUADFIX& num1, const DBLFIX& num2)
	{ QUADFIX num; num.Xor(num1, num2); return num; }

inline QUADFIX operator^ (const DBLFIX& num1, const QUADFIX& num2)
	{ QUADFIX num; num.Xor(num1, num2); return num; }

inline QUADFIX operator^ (const QUADFIX& num1, BASESINT num2)
	{ QUADFIX num; num.Xor(num1, num2); return num; }

inline QUADFIX operator^ (BASESINT num1, const QUADFIX& num2)
	{ QUADFIX num; num.Xor(num1, num2); return num; }

// <<
inline QUADFIX operator<< (const QUADFIX& num, int shift)
	{ QUADFIX n; n.LShift(num, shift); return n; }

// >>
inline QUADFIX operator>> (const QUADFIX& num, int shift)
	{ QUADFIX n; n.RShift(num, shift); return n; }


#undef QUADUINT
#undef DBLUINT
#undef BASEUINT
#undef HALFUINT

#undef QUADSINT
#undef DBLSINT
#undef BASESINT
#undef HALFSINT

#undef QUADFIX
#undef DBLFIX

#undef USEASM

#undef BASEBITS
#undef BASELAST
#undef HALFBITS
#undef HALFMASK
#undef BASENOT

#undef QUADFIX_MAX
#undef QUADFIX_MIN
#undef QUADFIX_DEC
