
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                           Double Integer (uint128)                        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

/* 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 DBLUINT

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

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

#define DBLFIX dec128		// double fixed point class (signed)

#define USEASM				// can use assembler

#endif // DBLUINT


#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 DBLFIX_MAX ((double)(BASELAST-1) + (double)BASENOT/BASELAST/2) // max. decimal number as double
#define DBLFIX_MIN (-(double)BASELAST) // min. decimal number as double
#define DBLFIX_DEC ((int)(BASEBITS*0.301)) // default number of decimal places

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

class DBLSINT;

// double integer unsigned
class DBLUINT
{
protected:

	BASEUINT		m_N[2];		// 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);

	// factorial table
	static DBLUINT* Fact_;

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

public:

	// max. factorial
	static BASEUINT FactMax;

// --- constructor

	inline DBLUINT() {}

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

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

// --- access to value

	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]; }

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

// --- SET =

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

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

	// this = all bits '1'
	inline void SetAll()
		{	this->N0() = BASENOT;
			this->N1() = 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 DBLUINT& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1(); }

	inline void Set(const DBLSINT& num) { this->Set(*(const DBLUINT*)&num); }

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

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

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

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

// --- ADD +=

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

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

// --- ADD +

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

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

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

// --- SUB -=

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

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

// --- SUB -

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

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

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

// --- INV SUB =-

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

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

// --- increment ++

	// this++
	void Inc();

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

// --- decrement --

	// this--
	void Dec();

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

// --- MUL *= (unsigned)

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

	// this *= 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 * (unsigned)

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

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

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

	// this = 0:num1 * 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 DBLUINT& num1, const DBLUINT& num2, DBLUINT* high);

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

// --- SQR

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

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

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

// --- DIV /=

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

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

	// this = this / 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 DBLUINT& num, DBLUINT* 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 DBLUINT& num1, const DBLUINT& num2, DBLUINT* rem = NULL);

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

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

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

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

// --- MOD %=

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

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

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

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

// --- MOD %

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

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

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

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

	// this = num % 10
	inline void Mod10(const DBLUINT& 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 DBLUINT& div);

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

	// test fast division and remainder (res = num1/num2 + rem)
	// num1, num2 and "this" cannot be the same variables!
	inline void TestFastDiv(const DBLUINT& num1, const DBLUINT& num2, DBLUINT* rem = NULL)
		{	DBLUINT 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)
	// num1, num2 and "this" cannot be the same variables!
	inline void TestFastMod(const DBLUINT& num1, const DBLUINT& num2)
		{	DBLUINT 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); }

	inline bool IsZero() const { return this->Equ0(); }

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

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

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

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

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

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

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

// --- NEQU !=

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

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

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

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

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

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

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

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

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

// --- LESS <

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

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

// --- LESS EQU <=

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

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

// --- GREATER >

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

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

// --- GREATER EQU >=

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

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

// --- NEG

	// this = -this
	void Neg();

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

	// this = -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 DBLUINT& 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 = ~num
	inline void Not(const DBLUINT& num)
		{	this->N0() = ~num.N0();
			this->N1() = ~num.N1(); }

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

// --- AND &=

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

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

// --- AND &

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

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

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

// --- OR |=

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

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

// --- OR |

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

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

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

// --- XOR ^=

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

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

// --- XOR ^

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

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

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

// --- 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..2*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 DBLUINT& num);

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

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

	// this = 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 DBLUINT& num);

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

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

	// this = 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
	// (uint128: 40, uin64: 21, uint32: 11), 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 DBLUINT& num, DBLUINT* rem = NULL);
	inline void Sqrt() { this->Sqrt(*this, NULL); }

// --- "in class" operators

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


// double integer signed
class DBLSINT : protected DBLUINT
{
protected:

	// factorial table
	static DBLSINT* Fact_;

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

public:

	// max. factorial
	static BASEUINT FactMax;

// --- constructor

	inline DBLSINT() {}

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

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

// --- access to value

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

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

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

// --- SET =

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

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

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

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

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

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

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

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

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

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

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

// --- ADD +=

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

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

// --- ADD +

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

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

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

// --- SUB -=

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

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

// --- SUB -

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

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

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

// --- INV SUB =-

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

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

// --- increment ++

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

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

// --- decrement --

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

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

// --- MUL *= (signed)

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

	// this *= 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 DBLSINT& num1, const DBLSINT& num2);

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

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

	// this = s:num1 * 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 DBLSINT& num1, const DBLSINT& num2, DBLSINT* high);

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

// --- SQR (signed)

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

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

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

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

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

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

	// this = this / 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 DBLSINT& num, DBLSINT* 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 DBLSINT& num1, const DBLSINT& num2, DBLSINT* rem = NULL);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// this = num % 10
	inline void Mod10(const DBLSINT& num)
		{ this->Set((BASESINT)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 DBLSINT& div);

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

	// test fast division and remainder (res = num1/num2 + rem)
	// num1, num2 and "this" cannot be the same variables!
	inline void TestFastDiv(const DBLSINT& num1, const DBLSINT& num2, DBLSINT* rem = NULL)
		{	DBLSINT 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)
	// num1, num2 and "this" cannot be the same variables!
	inline void TestFastMod(const DBLSINT& num1, const DBLSINT& num2)
		{	DBLSINT mul;
			int flags = mul.PreFastDiv(num2);
			mul.FastDiv(num1, mul, flags);
			this->GetMod(num1, mul, num2); }

// --- EQU ==

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

	inline bool IsZero() const { return this->Equ0(); }

	// this == 1
	inline bool Equ1() const
		{ return DBLUINT::Equ1(); }

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

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

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

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

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

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

// --- NEQU !=

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

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

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

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

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

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

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

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

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

// --- LESS <

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

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

// --- LESS EQU <=

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

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

// --- GREATER >

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

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

// --- GREATER EQU >=

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

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

// --- NEG

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

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

	// this = -s:num
	void Neg(BASESINT num);

// --- ABS

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

	// this = abs(num)
	inline void Abs(const DBLSINT& num)
		{ DBLUINT::Abs(*(const DBLUINT*)&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()
		{ DBLUINT::Not(); }

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

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

// --- AND &=

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

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

// --- AND &

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

	// this = num1 & s:num2
	inline void And(const DBLSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() & (BASEUINT)num2;
			this->N1() = (num2 < 0) ? num1.N1() : 0; }

	// this = s:num1 & num2
	inline void And(BASESINT num1, const DBLSINT& num2)
		{	this->N0() = (BASEUINT)num1 & num2.N0();
			this->N1() = (num1 < 0) ? num2.N1() : 0; }

// --- OR |=

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

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

// --- OR |

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

	// this = num1 | s:num2
	inline void Or(const DBLSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() | (BASEUINT)num2;
			this->N1() = (num2 < 0) ? -1 : num1.N1(); }

	// this = s:num1 | num2
	inline void Or(BASESINT num1, const DBLSINT& num2)
		{	this->N0() = (BASEUINT)num1 | num2.N0();
			this->N1() = (num1 < 0) ? -1 : num2.N1(); }

// --- XOR ^=

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

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

// --- XOR ^

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

	// this = num1 ^ s:num2
	inline void Xor(const DBLSINT& num1, BASESINT num2)
		{	this->N0() = num1.N0() ^ num2;
			this->N1() = (num2 < 0) ? ~num1.N1() : num1.N1(); }

	// this = s:num1 ^ num2
	inline void Xor(BASESINT num1, const DBLSINT& num2)
		{	this->N0() = num1 ^ num2.N0();
			this->N1() = (num1 < 0) ? ~num2.N1() : num2.N1(); }

// --- set/clear/get bit

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

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

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

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

	// get number of valid bits of absolute value (=logarithm+1, returns position of highest bit + 1, 0..2*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()
		{ DBLUINT::LShift1(); }

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

// --- LShift <<

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

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

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

	// this = 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 DBLSINT& num);

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

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

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

// --- text conversion

	// convert to ASCIIZ text into buffer of size approx. 2 + 2.41*size in bytes
	// (uint128: 41, uin64: 22, uint32: 12), 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 DBLUINT::ToTextBuf(buf, bufsize, sign); }

	inline CText ToText(bool sign = true) const
		{ return DBLUINT::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 DBLUINT::FromTextBuf(text, len); }

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

// --- functions

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

// --- "in class" operators

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


// double fixed point (upper half is integer part, lower half is fractional part)
class DBLFIX : protected DBLSINT
{
protected:

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

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

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

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

public:

	// max. factorial
	static BASEUINT FactMax;

// --- static constants

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

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

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

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

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

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

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

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

	// Pi constant
	static DBLFIX Pi;
	static CText PiTxt;

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

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

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

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

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

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

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

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

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

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

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

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

// --- constructor

	inline DBLFIX() {}

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

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

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

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

// --- access to value

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

	// upper half (integer)
	inline BASESINT& N1() { return *(BASESINT*)&m_N[1]; }
	inline const BASESINT& N1() const { return *(const BASESINT*)&m_N[1]; }

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

	// export to double number
	double Double();

	// export to float number
	float Float();

	// export to integer (round down)
	BASESINT Integer() { return this->N1(); }

// --- SET =

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

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

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

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

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

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

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

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

	// this = num1:num0 (integer:fractional)
	inline void Set(BASEUINT num0, BASESINT num1) { DBLSINT::Set(num0, num1); }

	// factorial this = num!
	void Fact(BASEUINT num);
	inline void Fact()
		{	if (this->IsNotNeg())
				this->Fact(this->N1());
			else
				this->Set0(); }

	// reciprocal factorial this = 1/num!
	void FactRec(BASEUINT num);
	inline void FactRec()
		{	if (this->IsNotNeg())
				this->FactRec(this->N1());
			else
				this->SetMax(); }

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

	// this = double
	void Set(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; }

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

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

	inline void Ceil(const DBLFIX& num)
		{	this->N1() = (num.N0() != 0) ? (num.N1()+1) : num.N1();
			this->N0() = 0; }

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

	inline void Round(const DBLFIX& num)
		{	this->N1() = (num.N0() >= BASELAST) ? (num.N1()+1) : num.N1();
			this->N0() = 0; }

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

	inline void Int(const DBLFIX& num)
		{	this->N1() = (num.IsNeg() && (num.N0() != 0)) ? (num.N1()+1) : num.N1();
			this->N0() = 0; }

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

	inline void Fract(const DBLFIX& num)
		{	this->N1() = num.IsNeg() ? -1 : 0;
			this->N0() = num.N0(); }

// --- ADD +=

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

	// this += s:num (signed)
	inline void Add(BASESINT num)
		{ this->N1() += num; }

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

// --- ADD +

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

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

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

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

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

// --- SUB -=

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

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

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

// --- SUB -

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

	// this = num1 - s:num2 (signed)
	inline void Sub(const DBLFIX& num1, BASESINT num2)
	{	this->N0() = num1.N0();
		this->N1() = num1.N1() - num2; }

	// this = s:num1 - num2 (signed)
	inline void Sub(BASESINT num1, const DBLFIX& num2)
		{	DBLSINT::Neg(*(const DBLSINT*)&num2);
			this->N1() += num1; }

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

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

// --- INV SUB =-

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

	// this = s:num - this (signed)
	inline void InvSub(BASESINT num)
		{	DBLSINT::Neg();
			this->N1() += num; }

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

// --- increment ++

	// this++
	inline void Inc()
		{ this->N1()++; }

	// this = num + 1
	inline void Inc(const DBLFIX& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1() + 1; }

// --- decrement --

	// this--
	inline void Dec()
		{ this->N1()--; }

	// this = num - 1
	inline void Dec(const DBLFIX& num)
		{	this->N0() = num.N0();
			this->N1() = num.N1() - 1; }

// --- MUL *= (signed)

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

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

	// this *= 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 DBLFIX& num1, const DBLFIX& num2);

	// this = num1 * dblsint
	inline void Mul(const DBLFIX& num1, const DBLSINT& num2)
		{ DBLSINT::Mul(*(const DBLSINT*)&num1, num2); }

	// this = dblsint * num2
	inline void Mul(const DBLSINT& num1, const DBLFIX& num2)
		{ DBLSINT::Mul(num1, *(const DBLSINT*)&num2); }

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

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

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

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

	// this = double * num
	inline void Mul(double num1, const DBLFIX& 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 DBLFIX& num1, const DBLFIX& num2, DBLSINT* high)
		{ DBLSINT::MulHigh(*(const DBLSINT*)&num1, *(const DBLSINT*)&num2, high); }

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

// --- SQR (signed)

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

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

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

// --- POW ^

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

// --- DIV /= (signed)

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

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

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

	// this = this / 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 DBLFIX& 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()
		{	DBLFIX n;
			n.Set1();
			this->Div(n, *this); }

// --- DIV / (signed)

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

	// this = num1 / dblsint
	inline void Div(const DBLFIX& num1, const DBLSINT& num2)
		{ DBLSINT::Div(*(const DBLSINT*)&num1, num2); }

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

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

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

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

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

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

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

	// this = 1 / 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 DBLFIX& num1, const DBLFIX& num2)
		{	DBLSINT::Div(*(const DBLSINT*)&num1, *(const DBLSINT*)&num2);
			this->N1() = this->N0();
			this->N0() = 0; }

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

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

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

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

	// this = num / 10 (integer divide)
	inline void DivInt10(const DBLFIX& num)
		{	this->N1() = num.N1() / 10;
			this->N0() = 0; }

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

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

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

	// this = this % 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 DBLFIX& num1, const DBLFIX& num2)
		{ DBLSINT n; n.Div(*(const DBLSINT*)&num1, *(const DBLSINT*)&num2, this); }

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

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

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

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

	// this = num % 10
	inline void Mod10(const DBLFIX& num)
		{	DBLFIX n;
			n.Set((BASESINT)10);
			this->Mod(num, n); }

// --- 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 DBLSINT& div)
		{ return DBLSINT::PreFastDiv(div); }

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

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

// --- EQU ==

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

	inline bool IsZero() const { return this->Equ0(); }

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

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

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

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

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

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

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

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

// --- NEQU !=

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

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

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

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

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

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

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

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

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

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

// --- LESS <

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

	// this < s:num
	inline bool Less(BASESINT num) const
		{ return (this->N1() < num); }

// --- LESS EQU <=

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

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

// --- GREATER >

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

	// this > s:num
	inline bool Greater(BASESINT num) const
		{	return (this->N1() > num) || ((this->N1() == num) &&
				(this->N0() > 0)); }

// --- GREATER EQU >=

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

	// this >= s:num
	inline bool GreaterEqu(BASESINT num) const
		{ return (this->N1() >= num); }

// --- NEG

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

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

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

// --- ABS

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

	// this = abs(num)
	inline void Abs(const DBLFIX& num)
		{ DBLSINT::Abs(*(const DBLSINT*)&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()
		{ DBLSINT::Not(); }

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

	// this = ~s:num
	inline void Not(BASESINT num)
		{	this->N1() = ~num;
			this->N0() = BASENOT; }

// --- AND &=

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

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

// --- AND &

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

	// this = num1 & s:num2
	inline void And(const DBLFIX& num1, BASESINT num2)
		{	this->N0() = 0;
			this->N1() = num1.N1() & num2; }

	// this = s:num1 & num2
	inline void And(BASESINT num1, const DBLFIX& num2)
		{	this->N0() = 0;
			this->N1() = num1 & num2.N1(); }

// --- OR |=

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

	// this |= s:num
	inline void Or(BASESINT num)
		{ this->N1() |= num; }

// --- OR |

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

	// this = num1 | s:num2
	inline void Or(const DBLFIX& num1, BASESINT num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1() | num2; }

	// this = s:num1 | num2
	inline void Or(BASESINT num1, const DBLFIX& num2)
		{	this->N0() = num2.N0();
			this->N1() = num1 | num2.N1(); }

// --- XOR ^=

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

	// this ^= s:num
	inline void Xor(BASESINT num)
		{ this->N1() ^= num; }

// --- XOR ^

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

	// this = num1 ^ s:num2
	inline void Xor(const DBLFIX& num1, BASESINT num2)
		{	this->N0() = num1.N0();
			this->N1() = num1.N1() ^ num2; }

	// this = s:num1 ^ num2
	inline void Xor(BASESINT num1, const DBLFIX& num2)
		{	this->N0() = num2.N0();
			this->N1() = num1 ^ num2.N1(); }

// --- set/clear/get bit

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

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

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

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

	// get number of valid bits of absolute value (=logarithm+1, returns position of highest bit + 1, 0..2*BASEBITS)
	inline int Bits() const
		{ return DBLSINT::Bits(); }

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

// --- LShift <<=

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

	// this <<= shift
	inline void LShift(int shift)
		{ DBLSINT::LShift(shift); }

// --- LShift <<

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

	// this = num << shift
	inline void LShift(const DBLFIX& num, int shift)
		{ DBLSINT::LShift(*(const DBLSINT*)&num, shift); }

	// this = s:num << 1
	inline void LShift1(BASESINT num)
		{	this->N0() = 0;
			this->N1() = num << 1; }

	// this = s:num << shift
	inline void LShift(BASESINT num, int shift)
		{	this->Set(num);
			this->LShift(shift); }

// --- RShift >>=

	// this >>= 1
	inline void RShift1()
		{ DBLSINT::RShift1(); }

	// this >>= shift
	inline void RShift(int shift)
		{ DBLSINT::RShift(shift); }

// --- RShift >>

	// this = num >> 1
	inline void RShift1(const DBLFIX& num)
		{ DBLSINT::RShift1(*(const DBLSINT*)&num); }

	// this = num >> shift
	inline void RShift(const DBLFIX& num, int shift)
		{ DBLSINT::RShift(*(const DBLSINT*)&num, shift); }

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

	// this = s:num >> shift
	inline 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
	// (fix128: 1+19+1+20+1=43, fix64: 1+9+1+10+1=23, fix32: 1+4+1+5+1=13), returns number of characters
	// dec = max. number of decimal places (max. DBLFIX_DEC+1)
	//   default precision: fix128: 19, fix64: 9, fix32: 4
	//   max. precision: fix128: 20, fix64: 10, fix32: 5 (last digit can be incorrect, previous one can be incorrectly rounded)
	int ToTextBuf(char* buf, int bufsize, int dec = DBLFIX_DEC) const;

	CText ToText(int dec = DBLFIX_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

	// this = sqrt(num), square root
	void Sqrt(const DBLFIX& num);
	inline void Sqrt() { this->Sqrt(*this); }

	// convert radians to degrees, this = num*180/Pi
	inline void RadDeg(const DBLFIX& num)
		{ this->Mul(num, DBLFIX::Pi180R); }
	inline void RadDeg()
		{ this->Mul(DBLFIX::Pi180R); }

	// convert degrees to radians, this = num*Pi/180
	inline void DegRad(const DBLFIX& num)
		{ this->Mul(num, DBLFIX::Pi180); }
	inline void DegRad()
		{ this->Mul(DBLFIX::Pi180); }

	// normalize angle in radians into range 0..Pi*2 (including 0, excluding Pi*2)
	void NormRad(const DBLFIX& num);
	inline void NormRad()
		{ this->NormRad(*this); }

	// normalize angle in degrees into range 0..360 (including 0, excluding 360)
	void NormDeg(const DBLFIX& num);
	inline void NormDeg()
		{ this->NormDeg(*this); }

	// this = sin(num), sine in radiands, result -1..+1
	void Sin(const DBLFIX& num);
	inline void Sin() { this->Sin(*this); }

	// this = arcsin(num), input -1..+1, result in radians
	inline void ASin(const DBLFIX& num) { this->ASin0(num, false); }
	inline void ASin() { this->ASin(*this); }

	// this = cos(num), cosine in radians, result -1..+1
	inline void Cos(const DBLFIX& num)
		{	this->Add(num, DBLFIX::Pi12);
			this->Sin(); }
	inline void Cos() { this->Cos(*this); }

	// this = arccos(num), input -1..+1, result in radians
	inline void ACos(const DBLFIX& num) { this->ASin0(num, true); }
	inline void ACos() { this->ACos(*this); }

	// this = tan(num), tangent in radians (tan = sin/cos)
	inline void Tan(const DBLFIX& num)
		{	DBLFIX 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 DBLFIX& num)
		{ this->ATan0(num, false); }
	inline void ATan() { this->ATan(*this); }

	// this = cotan(num), cotangent in radians (cotan = cos/sin)
	inline void CoTan(const DBLFIX& num)
		{	DBLFIX 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 DBLFIX& num)
		{ this->ATan0(num, true); }
	inline void ACoTan() { this->ACoTan(*this); }

	// this = log(num), natural logarithm
	void Log(const DBLFIX& num);
	inline void Log() { this->Log(*this); }

	// this = log10(num), decadic logarithm
	inline void Log10(const DBLFIX& num)
		{	this->Log(num);
			this->Mul(DBLFIX::Ln110); }
	inline void Log10() { this->Log10(*this); }

	// this = exp(num), natural exponent
	void Exp(const DBLFIX& num);
	inline void Exp() { this->Exp(*this); }

	// this = exp10(num), decadic exponent
	inline void Exp10(const DBLFIX& num)
		{	this->Mul(DBLFIX::Ln10, num);
			this->Exp(); }
	inline void Exp10() { this->Exp10(*this); }

// --- "in class" operators

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

inline DBLFIX operator+ (const DBLFIX& num1, double num2)
	{ DBLFIX n; n.Add(num1, num2); return n; }

inline DBLFIX operator+ (double num1, const DBLFIX& num2)
	{ DBLFIX n; n.Add(num1, num2); return n; }

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

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

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

inline DBLFIX operator- (const DBLFIX& num1, double num2)
	{ DBLFIX n; n.Sub(num1, num2); return n; }

inline DBLFIX operator- (double num1, const DBLFIX& num2)
	{ DBLFIX n; n.Sub(num1, num2); return n; }

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

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

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

inline DBLFIX operator* (const DBLFIX& num1, double num2)
	{ DBLFIX n; n.Mul(num1, num2); return n; }

inline DBLFIX operator* (double num1, const DBLFIX& num2)
	{ DBLFIX n; n.Mul(num1, num2); return n; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


#undef DBLUINT
#undef BASEUINT
#undef HALFUINT

#undef DBLSINT
#undef BASESINT
#undef HALFSINT

#undef DBLFIX

#undef USEASM

#undef BASEBITS
#undef BASELAST
#undef HALFBITS
#undef HALFMASK
#undef BASENOT

#undef DBLFIX_MAX
#undef DBLFIX_MIN
#undef DBLFIX_DEC
