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