/// <summary> /// Assigns n2 to 'this' /// </summary> /// <param name="n2"></param> public void Assign(BigInt n2) { if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2); sign = n2.sign; AssignInt(n2); }
/// <summary> /// Constructs a BigFloat from a BigInt, using the specified precision /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(BigInt value, PrecisionSpec mantissaPrec) { if (value.IsZero()) { Init(mantissaPrec); SetZero(); return; } mantissa = new BigInt(value, mantissaPrec); exponent = BigInt.GetMSB(value); mantissa.Normalise(); }
private void Init(PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; mantissa = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); }
private void Exp(int numBits) { if (IsSpecialValue) { if (SpecialValue == SpecialValueType.ZERO) { //e^0 = 1 exponent = 0; mantissa.SetHighDigit(0x80000000); } else if (SpecialValue == SpecialValueType.INF_MINUS) { //e^-inf = 0 SetZero(); } return; } PrecisionSpec prec = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); numBits = prec.NumBits; if (scratch.Precision.NumBits != prec.NumBits) { scratch = new BigInt(prec); } if (inverseFactorialCache == null || invFactorialCutoff < numBits) { CalculateFactorials(numBits); } //let x = 1 * 'this'.mantissa (i.e. 1 <= x < 2) //exp(2^n * x) = e^(2^n * x) = (e^x)^2n = exp(x)^2n int oldExponent = 0; if (exponent > -4) { oldExponent = exponent + 4; exponent = -4; } BigFloat thisSave = new BigFloat(this, prec); BigFloat temp = new BigFloat(1, prec); BigFloat temp2 = new BigFloat(this, prec); BigFloat res = new BigFloat(1, prec); int length = inverseFactorialCache.Length; int iterations; for (int i = 1; i < length; i++) { //temp = x^i temp.Mul(thisSave); temp2.Assign(inverseFactorialCache[i]); temp2.Mul(temp); if (temp2.exponent < -(numBits + 4)) { iterations = i; break; } res.Add(temp2); } //res = exp(x) //Now... x^(2^n) = (x^2)^(2^(n - 1)) for (int i = 0; i < oldExponent; i++) { res.mantissa.SquareHiFast(scratch); int shift = res.mantissa.Normalise(); res.exponent = res.exponent << 1; res.exponent += 1 - shift; } //Deal with +/- inf if (res.exponent == Int32.MaxValue) { res.mantissa.Zero(); } Assign(res); }
/// <summary> /// Constructs a BigFloat from a 64-bit integer /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(Int64 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; UInt64 uValue; if (value < 0) { if (value == Int64.MinValue) { uValue = 0x80000000; } else { uValue = (UInt64)(-value); } } else { uValue = (UInt64)value; } mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); int bit = BigInt.GetMSB(uValue); if (bit == -1) return; int shift = mantissa.Precision.NumBits - (bit + 1); if (shift > 0) { mantissa.LSH(shift); } else { mantissa.SetHighDigit((uint)(uValue >> (-shift))); } exponent = bit; }
/// <summary> /// Returns a base-10 string representing the number. /// /// Note: This is inefficient and possibly inaccurate. Please use with enough /// rounding digits (set using the RoundingDigits property) to ensure accuracy /// </summary> public override string ToString() { if (IsSpecialValue) { SpecialValueType s = SpecialValue; if (s == SpecialValueType.ZERO) { return String.Format("0{0}0", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); } else if (s == SpecialValueType.INF_PLUS) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PositiveInfinitySymbol; } else if (s == SpecialValueType.INF_MINUS) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeInfinitySymbol; } else if (s == SpecialValueType.NAN) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NaNSymbol; } else { return "Unrecognised special type"; } } if (scratch.Precision.NumBits != mantissa.Precision.NumBits) { scratch = new BigInt(mantissa.Precision); } //The mantissa expresses 1.xxxxxxxxxxx //The highest possible value for the mantissa without the implicit 1. is 0.9999999... scratch.Assign(mantissa); //scratch.Round(3); scratch.Sign = false; BigInt denom = new BigInt("0", mantissa.Precision); denom.SetBit(mantissa.Precision.NumBits - 1); bool useExponentialNotation = false; int halfBits = mantissa.Precision.NumBits / 2; if (halfBits > 60) halfBits = 60; int precDec = 10; if (exponent > 0) { if (exponent < halfBits) { denom.RSH(exponent); } else { useExponentialNotation = true; } } else if (exponent < 0) { int shift = -(exponent); if (shift < precDec) { scratch.RSH(shift); } else { useExponentialNotation = true; } } string output; if (useExponentialNotation) { int absExponent = exponent; if (absExponent < 0) absExponent = -absExponent; int powerOf10 = (int)((double)absExponent * Math.Log10(2.0)); //Use 1 extra digit of precision (this is actually 32 bits more, nb) BigFloat thisFloat = new BigFloat(this, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); thisFloat.mantissa.Sign = false; //Multiplicative correction factor to bring number into range. BigFloat one = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat ten = new BigFloat(10, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat tenRCP = ten.Reciprocal(); //Accumulator for the power of 10 calculation. BigFloat acc = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat tenToUse; if (exponent > 0) { tenToUse = new BigFloat(tenRCP, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); } else { tenToUse = new BigFloat(ten, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); } BigFloat tenToPower = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); int powerTemp = powerOf10; //Fast power function while (powerTemp != 0) { tenToPower.Mul(tenToUse); tenToUse.Assign(tenToPower); if ((powerTemp & 1) != 0) { acc.Mul(tenToPower); } powerTemp >>= 1; } thisFloat.Mul(acc); //If we are out of range, correct. if (thisFloat.GreaterThan(ten)) { thisFloat.Mul(tenRCP); if (exponent > 0) { powerOf10++; } else { powerOf10--; } } else if (thisFloat.LessThan(one)) { thisFloat.Mul(ten); if (exponent > 0) { powerOf10--; } else { powerOf10++; } } //Restore the precision and the sign. BigFloat printable = new BigFloat(thisFloat, mantissa.Precision); printable.mantissa.Sign = mantissa.Sign; output = printable.ToString(); if (exponent < 0) powerOf10 = -powerOf10; output = String.Format("{0}E{1}", output, powerOf10); } else { BigInt bigDigit = BigInt.Div(scratch, denom); bigDigit.Sign = false; scratch.Sub(BigInt.Mul(denom, bigDigit)); if (mantissa.Sign) { output = String.Format("-{0}.", bigDigit); } else { output = String.Format("{0}.", bigDigit); } denom = BigInt.Div(denom, 10u); while (!denom.IsZero()) { uint digit = (uint)BigInt.Div(scratch, denom); if (digit == 10) digit--; scratch.Sub(BigInt.Mul(denom, digit)); output = String.Format("{0}{1}", output, digit); denom = BigInt.Div(denom, 10u); } output = RoundString(output, RoundingDigits); } return output; }
/// <summary> /// Constructs a big float from a UInt32 to the required precision /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(UInt32 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(mantissa.Precision); int bit = BigInt.GetMSB(value); if (bit == -1) return; int shift = mantissa.Precision.NumBits - (bit + 1); mantissa.LSH(shift); exponent = bit; }
/// <summary> /// Sign-insensitive greater than comparison. /// unsafe if n1 and n2 disagree in precision /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> /// <returns></returns> 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; }
/// <summary> /// Makes sure the numbers have matching precisions /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> 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); } }
/// <summary> /// Constructs a bigint from the input, matching the new precision provided /// </summary> 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; }
//********************* ToString members ********************** /// <summary> /// Converts this to a string, in the specified base /// </summary> /// <param name="numberBase">the base to use (min 2, max 16)</param> /// <returns>a string representation of the number</returns> 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; }
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 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; }
/// <summary> /// Assign n2 to 'this', safe only if precision-matched /// </summary> /// <param name="n2"></param> /// <returns></returns> private void AssignInt(BigInt n2) { int Length = digitArray.Length; for (int i = 0; i < Length; i++) { digitArray[i] = n2.digitArray[i]; } }
/// <summary> /// Calculates 'this'^power /// </summary> /// <param name="power"></param> 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); }
/// <summary> /// Makes sure the numbers have matching precisions /// </summary> /// <param name="n2">the number to match to this</param> private void MakeSafe(ref BigInt n2) { n2 = new BigInt(n2, pres); n2.SetNumDigits(digitArray.Length); }
//************************** Conversions ************************* /// <summary> /// Converts a BigFloat to an BigInt with the specified precision /// </summary> /// <param name="n1">The number to convert</param> /// <param name="precision">The precision to convert it with</param> /// <param name="round">Do we round the number if we are truncating the mantissa?</param> /// <returns></returns> public static BigInt ConvertToInt(BigFloat n1, PrecisionSpec precision, bool round) { BigInt ret = new BigInt(precision); int numBits = n1.mantissa.Precision.NumBits; int shift = numBits - (n1.exponent + 1); BigFloat copy = new BigFloat(n1); bool inc = false; //Rounding if (copy.mantissa.Precision.NumBits > ret.Precision.NumBits) { inc = true; for (int i = copy.exponent + 1; i <= ret.Precision.NumBits; i++) { if (copy.mantissa.GetBitFromTop(i) == 0) { inc = false; break; } } } if (shift > 0) { copy.mantissa.RSH(shift); } else if (shift < 0) { copy.mantissa.LSH(-shift); } ret.Assign(copy.mantissa); if (inc) ret.Increment(); return ret; }
//*************** Utility Functions ************** /// <summary> /// Casts a BigInt to the new precision provided. /// Note: This will return the input if the precision already matches. /// </summary> /// <param name="input"></param> /// <param name="precision"></param> /// <returns></returns> public static BigInt CastToPrecision(BigInt input, PrecisionSpec precision) { if (input.pres == precision) return input; return new BigInt(input, precision); }
//************************ Constructors ************************** /// <summary> /// Constructs a 128-bit BigFloat /// /// Sets the value to zero /// </summary> static BigFloat() { RoundingDigits = 3; RoundingMode = RoundingModeType.TRIM; scratch = new BigInt(new PrecisionSpec(128, PrecisionSpec.BaseType.BIN)); }
/// <summary> /// Subtraction and assignment - without intermediate memory allocation. /// </summary> /// <param name="n2"></param> 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); } } }
/// <summary> /// The binary logarithm, log2(x) - for precisions above 1000 bits, use Log() and convert the base. /// </summary> private void Log2() { if (scratch.Precision.NumBits != mantissa.Precision.NumBits) { scratch = new BigInt(mantissa.Precision); } int bits = mantissa.Precision.NumBits; BigFloat temp = new BigFloat(this); BigFloat result = new BigFloat(exponent, mantissa.Precision); BigFloat pow2 = new BigFloat(1, mantissa.Precision); temp.exponent = 0; int bitsCalculated = 0; while (bitsCalculated < bits) { int i; for (i = 0; (temp.exponent == 0); i++) { temp.mantissa.SquareHiFast(scratch); int shift = temp.mantissa.Normalise(); temp.exponent += 1 - shift; if (i + bitsCalculated >= bits) break; } pow2.MulPow2(-i); result.Add(pow2); temp.exponent = 0; bitsCalculated += i; } this.Assign(result); }
/// <summary> /// 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). /// </summary> /// <param name="n2"></param> 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); }
/// <summary> /// Uses the Gauss-Legendre formula for pi /// Taken from http://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm /// </summary> /// <param name="numBits"></param> private static void CalculatePi(int numBits) { int bits = numBits + 32; //Precision extend taken out. PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN); if (scratch.Precision.NumBits != bits) { scratch = new BigInt(extendedPres); } //a0 = 1 BigFloat an = new BigFloat(1, extendedPres); //b0 = 1/sqrt(2) BigFloat bn = new BigFloat(2, extendedPres); bn.Sqrt(); bn.exponent--; //to = 1/4 BigFloat tn = new BigFloat(1, extendedPres); tn.exponent -= 2; int pn = 0; BigFloat anTemp = new BigFloat(extendedPres); int iteration = 0; int cutoffBits = numBits >> 5; for (iteration = 0; ; iteration++) { //Save a(n) anTemp.Assign(an); //Calculate new an an.Add(bn); an.exponent--; //Calculate new bn bn.Mul(anTemp); bn.Sqrt(); //Calculate new tn anTemp.Sub(an); anTemp.mantissa.SquareHiFast(scratch); anTemp.exponent += anTemp.exponent + pn + 1 - anTemp.mantissa.Normalise(); tn.Sub(anTemp); anTemp.Assign(an); anTemp.Sub(bn); if (anTemp.exponent < -(bits - cutoffBits)) break; //New pn pn++; } an.Add(bn); an.mantissa.SquareHiFast(scratch); an.exponent += an.exponent + 1 - an.mantissa.Normalise(); tn.exponent += 2; an.Div(tn); pi = new BigFloat(an, normalPres); piBy2 = new BigFloat(pi); piBy2.exponent--; twoPi = new BigFloat(pi, normalPres); twoPi.exponent++; piRecip = new BigFloat(an.Reciprocal(), normalPres); twoPiRecip = new BigFloat(piRecip); twoPiRecip.exponent--; //1/3 is going to be useful for sin. threeRecip = new BigFloat((new BigFloat(3, extendedPres)).Reciprocal(), normalPres); }
/// <summary> /// Floating-point helper function. /// Squares the number and keeps the high bits of the calculation. /// Takes a temporary BigInt as a working set. /// </summary> 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; }
/// <summary> /// Constructs a BigFloat from a 64-bit unsigned integer /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(UInt64 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; int bit = BigInt.GetMSB(value); mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(mantissa.Precision); int shift = mantissa.Precision.NumBits - (bit + 1); if (shift > 0) { mantissa.LSH(shift); } else { mantissa.SetHighDigit((uint)(value >> (-shift))); } exponent = bit; }
/// <summary> /// This function is used for floating-point division. /// </summary> /// <param name="n2"></param> //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; }
/// <summary> /// Construct a BigFloat from a double-precision floating point number /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(double value, PrecisionSpec mantissaPrec) { if (value == 0.0) { Init(mantissaPrec); return; } bool sign = (value < 0) ? true : false; long bits = BitConverter.DoubleToInt64Bits(value); // Note that the shift is sign-extended, hence the test against -1 not 1 int valueExponent = (int)((bits >> 52) & 0x7ffL); long valueMantissa = bits & 0xfffffffffffffL; //The mantissa is stored with the top bit implied. valueMantissa = valueMantissa | 0x10000000000000L; //The exponent is biased by 1023. exponent = valueExponent - 1023; //Round the number of bits to the nearest word. int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; mantissa = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); if (newManBits >= 64) { //The mantissa is 53 bits now, so add 11 to put it in the right place. mantissa.SetHighDigits(valueMantissa << 11); } else { //To get the top word of the mantissa, shift up by 11 and down by 32 = down by 21 mantissa.SetHighDigit((uint)(valueMantissa >> 21)); } mantissa.Sign = sign; }
/// <summary> /// Calculates 'this' mod n2 (using the schoolbook division algorithm as above) /// </summary> /// <param name="n2"></param> 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); }
//******************** Arithmetic Functions ******************** /// <summary> /// Addition (this = this + n2) /// </summary> /// <param name="n2">The number to add</param> public void Add(BigFloat n2) { if (SpecialValueAddTest(n2)) return; if (scratch.Precision.NumBits != n2.mantissa.Precision.NumBits) { scratch = new BigInt(n2.mantissa.Precision); } if (exponent <= n2.exponent) { int diff = n2.exponent - exponent; exponent = n2.exponent; if (diff != 0) { mantissa.RSH(diff); } uint carry = mantissa.Add(n2.mantissa); if (carry != 0) { mantissa.RSH(1); mantissa.SetBit(mantissa.Precision.NumBits - 1); exponent++; } exponent -= mantissa.Normalise(); } else { int diff = exponent - n2.exponent; scratch.Assign(n2.mantissa); scratch.RSH(diff); uint carry = scratch.Add(mantissa); if (carry != 0) { scratch.RSH(1); scratch.SetBit(mantissa.Precision.NumBits - 1); exponent++; } mantissa.Assign(scratch); exponent -= mantissa.Normalise(); } }
/// <summary> /// Constructs a bigint from the input. /// </summary> /// <param name="input"></param> 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; }