/// <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); }
/// <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); }
/// <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> /// Shifts and optionally precision-extends the arguments to prepare for Div_32 /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> private static int MakeSafeDiv(BigInt n1, BigInt n2) { int shift = n2.GetDivBitshift(); int n1MSD = n1.GetMSD(); uint temp = n1.digitArray[n1MSD]; if (n1MSD == n1.digitArray.Length - 1 && ((temp << shift) >> shift) != n1.digitArray[n1MSD]) { //Precision-extend n1 and n2 if necessary int digits = n1.digitArray.Length; n1.SetNumDigits(digits + 1); n2.SetNumDigits(digits + 1); } //Logical left-shift n1 and n2 n1.LSH(shift); n2.LSH(shift); return shift; }