// http://www.fractal-landscapes.co.uk/bigint.html
using System;
namespace BigNum
{
///
/// Specifies the desired precision for a BigInt or a BigFloat.
///
public struct PrecisionSpec
{
///
/// Precision can be specified in a choice of 8 bases.
/// Note that precision for decimals is approximate.
///
public enum BaseType
{
///
/// Binary base
///
BIN,
///
/// Octal base
///
OCT,
///
/// Decimal base
///
DEC,
///
/// Hexadecimal base
///
HEX,
///
/// 8-bits per digit
///
BYTES,
///
/// 16-bits per digit
///
WORDS,
///
/// 32-bits per digit
///
DWORDS,
///
/// 64-bits per digit
///
QWORDS
}
///
/// Constructor: Constructs a precision specification
///
/// The number of digits
/// The base of the digits
public PrecisionSpec(int precision, BaseType numberBase)
{
this.prec = precision;
this.nB = numberBase;
}
///
/// Explicit cast from integer value.
///
/// The value in bits for the new precision specification
/// A new precision specification with the number of bits specified
public static explicit operator PrecisionSpec(int value)
{
return new PrecisionSpec(value, BaseType.BIN);
}
///
/// Equality test
///
/// the first parameter
/// the second parameter
/// true iff both precisions have the same number of bits
public static bool operator ==(PrecisionSpec spec1, PrecisionSpec spec2)
{
return (spec1.NumBits == spec2.NumBits);
}
///
/// Inequality operator
///
/// the first parameter
/// the second parameter
/// true iff the parameters do not have the same number of bits
public static bool operator !=(PrecisionSpec spec1, PrecisionSpec spec2)
{
return !(spec1 == spec2);
}
///
/// Object equality override
///
/// the PrecisionSpec struct to compare
/// true iff obj has the same number of bits as this
public override bool Equals(object obj)
{
return NumBits == ((PrecisionSpec)obj).NumBits;
}
///
/// Override of the hash code
///
/// A basic hash
public override int GetHashCode()
{
return NumBits * prec + NumBits;
}
///
/// The precision in units specified by the base type (e.g. number of decimal digits)
///
public int Precision
{
get { return prec; }
}
///
/// The base type in which precision is specified
///
public BaseType NumberBaseType
{
get { return nB; }
}
///
/// Converts the number-base to an integer
///
public int NumberBase
{
get { return (int)nB; }
}
///
/// The number of bits that this PrecisionSpec structure specifies.
///
public int NumBits
{
get
{
if (nB == BaseType.BIN) return prec;
if (nB == BaseType.OCT) return prec * 3;
if (nB == BaseType.HEX) return prec * 4;
if (nB == BaseType.BYTES) return prec * 8;
if (nB == BaseType.WORDS) return prec * 16;
if (nB == BaseType.DWORDS) return prec * 32;
if (nB == BaseType.QWORDS) return prec * 64;
double factor = 3.322;
int bits = ((int)Math.Ceiling(factor * (double)prec));
return bits;
}
}
private int prec;
private BaseType nB;
}
///
/// An arbitrary-precision integer class
///
/// Format:
/// Each number consists of an array of 32-bit unsigned integers, and a bool sign
/// value.
///
/// Applicability and Performance:
/// This class is designed to be used for small extended precisions. It may not be
/// safe (and certainly won't be fast) to use it with mixed-precision arguments.
/// It does support, but will not be efficient for, numbers over around 2048 bits.
///
/// Notes:
/// All conversions to and from strings are slow.
///
/// Conversions from simple integer types Int32, Int64, UInt32, UInt64 are performed
/// using the appropriate constructor, and are relatively fast.
///
/// The class is written entirely in managed C# code, with not native or managed
/// assembler. The use of native assembler would speed up the multiplication operations
/// many times over, and therefore all higher-order operations too.
///
public class BigInt
{
//*************** Constructors ******************
///
/// Constructs an empty BigInt to the desired precision.
///
///
public BigInt(PrecisionSpec precision)
{
Init(precision);
}
///
/// Constructs a BigInt from a string, using the string length to determine the precision
/// Note, operations on BigInts of non-matching precision are slow, so avoid using this constructor
///
///
public BigInt(string init)
{
InitFromString(init, (PrecisionSpec)init.Length, 10);
}
///
/// Constructor for copying length and precision
///
/// The BigInt to copy
/// The precision of the new BigInt
/// decides whether to copy the actual input, or just its digit length
/// //Create an integer
/// BigInt four = new BigInt(4, new PrecisionSpec(128, PrecisionSpec.BaseType.BIN));
///
/// //Pad four to double its usual number of digits (this does not affect the precision)
/// four.Pad();
///
/// //Create a new, empty integer with matching precision, also padded to twice the usual length
/// BigInt newCopy = new BigInt(four, four.Precision, true);
public BigInt(BigInt inputToCopy, PrecisionSpec precision, bool bCopyLengthOnly)
{
digitArray = new uint[inputToCopy.digitArray.Length];
workingSet = new uint[inputToCopy.digitArray.Length];
if (!bCopyLengthOnly) Array.Copy(inputToCopy.digitArray, digitArray, digitArray.Length);
sign = inputToCopy.sign;
pres = inputToCopy.pres;
}
///
/// Constructs a bigint from the string, with the desired precision, using base 10
///
///
///
public BigInt(string init, PrecisionSpec precision)
{
InitFromString(init, precision, 10);
}
///
/// Constructs a BigInt from a string, using the specified precision and base
///
///
///
///
public BigInt(string init, PrecisionSpec precision, int numberBase)
{
InitFromString(init, precision, numberBase);
}
///
/// Constructs a bigint from the input.
///
///
public BigInt(BigInt input)
{
digitArray = new uint[input.digitArray.Length];
workingSet = new uint[input.digitArray.Length];
Array.Copy(input.digitArray, digitArray, digitArray.Length);
sign = input.sign;
pres = input.pres;
}
///
/// Constructs a bigint from the input, matching the new precision provided
///
public BigInt(BigInt input, PrecisionSpec precision)
{
//Casts the input to the new precision.
Init(precision);
int Min = (input.digitArray.Length < digitArray.Length) ? input.digitArray.Length : digitArray.Length;
for (int i = 0; i < Min; i++)
{
digitArray[i] = input.digitArray[i];
}
sign = input.sign;
}
///
/// Constructs a BigInt from a UInt32
///
///
///
public BigInt(UInt32 input, PrecisionSpec precision)
{
Init(precision);
digitArray[0] = input;
}
///
/// Constructs a BigInt from a UInt64
///
///
///
public BigInt(UInt64 input, PrecisionSpec precision)
{
Init(precision);
digitArray[0] = (UInt32)(input & 0xffffffff);
if (digitArray.Length > 1) digitArray[1] = (UInt32)(input >> 32);
}
///
/// Constructs a BigInt from an Int32
///
///
///
public BigInt(Int32 input, PrecisionSpec precision)
{
Init(precision);
if (input < 0)
{
sign = true;
if (input == Int32.MinValue)
{
digitArray[0] = 0x80000000;
}
else
{
digitArray[0] = (UInt32)(-input);
}
}
else
{
digitArray[0] = ((UInt32)input);
}
}
///
/// Constructs a BigInt from a UInt32
///
///
///
public BigInt(Int64 input, PrecisionSpec precision)
{
Init(precision);
if (input < 0) sign = true;
digitArray[0] = (UInt32)(input & 0xffffffff);
if (digitArray.Length >= 2)
{
if (input == Int64.MinValue)
{
digitArray[1] = 0x80000000;
}
else
{
digitArray[1] = (UInt32)((input >> 32) & 0x7fffffff);
}
}
}
//***************** Properties *******************
///
/// true iff the number is negative
///
public bool Sign { get { return sign; } set { sign = value; } }
///
/// The precision of the number.
///
public PrecisionSpec Precision { get { return pres; } }
//*************** Utility Functions **************
///
/// Casts a BigInt to the new precision provided.
/// Note: This will return the input if the precision already matches.
///
///
///
///
public static BigInt CastToPrecision(BigInt input, PrecisionSpec precision)
{
if (input.pres == precision) return input;
return new BigInt(input, precision);
}
//*************** Member Functions ***************
///
/// Addition and assignment - without intermediate memory allocation.
///
///
///
public uint Add(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
if (sign == n2.sign)
{
return AddInternalBits(n2.digitArray);
}
else
{
bool lessThan = LtInt(this, n2);
if (lessThan)
{
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
workingSet[i] = digitArray[i];
digitArray[i] = n2.digitArray[i];
}
sign = !sign;
return SubInternalBits(workingSet);
}
else
{
return SubInternalBits(n2.digitArray);
}
}
}
///
/// Subtraction and assignment - without intermediate memory allocation.
///
///
public uint Sub(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
if (sign != n2.sign)
{
return AddInternalBits(n2.digitArray);
}
else
{
bool lessThan = LtInt(this, n2);
if (lessThan)
{
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
workingSet[i] = digitArray[i];
digitArray[i] = n2.digitArray[i];
}
sign = !sign;
return SubInternalBits(workingSet);
}
else
{
return SubInternalBits(n2.digitArray);
}
}
}
///
/// Multiplication and assignmnet - with minimal intermediate memory allocation.
///
///
public void Mul(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
int Length = n2.digitArray.Length;
//Inner loop zero-mul avoidance
int maxDigit = 0;
for (int i = Length - 1; i >= 0; i--)
{
if (digitArray[i] != 0)
{
maxDigit = i + 1;
break;
}
}
//Result is zero, 'this' is unchanged
if (maxDigit == 0) return;
//Temp storage for source (both working sets are used by the calculation)
uint[] thisTemp = new uint [Length];
for (int i = 0; i < Length; i++)
{
thisTemp[i] = digitArray[i];
digitArray[i] = 0;
}
for (int i = 0; i < Length; i++)
{
//Clear the working set
for (int j = 0; j < i; j++)
{
workingSet[j] = 0;
n2.workingSet[j] = 0;
}
n2.workingSet[i] = 0;
ulong digit = n2.digitArray[i];
if (digit == 0) continue;
for (int j = 0; j + i < Length && j < maxDigit; j++)
{
//Multiply n1 by each of the integer digits of n2.
ulong temp = (ulong)thisTemp[j] * digit;
//n1.workingSet stores the low bits of each piecewise multiplication
workingSet[j + i] = (uint)(temp & 0xffffffff);
if (j + i + 1 < Length)
{
//n2.workingSet stores the high bits of each multiplication
n2.workingSet[j + i + 1] = (uint)(temp >> 32);
}
}
AddInternalBits(workingSet);
AddInternalBits(n2.workingSet);
}
sign = (sign != n2.sign);
}
///
/// Squares the number.
///
public void Square()
{
int Length = digitArray.Length;
//Inner loop zero-mul avoidance
int maxDigit = 0;
for (int i = Length - 1; i >= 0; i--)
{
if (digitArray[i] != 0)
{
maxDigit = i + 1;
break;
}
}
//Result is zero, 'this' is unchanged
if (maxDigit == 0) return;
//Temp storage for source (both working sets are used by the calculation)
uint[] thisTemp = new uint[Length];
for (int i = 0; i < Length; i++)
{
thisTemp[i] = digitArray[i];
digitArray[i] = 0;
}
UInt32 [] workingSet2 = new UInt32[Length];
for (int i = 0; i < Length; i++)
{
//Clear the working set
for (int j = 0; j < i; j++)
{
workingSet[j] = 0;
workingSet2[j] = 0;
}
workingSet2[i] = 0;
ulong digit = thisTemp[i];
if (digit == 0) continue;
for (int j = 0; j + i < Length && j < maxDigit; j++)
{
//Multiply n1 by each of the integer digits of n2.
ulong temp = (ulong)thisTemp[j] * digit;
//n1.workingSet stores the low bits of each piecewise multiplication
workingSet[j + i] = (uint)(temp & 0xffffffff);
if (j + i + 1 < Length)
{
//n2.workingSet stores the high bits of each multiplication
workingSet2[j + i + 1] = (uint)(temp >> 32);
}
}
AddInternalBits(workingSet);
AddInternalBits(workingSet2);
}
sign = false;
}
///
/// Used for floating-point multiplication
/// Stores the high bits of the multiplication only (the carry bit from the
/// lower bits is missing, so the true answer might be 1 greater).
///
///
public void MulHi(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
int Length = n2.digitArray.Length;
//Inner loop zero-mul avoidance
int maxDigit = 0;
for (int i = Length - 1; i >= 0; i--)
{
if (digitArray[i] != 0)
{
maxDigit = i + 1;
break;
}
}
//Result is zero, 'this' is unchanged
if (maxDigit == 0) return;
//Temp storage for source (both working sets are used by the calculation)
uint[] thisTemp = new uint[Length];
for (int i = 0; i < Length; i++)
{
thisTemp[i] = digitArray[i];
digitArray[i] = 0;
}
for (int i = 0; i < Length; i++)
{
//Clear the working set
for (int j = 0; j < Length; j++)
{
workingSet[j] = 0;
n2.workingSet[j] = 0;
}
n2.workingSet[i] = 0;
ulong digit = n2.digitArray[i];
if (digit == 0) continue;
//Only the high bits
if (maxDigit + i < Length - 1) continue;
for (int j = 0; j < maxDigit; j++)
{
if (j + i + 1 < Length) continue;
//Multiply n1 by each of the integer digits of n2.
ulong temp = (ulong)thisTemp[j] * digit;
//n1.workingSet stores the low bits of each piecewise multiplication
if (j + i >= Length)
{
workingSet[j + i - Length] = (uint)(temp & 0xffffffff);
}
//n2.workingSet stores the high bits of each multiplication
n2.workingSet[j + i + 1 - Length] = (uint)(temp >> 32);
}
AddInternalBits(workingSet);
AddInternalBits(n2.workingSet);
}
sign = (sign != n2.sign);
}
///
/// Floating-point helper function.
/// Squares the number and keeps the high bits of the calculation.
/// Takes a temporary BigInt as a working set.
///
public void SquareHiFast(BigInt scratch)
{
int Length = digitArray.Length;
uint[] tempDigits = scratch.digitArray;
uint[] workingSet2 = scratch.workingSet;
//Temp storage for source (both working sets are used by the calculation)
for (int i = 0; i < Length; i++)
{
tempDigits[i] = digitArray[i];
digitArray[i] = 0;
}
for (int i = 0; i < Length; i++)
{
//Clear the working set
for (int j = i; j < Length; j++)
{
workingSet[j] = 0;
workingSet2[j] = 0;
}
if (i - 1 >= 0) workingSet[i - 1] = 0;
ulong digit = tempDigits[i];
if (digit == 0) continue;
for (int j = 0; j < Length; j++)
{
if (j + i + 1 < Length) continue;
//Multiply n1 by each of the integer digits of n2.
ulong temp = (ulong)tempDigits[j] * digit;
//n1.workingSet stores the low bits of each piecewise multiplication
if (j + i >= Length)
{
workingSet[j + i - Length] = (uint)(temp & 0xffffffff);
}
//n2.workingSet stores the high bits of each multiplication
workingSet2[j + i + 1 - Length] = (uint)(temp >> 32);
}
AddInternalBits(workingSet);
AddInternalBits(workingSet2);
}
sign = false;
}
///
/// This uses the schoolbook division algorithm, as decribed by http://www.treskal.com/kalle/exjobb/original-report.pdf
/// Algorithms 3.1 (implemented by Div_31) and 3.2 (implemented by Div_32)
///
///
public void Div(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
int OldLength = digitArray.Length;
//First, we need to prepare the operands for division using Div_32, which requires
//That the most significant digit of n2 be set. To do this, we need to shift n2 (and therefore n1) up.
//This operation can potentially increase the precision of the operands.
int shift = MakeSafeDiv(this, n2);
BigInt Q = new BigInt(this, this.pres, true);
BigInt R = new BigInt(this, this.pres, true);
Div_32(this, n2, Q, R);
//Restore n2 to its pre-shift value
n2.RSH(shift);
AssignInt(Q);
sign = (sign != n2.sign);
//Reset the lengths of the operands
SetNumDigits(OldLength);
n2.SetNumDigits(OldLength);
}
///
/// This function is used for floating-point division.
///
///
//Given two numbers:
// In floating point 1 <= a, b < 2, meaning that both numbers have their top bits set.
// To calculate a / b, maintaining precision, we:
// 1. Double the number of digits available to both numbers.
// 2. set a = a * 2^d (where d is the number of digits)
// 3. calculate the quotient a <- q: 2^(d-1) <= q < 2^(d+1)
// 4. if a >= 2^d, s = 1, else s = 0
// 6. shift a down by s, and undo the precision extension
// 7. return 1 - shift (change necessary to exponent)
public int DivAndShift(BigInt n2)
{
if (n2.IsZero()) return -1;
if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);
int oldLength = digitArray.Length;
//Double the number of digits, and shift a into the higher digits.
Pad();
n2.Extend();
//Do the divide (at double precision, ouch!)
Div(n2);
//Shift down if 'this' >= 2^d
int ret = 1;
if (digitArray[oldLength] != 0)
{
RSH(1);
ret--;
}
SetNumDigits(oldLength);
n2.SetNumDigits(oldLength);
return ret;
}
///
/// Calculates 'this' mod n2 (using the schoolbook division algorithm as above)
///
///
public void Mod(BigInt n2)
{
if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);
int OldLength = digitArray.Length;
//First, we need to prepare the operands for division using Div_32, which requires
//That the most significant digit of n2 be set. To do this, we need to shift n2 (and therefore n1) up.
//This operation can potentially increase the precision of the operands.
int shift = MakeSafeDiv(this, n2);
BigInt Q = new BigInt(this.pres);
BigInt R = new BigInt(this.pres);
Q.digitArray = new UInt32[this.digitArray.Length];
R.digitArray = new UInt32[this.digitArray.Length];
Div_32(this, n2, Q, R);
//Restore n2 to its pre-shift value
n2.RSH(shift);
R.RSH(shift);
R.sign = (sign != n2.sign);
AssignInt(R);
//Reset the lengths of the operands
SetNumDigits(OldLength);
n2.SetNumDigits(OldLength);
}
///
/// Logical left shift
///
///
public void LSH(int shift)
{
if (shift <= 0) return;
int length = digitArray.Length;
int digits = shift >> 5;
int rem = shift & 31;
for (int i = length - 1; i >= digits; i--)
{
digitArray[i] = digitArray[i - digits];
}
if (digits > 0)
{
for (int i = digits - 1; i >= 0; i--)
{
digitArray[i] = 0;
}
}
UInt64 lastShift = 0;
for (int i = 0; i < length; i++)
{
UInt64 temp = (((UInt64)digitArray[i]) << rem) | lastShift;
digitArray[i] = (UInt32)(temp & 0xffffffff);
lastShift = temp >> 32;
}
}
///
/// Logical right-shift
///
///
public void RSH(int shift)
{
if (shift < 0) return;
int length = digitArray.Length;
int digits = shift >> 5;
int rem = shift & 31;
for (int i = 0; i < length - digits; i++)
{
digitArray[i] = digitArray[i + digits];
}
int start = (length - digits);
if (start < 0) start = 0;
for (int i = start; i < length; i++)
{
digitArray[i] = 0;
}
UInt64 lastShift = 0;
for (int i = length - 1; i >= 0; i--)
{
UInt64 temp = ((((UInt64)digitArray[i]) << 32) >> rem) | lastShift;
digitArray[i] = (UInt32)(temp >> 32);
lastShift = (temp & 0xffffffff) << 32;
}
}
///
/// Changes the sign of the number
///
public void Negate()
{
sign = !sign;
}
///
/// Increments the number.
///
public void Increment()
{
if (sign)
{
DecrementInt();
}
else
{
IncrementInt();
}
}
///
/// Decrements the number.
///
public void Decrement()
{
if (sign)
{
IncrementInt();
}
else
{
DecrementInt();
}
}
///
/// Calculates the factorial 'this'!
///
public void Factorial()
{
if (sign) return;
//Clamp to a reasonable range.
int factToUse = (int)(digitArray[0]);
if (factToUse > 65536) factToUse = 65536;
Zero();
digitArray[0] = 1;
for (uint i = 1; i <= factToUse; i++)
{
MulInternal(i);
}
}
///
/// Calculates 'this'^power
///
///
public void Power(BigInt power)
{
if (power.IsZero() || power.sign)
{
Zero();
digitArray[0] = 1;
return;
}
BigInt pow = new BigInt(power);
BigInt temp = new BigInt(this);
BigInt powTerm = new BigInt(this);
pow.Decrement();
for (; !pow.IsZero(); pow.RSH(1))
{
if ((pow.digitArray[0] & 1) == 1)
{
temp.Mul(powTerm);
}
powTerm.Square();
}
Assign(temp);
}
//***************** Comparison member functions *****************
///
/// returns true if this bigint == 0
///
///
public bool IsZero()
{
for (int i = 0; i < digitArray.Length; i++)
{
if (digitArray[i] != 0) return false;
}
return true;
}
///
/// true iff n2 (precision adjusted to this) is less than 'this'
///
///
///
public bool LessThan(BigInt n2)
{
if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);
if (sign)
{
if (!n2.sign) return true;
return GtInt(this, n2);
}
else
{
if (n2.sign) return false;
return LtInt(this, n2);
}
}
///
/// true iff n2 (precision adjusted to this) is greater than 'this'
///
///
///
public bool GreaterThan(BigInt n2)
{
if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);
if (sign)
{
if (!n2.sign) return false;
return LtInt(this, n2);
}
else
{
if (n2.sign) return true;
return GtInt(this, n2);
}
}
///
/// Override of base-class equals
///
///
///
public override bool Equals(object obj)
{
BigInt n2 = ((BigInt)obj);
return Equals(n2);
}
///
/// Get hash code
///
///
public override int GetHashCode()
{
return (Int32)digitArray[0];
}
///
/// True iff n2 (precision-adjusted to this) == n1
///
///
///
public bool Equals(BigInt n2)
{
if (IsZero() && n2.IsZero()) return true;
if (sign != n2.sign) return false;
int Length = digitArray.Length;
if (n2.digitArray.Length != Length) MakeSafe(ref n2);
for (int i = 0; i < Length; i++)
{
if (digitArray[i] != n2.digitArray[i]) return false;
}
return true;
}
//******************* Bitwise member functions ********************
///
/// Takes the bitwise complement of the number
///
public void Complement()
{
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
digitArray[i] = ~digitArray[i];
}
}
///
/// Bitwise And
///
///
public void And(BigInt n2)
{
int Length = digitArray.Length;
if (n2.digitArray.Length != Length) MakeSafe(ref n2);
for (int i = 0; i < Length; i++)
{
digitArray[i] &= n2.digitArray[i];
}
sign &= n2.sign;
}
///
/// Bitwise Or
///
///
public void Or(BigInt n2)
{
int Length = digitArray.Length;
if (n2.digitArray.Length != Length) MakeSafe(ref n2);
for (int i = 0; i < Length; i++)
{
digitArray[i] |= n2.digitArray[i];
}
sign |= n2.sign;
}
///
/// Bitwise Xor
///
///
public void Xor(BigInt n2)
{
int Length = digitArray.Length;
if (n2.digitArray.Length != Length) MakeSafe(ref n2);
for (int i = 0; i < Length; i++)
{
digitArray[i] ^= n2.digitArray[i];
}
sign ^= n2.sign;
}
//*************** Fast Static Arithmetic Functions *****************
///
/// Adds n1 and n2 and puts result in dest, without intermediate memory allocation
/// (unsafe if n1 and n2 disagree in precision, safe even if dest is n1 or n2)
///
///
///
///
public static void AddFast(BigInt dest, BigInt n1, BigInt n2)
{
//We cast to the highest input precision...
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
//Then we up the output precision if less than the input precision.
if (dest.digitArray.Length < n1.digitArray.Length) n1.MakeSafe(ref dest);
int Length = n1.digitArray.Length;
if (n1.sign == n2.sign)
{
//Copies sources into digit array and working set for all cases, to avoid
//problems when dest is n1 or n2
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n2.digitArray[i];
dest.digitArray[i] = n1.digitArray[i];
}
dest.AddInternalBits(dest.workingSet);
dest.sign = n1.sign;
}
else
{
bool lessThan = LtInt(n1, n2);
if (lessThan)
{
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n1.digitArray[i];
dest.digitArray[i] = n2.digitArray[i];
}
dest.SubInternalBits(dest.workingSet);
dest.sign = !n1.sign;
}
else
{
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n2.digitArray[i];
dest.digitArray[i] = n1.digitArray[i];
}
dest.SubInternalBits(dest.workingSet);
dest.sign = n1.sign;
}
}
}
///
/// Adds n1 and n2 and puts result in dest, without intermediate memory allocation
/// (unsafe if n1 and n2 disagree in precision, safe even if dest is n1 or n2)
///
///
///
///
public static void SubFast(BigInt dest, BigInt n1, BigInt n2)
{
//We cast to the highest input precision...
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
//Then we up the output precision if less than the input precision.
if (dest.digitArray.Length < n1.digitArray.Length) n1.MakeSafe(ref dest);
int Length = n1.digitArray.Length;
if (n1.sign != n2.sign)
{
//Copies sources into digit array and working set for all cases, to avoid
//problems when dest is n1 or n2
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n2.digitArray[i];
dest.digitArray[i] = n1.digitArray[i];
}
dest.AddInternalBits(dest.workingSet);
dest.sign = n1.sign;
}
else
{
bool lessThan = LtInt(n1, n2);
if (lessThan)
{
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n1.digitArray[i];
dest.digitArray[i] = n2.digitArray[i];
}
dest.SubInternalBits(dest.workingSet);
dest.sign = !n1.sign;
}
else
{
for (int i = 0; i < Length; i++)
{
dest.workingSet[i] = n2.digitArray[i];
dest.digitArray[i] = n1.digitArray[i];
}
dest.SubInternalBits(dest.workingSet);
dest.sign = n1.sign;
}
}
}
//*************** Static Arithmetic Functions ***************
///
/// signed addition of 2 numbers.
///
///
///
///
public static BigInt Add(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt result;
if (n1.sign == n2.sign)
{
result = new BigInt(n1);
result.AddInternal(n2);
result.sign = n1.sign;
}
else
{
bool lessThan = LtInt(n1, n2);
if (lessThan)
{
result = new BigInt(n2);
result.SubInternal(n1);
result.sign = !n1.sign;
}
else
{
result = new BigInt(n1);
result.SubInternal(n2);
result.sign = n1.sign;
}
}
return result;
}
///
/// signed subtraction of 2 numbers.
///
///
///
///
public static BigInt Sub(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt result;
if ((n1.sign && !n2.sign) || (!n1.sign && n2.sign))
{
result = new BigInt(n1);
result.AddInternal(n2);
result.sign = n1.sign;
}
else
{
bool lessThan = LtInt(n1, n2);
if (lessThan)
{
result = new BigInt(n2);
result.SubInternal(n1);
result.sign = !n1.sign;
}
else
{
result = new BigInt(n1);
result.SubInternal(n2);
result.sign = n1.sign;
}
}
return result;
}
///
/// Multiplication of two BigInts
///
///
///
///
public static BigInt Mul(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt result = new BigInt(n1);
result.Mul(n2);
return result;
}
///
/// True arbitrary precision divide.
///
///
///
///
public static BigInt Div(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt res = new BigInt(n1);
res.Div(n2);
return res;
}
///
/// True arbitrary-precision mod operation
///
///
///
///
public static BigInt Mod(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt res = new BigInt(n1);
res.Mod(n2);
return res;
}
///
/// Unsigned multiplication of a BigInt by a small number
///
///
///
///
public static BigInt Mul(BigInt n1, uint n2)
{
BigInt result = new BigInt(n1);
result.MulInternal(n2);
return result;
}
///
/// Division of a BigInt by a small (unsigned) number
///
///
///
///
public static BigInt Div(BigInt n1, uint n2)
{
BigInt result = new BigInt(n1);
result.DivInternal(n2);
return result;
}
///
/// Division and remainder of a BigInt by a small (unsigned) number
/// n1 / n2 = div remainder mod
///
/// The number to divide (dividend)
/// The number to divide by (divisor)
/// The quotient (output parameter)
/// The remainder (output parameter)
public static void DivMod(BigInt n1, uint n2, out BigInt div, out BigInt mod)
{
div = Div(n1, n2);
mod = Mul(div, n2);
mod = Sub(n1, mod);
}
//**************** Static Comparison Functions ***************
///
/// true iff n1 is less than n2
///
///
///
///
public static bool LessThan(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
if (n1.sign)
{
if (!n2.sign) return true;
return GtInt(n1, n2);
}
else
{
if (n2.sign) return false;
return LtInt(n1, n2);
}
}
///
/// true iff n1 is greater than n2
///
///
///
///
public static bool GreaterThan(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
if (n1.sign)
{
if (!n2.sign) return false;
return LtInt(n1, n2);
}
else
{
if (n2.sign) return true;
return GtInt(n1, n2);
}
}
///
/// true iff n1 == n2
///
///
///
///
public static bool Equals(BigInt n1, BigInt n2)
{
return n1.Equals(n2);
}
//***************** Static Bitwise Functions *****************
///
/// Bitwise And
///
///
///
///
public static BigInt And(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt res = new BigInt(n1);
res.And(n2);
return res;
}
///
/// Bitwise Or
///
///
///
///
public static BigInt Or(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt res = new BigInt(n1);
res.Or(n2);
return res;
}
///
/// Bitwise Xor
///
///
///
///
public static BigInt Xor(BigInt n1, BigInt n2)
{
if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
BigInt res = new BigInt(n1);
res.And(n2);
return res;
}
//**************** Static Operator Overloads *****************
///
/// Addition operator
///
public static BigInt operator +(BigInt n1, BigInt n2)
{
return Add(n1, n2);
}
///
/// The subtraction operator
///
public static BigInt operator -(BigInt n1, BigInt n2)
{
return Sub(n1, n2);
}
///
/// The multiplication operator
///
public static BigInt operator *(BigInt n1, BigInt n2)
{
return Mul(n1, n2);
}
///
/// The division operator
///
public static BigInt operator /(BigInt n1, BigInt n2)
{
return Div(n1, n2);
}
///
/// The remainder (mod) operator
///
public static BigInt operator %(BigInt n1, BigInt n2)
{
return Mod(n1, n2);
}
///
/// The left-shift operator
///
public static BigInt operator <<(BigInt n1, int n2)
{
BigInt res = new BigInt(n1);
res.LSH(n2);
return res;
}
///
/// The right-shift operator
///
public static BigInt operator >>(BigInt n1, int n2)
{
BigInt res = new BigInt(n1);
res.RSH(n2);
return res;
}
///
/// The less than operator
///
public static bool operator <(BigInt n1, BigInt n2)
{
return LessThan(n1, n2);
}
///
/// The greater than operator
///
public static bool operator >(BigInt n1, BigInt n2)
{
return GreaterThan(n1, n2);
}
///
/// The less than or equal to operator
///
public static bool operator <=(BigInt n1, BigInt n2)
{
return !GreaterThan(n1, n2);
}
///
/// The greater than or equal to operator
///
public static bool operator >=(BigInt n1, BigInt n2)
{
return !LessThan(n1, n2);
}
///
/// The equality operator
///
public static bool operator ==(BigInt n1, BigInt n2)
{
return Equals(n1, n2);
}
///
/// The inequality operator
///
public static bool operator !=(BigInt n1, BigInt n2)
{
return !Equals(n1, n2);
}
///
/// The bitwise AND operator
///
public static BigInt operator &(BigInt n1, BigInt n2)
{
return And(n1, n2);
}
///
/// The bitwise OR operator
///
public static BigInt operator |(BigInt n1, BigInt n2)
{
return Or(n1, n2);
}
///
/// The bitwise eXclusive OR operator
///
public static BigInt operator ^(BigInt n1, BigInt n2)
{
return Xor(n1, n2);
}
///
/// The increment operator
///
public static BigInt operator ++(BigInt n1)
{
n1.Increment();
return n1;
}
///
/// The decrement operator
///
public static BigInt operator --(BigInt n1)
{
n1.Decrement();
return n1;
}
//**************** Private Member Functions *****************
///
/// Unsigned multiplication and assignment by a small number
///
///
private void MulInternal(uint n2)
{
int Length = digitArray.Length;
ulong n2long = (ulong)n2;
for (int i = 0; i < Length; i++)
{
workingSet[i] = 0;
}
for (int i = 0; i < Length; i++)
{
if (digitArray[i] == 0) continue;
ulong temp = (ulong)digitArray[i] * n2long;
digitArray[i] = (uint)(temp & 0xffffffff);
if (i + 1 < Length) workingSet[i + 1] = (uint)(temp >> 32);
}
AddInternalBits(workingSet);
}
///
/// Unsigned division and assignment by a small number
///
///
private void DivInternal(uint n2)
{
int Length = digitArray.Length;
ulong carry = 0;
//Divide each digit by the small number.
for (int i = Length - 1; i >= 0; i--)
{
ulong temp = (ulong)digitArray[i] + (carry << 32);
digitArray[i] = (uint)(temp / (ulong)n2);
carry = temp % (ulong)n2;
}
}
///
/// Adds a signed integer to the number.
///
///
private void AddInternal(int n1)
{
if (n1 < 0)
{
SubInternal(-n1);
return;
}
uint carry = 0;
int length = digitArray.Length;
for (int i = 0; i < length && !(n1 == 0 && carry == 0); i++)
{
uint temp = digitArray[i];
digitArray[i] += (uint)n1 + carry;
carry = (digitArray[i] <= temp) ? 1u: 0u;
n1 = 0;
}
}
///
/// Subtract a signed integer from the number.
/// This is internal because it will fail spectacularly if this number is negative or if n1 is bigger than this number.
///
///
private void SubInternal(int n1)
{
if (n1 < 0)
{
AddInternal(-n1);
return;
}
uint carry = 0;
int length = digitArray.Length;
for (int i = 0; i < length && !(n1 == 0 && carry == 0); i++)
{
uint temp = digitArray[i];
digitArray[i] -= ((uint)n1 + carry);
carry = (digitArray[i] >= temp) ? 1u: 0u;
n1 = 0;
}
}
///
/// Adds a signed integer to the number.
///
///
private bool AddInternal(uint n1)
{
uint carry = 0;
int length = digitArray.Length;
for (int i = 0; i < length && !(n1 == 0 && carry == 0); i++)
{
uint temp = digitArray[i];
digitArray[i] += n1 + carry;
carry = (digitArray[i] <= temp) ? 1u: 0u;
n1 = 0;
}
return (carry != 0);
}
///
/// Internally subtracts a uint from the number (sign insensitive)
///
///
///
private bool SubInternal(uint n1)
{
uint carry = 0;
int length = digitArray.Length;
for (int i = 0; i < length && !(n1 == 0 && carry == 0); i++)
{
uint temp = digitArray[i];
digitArray[i] -= (n1 + carry);
carry = (digitArray[i] >= temp) ? 1u: 0u;
n1 = 0;
}
return (carry != 0);
}
///
/// Internal increment function (sign insensitive)
///
private bool IncrementInt()
{
uint carry = 1;
int length = digitArray.Length;
for (int i = 0; i < length && carry != 0; i++)
{
uint temp = digitArray[i];
digitArray[i]++;
if (digitArray[i] > temp) carry = 0;
}
return (carry != 0);
}
///
/// Internal increment function (sign insensitive)
///
private bool DecrementInt()
{
uint carry = 1;
int length = digitArray.Length;
for (int i = 0; i < length && carry != 0; i++)
{
uint temp = digitArray[i];
digitArray[i]--;
if (digitArray[i] < temp) carry = 0;
}
return (carry != 0);
}
///
/// Used to add a digit array to a big int.
///
///
private uint AddInternalBits(uint[] digitsToAdd)
{
uint carry = 0;
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
//Necessary because otherwise the carry calculation could go bad.
if (digitsToAdd[i] == 0 && carry == 0) continue;
uint temp = digitArray[i];
digitArray[i] += (digitsToAdd[i] + carry);
carry = 0;
if (digitArray[i] <= temp) carry = 1;
}
return carry;
}
///
/// Used to add with matching signs (true addition of the digit arrays)
/// This is internal because it will fail spectacularly if n1 is negative.
///
///
private uint AddInternal(BigInt n1)
{
return AddInternalBits(n1.digitArray);
}
private uint SubInternalBits(uint[] digitsToAdd)
{
uint carry = 0;
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
//Necessary because otherwise the carry calculation could go bad.
if (digitsToAdd[i] == 0 && carry == 0) continue;
uint temp = digitArray[i];
digitArray[i] -= (digitsToAdd[i] + carry);
carry = 0;
if (digitArray[i] >= temp) carry = 1;
}
return carry;
}
///
/// Used to subtract n1 (true subtraction of digit arrays) - n1 must be less than or equal to this number
///
///
private uint SubInternal(BigInt n1)
{
return SubInternalBits(n1.digitArray);
}
///
/// Returns the length of the BigInt in 32-bit words for a given decimal precision
///
///
///
private static int GetRequiredDigitsForPrecision(PrecisionSpec precision)
{
int bits = precision.NumBits;
return ((bits - 1) >> 5) + 1;
}
///
/// Initialises the BigInt to a desired decimal precision
///
///
private void Init(PrecisionSpec precision)
{
int numDigits = GetRequiredDigitsForPrecision(precision);
digitArray = new uint[numDigits];
workingSet = new uint[numDigits];
pres = precision;
}
///
/// Initialises the BigInt from a string, given a base and precision
///
///
///
///
private void InitFromString(string init, PrecisionSpec precision, int numberBase)
{
PrecisionSpec test;
if (numberBase == 2)
{
test = new PrecisionSpec(init.Length, PrecisionSpec.BaseType.BIN);
}
else if (numberBase == 8)
{
test = new PrecisionSpec(init.Length, PrecisionSpec.BaseType.OCT);
}
else if (numberBase == 10)
{
test = new PrecisionSpec(init.Length, PrecisionSpec.BaseType.DEC);
}
else if (numberBase == 16)
{
test = new PrecisionSpec(init.Length, PrecisionSpec.BaseType.HEX);
}
else
{
throw new ArgumentOutOfRangeException();
}
//if (test.NumBits > precision.NumBits) precision = test;
Init(precision);
FromStringInt(init, numberBase);
}
//************ Helper Functions for floating point *************
///
/// Returns true if only the top bit is set: i.e. if the floating-point number is a power of 2
///
///
public bool IsTopBitOnlyBit()
{
int length = digitArray.Length;
if (digitArray[length - 1] != 0x80000000u) return false;
length--;
for (int i = 0; i < length; i++)
{
if (digitArray[i] != 0) return false;
}
return true;
}
///
/// Zeroes the n most significant bits of the number
///
///
public void ZeroBitsHigh(int bits)
{
//Already done.
if (bits <= 0) return;
int length = digitArray.Length;
//The entire digit array.
if ((bits >> 5) > length)
{
bits = length << 5;
}
int remBits = (bits & 31);
int startDigit = length - ((bits >> 5) + 1);
if (remBits != 0)
{
digitArray[startDigit] = digitArray[startDigit] & (0xffffffffu >> remBits);
}
for (int i = startDigit + 1; i < length; i++)
{
digitArray[i] = 0;
}
}
///
/// Zeroes the least-significant n bits.
///
///
public void ZeroBits(int bits)
{
//Already done.
if (bits <= 0) return;
//The entire digit array.
if ((bits >> 5) > digitArray.Length)
{
bits = digitArray.Length << 5;
}
int remBits = (bits & 31);
int startDigit = bits >> 5;
if (remBits != 0)
{
UInt32 startMask = 0xffffffffu & ~(UInt32)(((1 << remBits) - 1));
digitArray[startDigit] = digitArray[startDigit] & startMask;
}
for (int i = startDigit - 1; i >= 0; i--)
{
digitArray[i] = 0;
}
}
///
/// Sets the number to 0
///
public void Zero()
{
int length = digitArray.Length;
for (int i = 0; i < length; i++)
{
digitArray[i] = 0;
}
}
///
/// Rounds off the least significant bits of the number.
/// Can only round off up to 31 bits.
///
/// number of bits to round
///
public bool Round(int bits)
{
//Always less than 32 bits, please!
if (bits < 32)
{
uint pow2 = 1u << bits;
uint test = digitArray[0] & (pow2 >> 1);
//Zero the lower bits
digitArray[0] = digitArray[0] & ~(pow2 - 1);
if (test != 0)
{
bool bRet = AddInternal(pow2);
digitArray[digitArray.Length - 1] = digitArray[digitArray.Length - 1] | 0x80000000;
return bRet;
}
}
return false;
}
///
/// Used for casting between BigFloats of different precisions - this assumes
/// that the number is a normalised mantissa.
///
///
/// true if a round-up caused the high bits to become zero
public bool AssignHigh(BigInt n2)
{
int length = digitArray.Length;
int length2 = n2.digitArray.Length;
int minWords = (length < length2) ? length: length2;
bool bRet = false;
for (int i = 1; i <= minWords; i++)
{
digitArray[length - i] = n2.digitArray[length2 - i];
}
if (length2 > length && n2.digitArray[length2 - (length + 1)] >= 0x80000000)
{
bRet = IncrementInt();
//Because we are assuming normalisation, we set the top bit (it will already be set if
//bRet is false.
digitArray[length - 1] = digitArray[length - 1] | 0x80000000;
}
sign = n2.sign;
return bRet;
}
///
/// Used for casting between long ints or doubles and floating-point numbers
///
///
public void SetHighDigits(Int64 digits)
{
digitArray[digitArray.Length - 1] = (uint)(digits >> 32);
if (digitArray.Length > 1) digitArray[digitArray.Length - 2] = (uint)(digits & 0xffffffff);
}
///
/// Used for casting between ints and doubles or floats.
///
///
public void SetHighDigit(UInt32 digit)
{
digitArray[digitArray.Length - 1] = digit;
}
///
/// Helper function for floating-point - extends the number to twice the precision
/// and shifts the digits into the upper bits.
///
public void Pad()
{
int length = digitArray.Length;
int digits = length << 1;
UInt32[] newDigitArray = new UInt32[digits];
workingSet = new UInt32[digits];
for (int i = 0; i < length; i++)
{
newDigitArray[i + length] = digitArray[i];
}
digitArray = newDigitArray;
}
///
/// Helper function for floating-point - extends the number to twice the precision...
/// This is a necessary step in floating-point division.
///
public void Extend()
{
SetNumDigits(digitArray.Length * 2);
}
///
/// Gets the highest big of the integer (used for floating point stuff)
///
///
public uint GetTopBit()
{
return (digitArray[digitArray.Length - 1] >> 31);
}
///
/// Used for floating point multiplication, this shifts the number so that
/// the highest bit is set, and returns the number of places shifted.
///
///
public int Normalise()
{
if (IsZero()) return 0;
int MSD = GetMSD();
int digitShift = (digitArray.Length - (MSD + 1));
int bitShift = (31 - GetMSB(digitArray[MSD])) + (digitShift << 5);
LSH(bitShift);
return bitShift;
}
///
/// Gets the most significant bit
///
/// the input to search for the MSB in
/// -1 if the input was zero, the position of the MSB otherwise
public static int GetMSB(UInt32 value)
{
if (value == 0) return -1;
uint mask1 = 0xffff0000;
uint mask2 = 0xff00;
uint mask3 = 0xf0;
uint mask4 = 0xc; //1100 in binary
uint mask5 = 0x2; //10 in binary
int iPos = 0;
//Unrolled binary search for the most significant bit.
if ((value & mask1) != 0) iPos += 16;
mask2 <<= iPos;
if ((value & mask2) != 0) iPos += 8;
mask3 <<= iPos;
if ((value & mask3) != 0) iPos += 4;
mask4 <<= iPos;
if ((value & mask4) != 0) iPos += 2;
mask5 <<= iPos;
if ((value & mask5) != 0) iPos++;
return iPos;
}
///
/// Gets the most significant bit
///
/// the input to search for the MSB in
/// -1 if the input was zero, the position of the MSB otherwise
public static int GetMSB(UInt64 value)
{
if (value == 0) return -1;
UInt64 mask0 = 0xffffffff00000000ul;
UInt64 mask1 = 0xffff0000;
UInt64 mask2 = 0xff00;
UInt64 mask3 = 0xf0;
UInt64 mask4 = 0xc; //1100 in binary
UInt64 mask5 = 0x2; //10 in binary
int iPos = 0;
//Unrolled binary search for the most significant bit.
if ((value & mask0) != 0) iPos += 32;
mask1 <<= iPos;
if ((value & mask1) != 0) iPos += 16;
mask2 <<= iPos;
if ((value & mask2) != 0) iPos += 8;
mask3 <<= iPos;
if ((value & mask3) != 0) iPos += 4;
mask4 <<= iPos;
if ((value & mask4) != 0) iPos += 2;
mask5 <<= iPos;
if ((value & mask5) != 0) iPos++;
return iPos;
}
///
/// Gets the most significant bit
///
/// the input to search for the MSB in
/// -1 if the input was zero, the position of the MSB otherwise
public static int GetMSB(BigInt value)
{
int digit = value.GetMSD();
int bit = GetMSB(value.digitArray[digit]);
return (digit << 5) + bit;
}
//**************** Helper Functions for Div ********************
///
/// Gets the index of the most significant digit
///
///
private int GetMSD()
{
for (int i = digitArray.Length - 1; i >= 0; i--)
{
if (digitArray[i] != 0) return i;
}
return 0;
}
///
/// Gets the required bitshift for the Div_32 algorithm
///
///
private int GetDivBitshift()
{
uint digit = digitArray[GetMSD()];
uint mask1 = 0xffff0000;
uint mask2 = 0xff00;
uint mask3 = 0xf0;
uint mask4 = 0xc; //1100 in binary
uint mask5 = 0x2; //10 in binary
int iPos = 0;
//Unrolled binary search for the most significant bit.
if ((digit & mask1) != 0) iPos += 16;
mask2 <<= iPos;
if ((digit & mask2) != 0) iPos += 8;
mask3 <<= iPos;
if ((digit & mask3) != 0) iPos += 4;
mask4 <<= iPos;
if ((digit & mask4) != 0) iPos += 2;
mask5 <<= iPos;
if ((digit & mask5) != 0) return 30 - iPos;
return 31 - iPos;
}
///
/// Shifts and optionally precision-extends the arguments to prepare for Div_32
///
///
///
private static int MakeSafeDiv(BigInt n1, BigInt n2)
{
int shift = n2.GetDivBitshift();
int n1MSD = n1.GetMSD();
uint temp = n1.digitArray[n1MSD];
if (n1MSD == n1.digitArray.Length - 1 && ((temp << shift) >> shift) != n1.digitArray[n1MSD])
{
//Precision-extend n1 and n2 if necessary
int digits = n1.digitArray.Length;
n1.SetNumDigits(digits + 1);
n2.SetNumDigits(digits + 1);
}
//Logical left-shift n1 and n2
n1.LSH(shift);
n2.LSH(shift);
return shift;
}
///
/// Schoolbook division helper function.
///
///
///
/// Quotient output value
/// Remainder output value
private static void Div_31(BigInt n1, BigInt n2, BigInt Q, BigInt R)
{
int digitsN1 = n1.GetMSD() + 1;
int digitsN2 = n2.GetMSD() + 1;
if ((digitsN1 > digitsN2))
{
BigInt n1New = new BigInt(n2);
n1New.DigitShiftSelfLeft(1);
//If n1 >= n2 * 2^32
if (!LtInt(n1, n1New))
{
n1New.sign = n1.sign;
SubFast(n1New, n1, n1New);
Div_32(n1New, n2, Q, R);
//Q = (A - B*2^32)/B + 2^32
Q.Add2Pow32Self();
return;
}
}
UInt32 q = 0;
if (digitsN1 >= 2)
{
UInt64 q64 = ((((UInt64)n1.digitArray[digitsN1 - 1]) << 32) + n1.digitArray[digitsN1 - 2]) / (UInt64)n2.digitArray[digitsN2 - 1];
if (q64 > 0xfffffffful)
{
q = 0xffffffff;
}
else
{
q = (UInt32)q64;
}
}
BigInt temp = Mul(n2, q);
if (GtInt(temp, n1))
{
temp.SubInternalBits(n2.digitArray);
q--;
if (GtInt(temp, n1))
{
temp.SubInternalBits(n2.digitArray);
q--;
}
}
Q.Zero();
Q.digitArray[0] = q;
R.Assign(n1);
R.SubInternalBits(temp.digitArray);
}
///
/// Schoolbook division algorithm
///
///
///
///
///
private static void Div_32(BigInt n1, BigInt n2, BigInt Q, BigInt R)
{
int digitsN1 = n1.GetMSD() + 1;
int digitsN2 = n2.GetMSD() + 1;
//n2 is bigger than n1
if (digitsN1 < digitsN2)
{
R.AssignInt(n1);
Q.Zero();
return;
}
if (digitsN1 == digitsN2)
{
//n2 is bigger than n1
if (LtInt(n1, n2))
{
R.AssignInt(n1);
Q.Zero();
return;
}
//n2 >= n1, but less the 2x n1 (initial conditions make this certain)
Q.Zero();
Q.digitArray[0] = 1;
R.Assign(n1);
R.SubInternalBits(n2.digitArray);
return;
}
int digits = digitsN1 - (digitsN2 + 1);
//Algorithm Div_31 can be used to get the answer in O(n) time.
if (digits == 0)
{
Div_31(n1, n2, Q, R);
return;
}
BigInt n1New = DigitShiftRight(n1, digits);
BigInt s = DigitTruncate(n1, digits);
BigInt Q2 = new BigInt(n1, n1.pres, true);
BigInt R2 = new BigInt(n1, n1.pres, true);
Div_31(n1New, n2, Q2, R2);
R2.DigitShiftSelfLeft(digits);
R2.Add(s);
Div_32(R2, n2, Q, R);
Q2.DigitShiftSelfLeft(digits);
Q.Add(Q2);
}
///
/// Sets the n-th bit of the number to 1
///
/// the index of the bit to set
public void SetBit(int bit)
{
int digit = (bit >> 5);
if (digit >= digitArray.Length) return;
digitArray[digit] = digitArray[digit] | (1u << (bit - (digit << 5)));
}
///
/// Sets the n-th bit of the number to 0
///
/// the index of the bit to set
public void ClearBit(int bit)
{
int digit = (bit >> 5);
if (digit >= digitArray.Length) return;
digitArray[digit] = digitArray[digit] & (~(1u << (bit - (digit << 5))));
}
///
/// Returns the n-th bit, counting from the MSB to the LSB
///
/// the index of the bit to return
/// 1 if the bit is 1, 0 otherwise
public uint GetBitFromTop(int bit)
{
if (bit < 0) return 0;
int wordCount = (bit >> 5);
int upBit = 31 - (bit & 31);
if (wordCount >= digitArray.Length) return 0;
return ((digitArray[digitArray.Length - (wordCount + 1)] & (1u << upBit)) >> upBit);
}
///
/// Assigns n2 to 'this'
///
///
public void Assign(BigInt n2)
{
if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);
sign = n2.sign;
AssignInt(n2);
}
///
/// Assign n2 to 'this', safe only if precision-matched
///
///
///
private void AssignInt(BigInt n2)
{
int Length = digitArray.Length;
for (int i = 0; i < Length; i++)
{
digitArray[i] = n2.digitArray[i];
}
}
private static BigInt DigitShiftRight(BigInt n1, int digits)
{
BigInt res = new BigInt(n1);
int Length = res.digitArray.Length;
for (int i = 0; i < Length - digits; i++)
{
res.digitArray[i] = res.digitArray[i + digits];
}
for (int i = Length - digits; i < Length; i++)
{
res.digitArray[i] = 0;
}
return res;
}
private void DigitShiftSelfRight(int digits)
{
for (int i = digits; i < digitArray.Length; i++)
{
digitArray[i - digits] = digitArray[i];
}
for (int i = digitArray.Length - digits; i < digitArray.Length; i++)
{
digitArray[i] = 0;
}
}
private void DigitShiftSelfLeft(int digits)
{
for (int i = digitArray.Length - 1; i >= digits; i--)
{
digitArray[i] = digitArray[i - digits];
}
for (int i = digits - 1; i >= 0; i--)
{
digitArray[i] = 0;
}
}
private static BigInt DigitTruncate(BigInt n1, int digits)
{
BigInt res = new BigInt(n1);
for (int i = res.digitArray.Length - 1; i >= digits; i--)
{
res.digitArray[i] = 0;
}
return res;
}
private void Add2Pow32Self()
{
int Length = digitArray.Length;
uint carry = 1;
for (int i = 1; i < Length; i++)
{
uint temp = digitArray[i];
digitArray[i] += carry;
if (digitArray[i] > temp) return;
}
return;
}
///
/// Sets the number of digits without changing the precision
/// This method is made public only to facilitate fixed-point operations
/// It should under no circumstances be used for anything else, because
/// it breaks the BigNum(PrecisionSpec precision) constructor in dangerous
/// and unpredictable ways.
///
///
public void SetNumDigits(int digits)
{
if (digits == digitArray.Length) return;
UInt32[] newDigitArray = new UInt32[digits];
workingSet = new UInt32[digits];
int numCopy = (digits < digitArray.Length) ? digits : digitArray.Length;
for (int i = 0; i < numCopy; i++)
{
newDigitArray[i] = digitArray[i];
}
digitArray = newDigitArray;
}
//********************** Explicit casts ***********************
///
/// Cast to int
///
///
///
public static explicit operator Int32(BigInt value)
{
if (value.digitArray[0] == 0x80000000 && value.sign) return Int32.MinValue;
int res = (int)(value.digitArray[0] & 0x7fffffff);
if (value.sign) res = -res;
return res;
}
///
/// explicit cast to unsigned int.
///
///
///
public static explicit operator UInt32(BigInt value)
{
if (value.sign) return (UInt32)((Int32)(value));
return (UInt32)value.digitArray[0];
}
///
/// explicit cast to 64-bit signed integer.
///
///
///
public static explicit operator Int64(BigInt value)
{
if (value.digitArray.Length < 2) return (value.sign ? -((Int64)value.digitArray[0]): ((Int64)value.digitArray[0]));
UInt64 ret = (((UInt64)value.digitArray[1]) << 32) + (UInt64)value.digitArray[0];
if (ret == 0x8000000000000000L && value.sign) return Int64.MinValue;
Int64 signedRet = (Int64)(ret & 0x7fffffffffffffffL);
if (value.sign) signedRet = -signedRet;
return signedRet;
}
///
/// Explicit cast to UInt64
///
///
///
public static explicit operator UInt64(BigInt value)
{
if (value.sign) return (UInt64)((Int64)(value));
if (value.digitArray.Length < 2) return (UInt64)value.digitArray[0];
return ((((UInt64)value.digitArray[1]) << 32) + (UInt64)value.digitArray[0]);
}
///
/// Cast to string
///
///
///
public static explicit operator string(BigInt value)
{
return value.ToString();
}
///
/// Cast from string - this is not wholly safe, because precision is not
/// specified. You should try to construct a BigInt with the appropriate
/// constructor instead.
///
/// The decimal string to convert to a BigInt
/// A BigInt of the precision required to encompass the string
public static explicit operator BigInt(string value)
{
return new BigInt(value);
}
//********************* ToString members **********************
///
/// Converts this to a string, in the specified base
///
/// the base to use (min 2, max 16)
/// a string representation of the number
public string ToString(int numberBase)
{
char[] digitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
string output = "";
BigInt clone = new BigInt(this);
clone.sign = false;
int numDigits = 0;
while (!clone.IsZero())
{
if (numberBase == 10 && (numDigits % 3) == 0 && numDigits != 0)
{
output = String.Format(",{0}", output);
}
else if (numberBase != 10 && (numDigits % 8) == 0 && numDigits != 0)
{
output = String.Format(" {0}", output);
}
BigInt div, mod;
DivMod(clone, (uint)numberBase, out div, out mod);
int iMod = (int)mod;
output = String.Format("{0}{1}", digitChars[(int)mod], output);
numDigits++;
clone = div;
}
if (output.Length == 0) output = String.Format("0");
if (sign) output = String.Format("-{0}", output);
return output;
}
///
/// Converts the number to a string, in base 10
///
/// a string representation of the number in base 10
public override string ToString()
{
return ToString(10);
}
//***************** Internal helper functions *****************
private void FromStringInt(string init, int numberBase)
{
char [] digitChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
string formattedInput = init.Trim().ToUpper();
for (int i = 0; i < formattedInput.Length; i++)
{
int digitIndex = Array.IndexOf(digitChars, formattedInput[i]);
//Skip fractional part altogether
if (formattedInput[i] == '.') break;
//skip non-digit characters.
if (digitIndex < 0) continue;
//Multiply
MulInternal((uint)numberBase);
//Add
AddInternal(digitIndex);
}
if (init.Length > 0 && init[0] == '-') sign = true;
}
///
/// Sign-insensitive less than comparison.
/// unsafe if n1 and n2 disagree in precision
///
///
///
///
private static bool LtInt(BigInt n1, BigInt n2)
{
//MakeSafe(ref n1, ref n2);
for (int i = n1.digitArray.Length - 1; i >= 0; i--)
{
if (n1.digitArray[i] < n2.digitArray[i]) return true;
if (n1.digitArray[i] > n2.digitArray[i]) return false;
}
//equal
return false;
}
///
/// Sign-insensitive greater than comparison.
/// unsafe if n1 and n2 disagree in precision
///
///
///
///
private static bool GtInt(BigInt n1, BigInt n2)
{
//MakeSafe(ref n1, ref n2);
for (int i = n1.digitArray.Length - 1; i >= 0; i--)
{
if (n1.digitArray[i] > n2.digitArray[i]) return true;
if (n1.digitArray[i] < n2.digitArray[i]) return false;
}
//equal
return false;
}
///
/// Makes sure the numbers have matching precisions
///
///
///
private static void MakeSafe(ref BigInt n1, ref BigInt n2)
{
if (n1.digitArray.Length == n2.digitArray.Length)
{
return;
}
else if (n1.digitArray.Length > n2.digitArray.Length)
{
n2 = new BigInt(n2, n1.pres);
}
else
{
n1 = new BigInt(n1, n2.pres);
}
}
///
/// Makes sure the numbers have matching precisions
///
/// the number to match to this
private void MakeSafe(ref BigInt n2)
{
n2 = new BigInt(n2, pres);
n2.SetNumDigits(digitArray.Length);
}
private PrecisionSpec pres;
private bool sign;
private uint[] digitArray;
private uint[] workingSet;
}
}