/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult) { // Create some buffers if necessary if (digitsBuffer1 == null) { digitsBuffer1 = new uint[length1 + 1]; } if (digitsBuffer2 == null) { digitsBuffer2 = new uint[length2]; } fixed(uint *digitsPtr1 = digits1, digitsBufferPtr1 = digitsBuffer1, digitsPtr2 = digits2, digitsBufferPtr2 = digitsBuffer2, digitsResPtr = digitsRes != null?digitsRes : digits1) { return(DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr == digitsPtr1 ? null : digitsResPtr, resultFlags, cmpResult)); } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult) { // Create some buffers if necessary if (digitsBuffer1 == null) { digitsBuffer1 = new uint[length1 + 1]; } if (digitsBuffer2 == null) { digitsBuffer2 = new uint[length2]; } fixed (uint* digitsPtr1 = digits1, digitsBufferPtr1 = digitsBuffer1, digitsPtr2 = digits2, digitsBufferPtr2 = digitsBuffer2, digitsResPtr = digitsRes != null ? digitsRes : digits1) { return DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr == digitsPtr1 ? null : digitsResPtr, resultFlags, cmpResult); } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> abstract public uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult);
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> public unsafe override uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult) { // Maybe immediately use classic algorithm here if (IsClassicAlgorithmNeeded(length1, length2)) { return _classicDivider.DivMod( digits1, digitsBuffer1, ref length1, digits2, digitsBuffer2, length2, digitsRes, resultFlags, cmpResult); } // Create some buffers if necessary if (digitsBuffer1 == null) { digitsBuffer1 = new uint[length1 + 1]; } fixed (uint* digitsPtr1 = digits1, digitsBufferPtr1 = digitsBuffer1, digitsPtr2 = digits2, digitsBufferPtr2 = digitsBuffer2 != null ? digitsBuffer2 : digits1, digitsResPtr = digitsRes != null ? digitsRes : digits1) { return DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2 == digitsPtr1 ? null : digitsBufferPtr2, length2, digitsResPtr == digitsPtr1 ? null : digitsResPtr, resultFlags, cmpResult); } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult) { // Maybe immediately use classic algorithm here if (IsClassicAlgorithmNeeded(length1, length2)) { return(_classicDivider.DivMod( digits1, digitsBuffer1, ref length1, digits2, digitsBuffer2, length2, digitsRes, resultFlags, cmpResult)); } // Create some buffers if necessary if (digitsBuffer1 == null) { digitsBuffer1 = new uint[length1 + 1]; } fixed(uint *digitsPtr1 = digits1, digitsBufferPtr1 = digitsBuffer1, digitsPtr2 = digits2, digitsBufferPtr2 = digitsBuffer2 != null?digitsBuffer2 : digits1, digitsResPtr = digitsRes != null?digitsRes : digits1) { return(DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2 == digitsPtr1 ? null : digitsBufferPtr2, length2, digitsResPtr == digitsPtr1 ? null : digitsResPtr, resultFlags, cmpResult)); } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> public unsafe override uint DivMod( uint* digitsPtr1, uint* digitsBufferPtr1, ref uint length1, uint* digitsPtr2, uint* digitsBufferPtr2, uint length2, uint* digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Maybe immediately use classic algorithm here if (IsClassicAlgorithmNeeded(length1, length2)) { return _classicDivider.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult); } // Call base (for special cases) uint resultLength = base.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult); if (resultLength != uint.MaxValue) return resultLength; // First retrieve opposite for the divider uint int2OppositeLength; ulong int2OppositeRightShift; uint[] int2OppositeDigits = NewtonHelper.GetIntegerOpposite( digitsPtr2, length2, length1, digitsBufferPtr1, out int2OppositeLength, out int2OppositeRightShift); // We will need to muptiply it by divident now to receive quotient. // Prepare digits for multiply result uint quotLength; uint[] quotDigits = new uint[length1 + int2OppositeLength]; IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier(); // Fix some arrays fixed (uint* oppositePtr = int2OppositeDigits, quotPtr = quotDigits) { // Multiply quotLength = multiplier.Multiply( oppositePtr, int2OppositeLength, digitsPtr1, length1, quotPtr); // Calculate shift uint shiftOffset = (uint)(int2OppositeRightShift / Constants.DigitBitCount); int shiftCount = (int)(int2OppositeRightShift % Constants.DigitBitCount); // Get the very first bit of the shifted part uint highestLostBit; if (shiftCount == 0) { highestLostBit = quotPtr[shiftOffset - 1] >> 31; } else { highestLostBit = quotPtr[shiftOffset] >> (shiftCount - 1) & 1U; } // After this result must be shifted to the right - this is required quotLength = DigitOpHelper.Shr( quotPtr + shiftOffset, quotLength - shiftOffset, quotPtr, shiftCount, false); // Maybe quotient must be corrected if (highestLostBit == 1U) { quotLength = DigitOpHelper.Add(quotPtr, quotLength, &highestLostBit, 1U, quotPtr); } // Check quotient - finally it might be too big. // For this we must multiply quotient by divider uint quotDivLength; uint[] quotDivDigits = new uint[quotLength + length2]; fixed (uint* quotDivPtr = quotDivDigits) { quotDivLength = multiplier.Multiply(quotPtr, quotLength, digitsPtr2, length2, quotDivPtr); int cmpRes = DigitOpHelper.Cmp(quotDivPtr, quotDivLength, digitsPtr1, length1); if (cmpRes > 0) { highestLostBit = 1; quotLength = DigitOpHelper.Sub(quotPtr, quotLength, &highestLostBit, 1U, quotPtr); quotDivLength = DigitOpHelper.Sub(quotDivPtr, quotDivLength, digitsPtr2, length2, quotDivPtr); } // Now everything is ready and prepared to return results // First maybe fill remainder if ((resultFlags & DivModResultFlags.Mod) != 0) { length1 = DigitOpHelper.Sub(digitsPtr1, length1, quotDivPtr, quotDivLength, digitsBufferPtr1); } // And finally fill quotient if ((resultFlags & DivModResultFlags.Div) != 0) { DigitHelper.DigitsBlockCopy(quotPtr, digitsResPtr, quotLength); } else { quotLength = 0; } // Return some arrays to pool ArrayPool<uint>.Instance.AddArray(int2OppositeDigits); return quotLength; } } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint *digitsPtr1, uint *digitsBufferPtr1, ref uint length1, uint *digitsPtr2, uint *digitsBufferPtr2, uint length2, uint *digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Maybe immediately use classic algorithm here if (IsClassicAlgorithmNeeded(length1, length2)) { return(_classicDivider.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult)); } // Call base (for special cases) uint resultLength = base.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult); if (resultLength != uint.MaxValue) { return(resultLength); } // First retrieve opposite for the divider uint int2OppositeLength; ulong int2OppositeRightShift; uint[] int2OppositeDigits = NewtonHelper.GetIntegerOpposite( digitsPtr2, length2, length1, digitsBufferPtr1, out int2OppositeLength, out int2OppositeRightShift); // We will need to muptiply it by divident now to receive quotient. // Prepare digits for multiply result uint quotLength; uint[] quotDigits = new uint[length1 + int2OppositeLength]; IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier(); // Fix some arrays fixed(uint *oppositePtr = int2OppositeDigits, quotPtr = quotDigits) { // Multiply quotLength = multiplier.Multiply( oppositePtr, int2OppositeLength, digitsPtr1, length1, quotPtr); // Calculate shift uint shiftOffset = (uint)(int2OppositeRightShift / Constants.DigitBitCount); int shiftCount = (int)(int2OppositeRightShift % Constants.DigitBitCount); // Get the very first bit of the shifted part uint highestLostBit; if (shiftCount == 0) { highestLostBit = quotPtr[shiftOffset - 1] >> 31; } else { highestLostBit = quotPtr[shiftOffset] >> (shiftCount - 1) & 1U; } // After this result must be shifted to the right - this is required quotLength = DigitOpHelper.Shr( quotPtr + shiftOffset, quotLength - shiftOffset, quotPtr, shiftCount, false); // Maybe quotient must be corrected if (highestLostBit == 1U) { quotLength = DigitOpHelper.Add(quotPtr, quotLength, &highestLostBit, 1U, quotPtr); } // Check quotient - finally it might be too big. // For this we must multiply quotient by divider uint quotDivLength; uint[] quotDivDigits = new uint[quotLength + length2]; fixed(uint *quotDivPtr = quotDivDigits) { quotDivLength = multiplier.Multiply(quotPtr, quotLength, digitsPtr2, length2, quotDivPtr); int cmpRes = DigitOpHelper.Cmp(quotDivPtr, quotDivLength, digitsPtr1, length1); if (cmpRes > 0) { highestLostBit = 1; quotLength = DigitOpHelper.Sub(quotPtr, quotLength, &highestLostBit, 1U, quotPtr); quotDivLength = DigitOpHelper.Sub(quotDivPtr, quotDivLength, digitsPtr2, length2, quotDivPtr); } // Now everything is ready and prepared to return results // First maybe fill remainder if ((resultFlags & DivModResultFlags.Mod) != 0) { length1 = DigitOpHelper.Sub(digitsPtr1, length1, quotDivPtr, quotDivLength, digitsBufferPtr1); } // And finally fill quotient if ((resultFlags & DivModResultFlags.Div) != 0) { DigitHelper.DigitsBlockCopy(quotPtr, digitsResPtr, quotLength); } else { quotLength = 0; } // Return some arrays to pool ArrayPool <uint> .Instance.AddArray(int2OppositeDigits); return(quotLength); } } }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint* digitsPtr1, uint* digitsBufferPtr1, ref uint length1, uint* digitsPtr2, uint* digitsBufferPtr2, uint length2, uint* digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Call base (for special cases) uint resultLength = base.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult); if (resultLength != uint.MaxValue) return resultLength; bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // // Prepare digitsBufferPtr1 and digitsBufferPtr2 // int shift1 = 31 - Bits.Msb(digitsPtr2[length2 - 1]); if (shift1 == 0) { // We don't need to shift - just copy DigitHelper.DigitsBlockCopy(digitsPtr1, digitsBufferPtr1, length1); // We also don't need to shift second digits digitsBufferPtr2 = digitsPtr2; } else { int rightShift1 = Constants.DigitBitCount - shift1; // We do need to shift here - so copy with shift - suppose we have enough storage for this operation length1 = DigitOpHelper.Shr(digitsPtr1, length1, digitsBufferPtr1 + 1, rightShift1, true) + 1U; // Second digits also must be shifted DigitOpHelper.Shr(digitsPtr2, length2, digitsBufferPtr2 + 1, rightShift1, true); } // // Division main algorithm implementation // ulong longDigit; ulong divEst; ulong modEst; ulong mulRes; uint divRes; long k, t; // Some digits2 cached digits uint lastDigit2 = digitsBufferPtr2[length2 - 1]; uint preLastDigit2 = digitsBufferPtr2[length2 - 2]; // Main divide loop bool isMaxLength; uint maxLength = length1 - length2; for (uint i = maxLength, iLen2 = length1, j, ji; i <= maxLength; --i, --iLen2) { isMaxLength = iLen2 == length1; // Calculate estimates if (isMaxLength) { longDigit = digitsBufferPtr1[iLen2 - 1]; } else { longDigit = (ulong)digitsBufferPtr1[iLen2] << Constants.DigitBitCount | digitsBufferPtr1[iLen2 - 1]; } divEst = longDigit / lastDigit2; modEst = longDigit - divEst * lastDigit2; // Check estimate (maybe correct it) for (;;) { if (divEst == Constants.BitCountStepOf2 || divEst * preLastDigit2 > (modEst << Constants.DigitBitCount) + digitsBufferPtr1[iLen2 - 2]) { --divEst; modEst += lastDigit2; if (modEst < Constants.BitCountStepOf2) continue; } break; } divRes = (uint)divEst; // Multiply and subtract k = 0; for (j = 0, ji = i; j < length2; ++j, ++ji) { mulRes = (ulong)divRes * digitsBufferPtr2[j]; t = digitsBufferPtr1[ji] - k - (long)(mulRes & 0xFFFFFFFF); digitsBufferPtr1[ji] = (uint)t; k = (long)(mulRes >> Constants.DigitBitCount) - (t >> Constants.DigitBitCount); } if (!isMaxLength) { t = digitsBufferPtr1[iLen2] - k; digitsBufferPtr1[iLen2] = (uint)t; } else { t = -k; } // Correct result if subtracted too much if (t < 0) { --divRes; k = 0; for (j = 0, ji = i; j < length2; ++j, ++ji) { t = (long)digitsBufferPtr1[ji] + digitsBufferPtr2[j] + k; digitsBufferPtr1[ji] = (uint)t; k = t >> Constants.DigitBitCount; } if (!isMaxLength) { digitsBufferPtr1[iLen2] = (uint)(k + digitsBufferPtr1[iLen2]); } } // Maybe save div result if (divNeeded) { digitsResPtr[i] = divRes; } } if (modNeeded) { // First set correct mod length length1 = DigitHelper.GetRealDigitsLength(digitsBufferPtr1, length2); // Next maybe shift result back to the right if (shift1 != 0 && length1 != 0) { length1 = DigitOpHelper.Shr(digitsBufferPtr1, length1, digitsBufferPtr1, shift1, false); } } // Finally return length return !divNeeded ? 0 : (digitsResPtr[maxLength] == 0 ? maxLength : ++maxLength); }
/// <summary> /// Divides one <see cref="IntX" /> by another. /// </summary> /// <param name="int1">First big integer.</param> /// <param name="int2">Second big integer.</param> /// <param name="modRes">Remainder big integer.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <returns>Divident big integer.</returns> /// <exception cref="ArgumentNullException"><paramref name="int1" /> or <paramref name="int2" /> is a null reference.</exception> /// <exception cref="DivideByZeroException"><paramref name="int2" /> equals zero.</exception> virtual public IntX DivMod(IntX int1, IntX int2, out IntX modRes, DivModResultFlags resultFlags) { // Null reference exceptions if (ReferenceEquals(int1, null)) { throw new ArgumentNullException("int1", Strings.CantBeNull); } else if (ReferenceEquals(int2, null)) { throw new ArgumentNullException("int2", Strings.CantBeNull); } // Check if int2 equals zero if (int2._length == 0) { throw new DivideByZeroException(); } // Get flags bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // Special situation: check if int1 equals zero; in this case zero is always returned if (int1._length == 0) { modRes = modNeeded ? new IntX() : null; return(divNeeded ? new IntX() : null); } // Special situation: check if int2 equals one - nothing to divide in this case if (int2._length == 1 && int2._digits[0] == 1) { modRes = modNeeded ? new IntX() : null; return(divNeeded ? int2._negative ? -int1 : +int1 : null); } // Get resulting sign bool resultNegative = int1._negative ^ int2._negative; // Check if int1 > int2 int compareResult = DigitOpHelper.Cmp(int1._digits, int1._length, int2._digits, int2._length); if (compareResult < 0) { modRes = modNeeded ? new IntX(int1) : null; return(divNeeded ? new IntX() : null); } else if (compareResult == 0) { modRes = modNeeded ? new IntX() : null; return(divNeeded ? new IntX(resultNegative ? -1 : 1) : null); } // // Actually divide here (by Knuth algorithm) // // Prepare divident (if needed) IntX divRes = null; if (divNeeded) { divRes = new IntX(int1._length - int2._length + 1U, resultNegative); } // Prepare mod (if needed) if (modNeeded) { modRes = new IntX(int1._length + 1U, int1._negative); } else { modRes = null; } // Call procedure itself uint modLength = int1._length; uint divLength = DivMod( int1._digits, modNeeded ? modRes._digits : null, ref modLength, int2._digits, null, int2._length, divNeeded ? divRes._digits : null, resultFlags, compareResult); // Maybe set new lengths and perform normalization if (divNeeded) { divRes._length = divLength; divRes.TryNormalize(); } if (modNeeded) { modRes._length = modLength; modRes.TryNormalize(); } // Return div return(divRes); }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> virtual unsafe public uint DivMod( uint *digitsPtr1, uint *digitsBufferPtr1, ref uint length1, uint *digitsPtr2, uint *digitsBufferPtr2, uint length2, uint *digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Base implementation covers some special cases bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // // Special cases // // Case when length1 == 0 if (length1 == 0) { return(0); } // Case when both lengths are 1 if (length1 == 1 && length2 == 1) { if (divNeeded) { *digitsResPtr = *digitsPtr1 / *digitsPtr2; if (*digitsResPtr == 0) { length2 = 0; } } if (modNeeded) { *digitsBufferPtr1 = *digitsPtr1 % *digitsPtr2; if (*digitsBufferPtr1 == 0) { length1 = 0; } } return(length2); } // Compare digits first (if was not previously compared) if (cmpResult == -2) { cmpResult = DigitOpHelper.Cmp(digitsPtr1, length1, digitsPtr2, length2); } // Case when first value is smaller then the second one - we will have remainder only if (cmpResult < 0) { // Maybe we should copy first digits into remainder (if remainder is needed at all) if (modNeeded) { DigitHelper.DigitsBlockCopy(digitsPtr1, digitsBufferPtr1, length1); } // Zero as division result return(0); } // Case when values are equal if (cmpResult == 0) { // Maybe remainder must be marked as empty if (modNeeded) { length1 = 0; } // One as division result if (divNeeded) { *digitsResPtr = 1; } return(1); } // Case when second length equals to 1 if (length2 == 1) { // Call method basing on fact if div is needed uint modRes; if (divNeeded) { length2 = DigitOpHelper.DivMod(digitsPtr1, length1, *digitsPtr2, digitsResPtr, out modRes); } else { modRes = DigitOpHelper.Mod(digitsPtr1, length1, *digitsPtr2); } // Maybe save mod result if (modNeeded) { if (modRes != 0) { length1 = 1; *digitsBufferPtr1 = modRes; } else { length1 = 0; } } return(length2); } // This is regular case, not special return(uint.MaxValue); }
/// <summary> /// Divides one <see cref="IntX" /> by another. /// </summary> /// <param name="int1">First big integer.</param> /// <param name="int2">Second big integer.</param> /// <param name="modRes">Remainder big integer.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <returns>Divident big integer.</returns> /// <exception cref="ArgumentNullException"><paramref name="int1" /> or <paramref name="int2" /> is a null reference.</exception> /// <exception cref="DivideByZeroException"><paramref name="int2" /> equals zero.</exception> public virtual IntX DivMod(IntX int1, IntX int2, out IntX modRes, DivModResultFlags resultFlags) { // Null reference exceptions if (ReferenceEquals(int1, null)) { throw new ArgumentNullException("int1", Strings.CantBeNull); } else if (ReferenceEquals(int2, null)) { throw new ArgumentNullException("int2", Strings.CantBeNull); } // Check if int2 equals zero if (int2._length == 0) { throw new DivideByZeroException(); } // Get flags bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // Special situation: check if int1 equals zero; in this case zero is always returned if (int1._length == 0) { modRes = modNeeded ? new IntX() : null; return divNeeded ? new IntX() : null; } // Special situation: check if int2 equals one - nothing to divide in this case if (int2._length == 1 && int2._digits[0] == 1) { modRes = modNeeded ? new IntX() : null; return divNeeded ? int2._negative ? -int1 : +int1 : null; } // Get resulting sign bool resultNegative = int1._negative ^ int2._negative; // Check if int1 > int2 int compareResult = DigitOpHelper.Cmp(int1._digits, int1._length, int2._digits, int2._length); if (compareResult < 0) { modRes = modNeeded ? new IntX(int1) : null; return divNeeded ? new IntX() : null; } else if (compareResult == 0) { modRes = modNeeded ? new IntX() : null; return divNeeded ? new IntX(resultNegative ? -1 : 1) : null; } // // Actually divide here (by Knuth algorithm) // // Prepare divident (if needed) IntX divRes = null; if (divNeeded) { divRes = new IntX(int1._length - int2._length + 1U, resultNegative); } // Prepare mod (if needed) if (modNeeded) { modRes = new IntX(int1._length + 1U, int1._negative); } else { modRes = null; } // Call procedure itself uint modLength = int1._length; uint divLength = DivMod( int1._digits, modNeeded ? modRes._digits : null, ref modLength, int2._digits, null, int2._length, divNeeded ? divRes._digits : null, resultFlags, compareResult); // Maybe set new lengths and perform normalization if (divNeeded) { divRes._length = divLength; divRes.TryNormalize(); } if (modNeeded) { modRes._length = modLength; modRes.TryNormalize(); } // Return div return divRes; }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> public unsafe virtual uint DivMod( uint* digitsPtr1, uint* digitsBufferPtr1, ref uint length1, uint* digitsPtr2, uint* digitsBufferPtr2, uint length2, uint* digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Base implementation covers some special cases bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // // Special cases // // Case when length1 == 0 if (length1 == 0) return 0; // Case when both lengths are 1 if (length1 == 1 && length2 == 1) { if (divNeeded) { *digitsResPtr = *digitsPtr1 / *digitsPtr2; if (*digitsResPtr == 0) { length2 = 0; } } if (modNeeded) { *digitsBufferPtr1 = *digitsPtr1 % *digitsPtr2; if (*digitsBufferPtr1 == 0) { length1 = 0; } } return length2; } // Compare digits first (if was not previously compared) if (cmpResult == -2) { cmpResult = DigitOpHelper.Cmp(digitsPtr1, length1, digitsPtr2, length2); } // Case when first value is smaller then the second one - we will have remainder only if (cmpResult < 0) { // Maybe we should copy first digits into remainder (if remainder is needed at all) if (modNeeded) { DigitHelper.DigitsBlockCopy(digitsPtr1, digitsBufferPtr1, length1); } // Zero as division result return 0; } // Case when values are equal if (cmpResult == 0) { // Maybe remainder must be marked as empty if (modNeeded) { length1 = 0; } // One as division result if (divNeeded) { *digitsResPtr = 1; } return 1; } // Case when second length equals to 1 if (length2 == 1) { // Call method basing on fact if div is needed uint modRes; if (divNeeded) { length2 = DigitOpHelper.DivMod(digitsPtr1, length1, *digitsPtr2, digitsResPtr, out modRes); } else { modRes = DigitOpHelper.Mod(digitsPtr1, length1, *digitsPtr2); } // Maybe save mod result if (modNeeded) { if (modRes != 0) { length1 = 1; *digitsBufferPtr1 = modRes; } else { length1 = 0; } } return length2; } // This is regular case, not special return uint.MaxValue; }
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digits1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digits1">First big integer digits.</param> /// <param name="digitsBuffer1">Buffer for first big integer digits. May also contain remainder. Can be null - in this case it's created if necessary.</param> /// <param name="length1">First big integer length.</param> /// <param name="digits2">Second big integer digits.</param> /// <param name="digitsBuffer2">Buffer for second big integer digits. Only temporarily used. Can be null - in this case it's created if necessary.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsRes">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> public abstract uint DivMod( uint[] digits1, uint[] digitsBuffer1, ref uint length1, uint[] digits2, uint[] digitsBuffer2, uint length2, uint[] digitsRes, DivModResultFlags resultFlags, int cmpResult);
/// <summary> /// Divides two big integers. /// Also modifies <paramref name="digitsPtr1" /> and <paramref name="length1"/> (it will contain remainder). /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="digitsBufferPtr1">Buffer for first big integer digits. May also contain remainder.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="digitsBufferPtr2">Buffer for second big integer digits. Only temporarily used.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <param name="resultFlags">Which operation results to return.</param> /// <param name="cmpResult">Big integers comparsion result (pass -2 if omitted).</param> /// <returns>Resulting big integer length.</returns> override unsafe public uint DivMod( uint *digitsPtr1, uint *digitsBufferPtr1, ref uint length1, uint *digitsPtr2, uint *digitsBufferPtr2, uint length2, uint *digitsResPtr, DivModResultFlags resultFlags, int cmpResult) { // Call base (for special cases) uint resultLength = base.DivMod( digitsPtr1, digitsBufferPtr1, ref length1, digitsPtr2, digitsBufferPtr2, length2, digitsResPtr, resultFlags, cmpResult); if (resultLength != uint.MaxValue) { return(resultLength); } bool divNeeded = (resultFlags & DivModResultFlags.Div) != 0; bool modNeeded = (resultFlags & DivModResultFlags.Mod) != 0; // // Prepare digitsBufferPtr1 and digitsBufferPtr2 // int shift1 = 31 - Bits.Msb(digitsPtr2[length2 - 1]); if (shift1 == 0) { // We don't need to shift - just copy DigitHelper.DigitsBlockCopy(digitsPtr1, digitsBufferPtr1, length1); // We also don't need to shift second digits digitsBufferPtr2 = digitsPtr2; } else { int rightShift1 = Constants.DigitBitCount - shift1; // We do need to shift here - so copy with shift - suppose we have enough storage for this operation length1 = DigitOpHelper.Shr(digitsPtr1, length1, digitsBufferPtr1 + 1, rightShift1, true) + 1U; // Second digits also must be shifted DigitOpHelper.Shr(digitsPtr2, length2, digitsBufferPtr2 + 1, rightShift1, true); } // // Division main algorithm implementation // ulong longDigit; ulong divEst; ulong modEst; ulong mulRes; uint divRes; long k, t; // Some digits2 cached digits uint lastDigit2 = digitsBufferPtr2[length2 - 1]; uint preLastDigit2 = digitsBufferPtr2[length2 - 2]; // Main divide loop bool isMaxLength; uint maxLength = length1 - length2; for (uint i = maxLength, iLen2 = length1, j, ji; i <= maxLength; --i, --iLen2) { isMaxLength = iLen2 == length1; // Calculate estimates if (isMaxLength) { longDigit = digitsBufferPtr1[iLen2 - 1]; } else { longDigit = (ulong)digitsBufferPtr1[iLen2] << Constants.DigitBitCount | digitsBufferPtr1[iLen2 - 1]; } divEst = longDigit / lastDigit2; modEst = longDigit - divEst * lastDigit2; // Check estimate (maybe correct it) for (;;) { if (divEst == Constants.BitCountStepOf2 || divEst * preLastDigit2 > (modEst << Constants.DigitBitCount) + digitsBufferPtr1[iLen2 - 2]) { --divEst; modEst += lastDigit2; if (modEst < Constants.BitCountStepOf2) { continue; } } break; } divRes = (uint)divEst; // Multiply and subtract k = 0; for (j = 0, ji = i; j < length2; ++j, ++ji) { mulRes = (ulong)divRes * digitsBufferPtr2[j]; t = digitsBufferPtr1[ji] - k - (long)(mulRes & 0xFFFFFFFF); digitsBufferPtr1[ji] = (uint)t; k = (long)(mulRes >> Constants.DigitBitCount) - (t >> Constants.DigitBitCount); } if (!isMaxLength) { t = digitsBufferPtr1[iLen2] - k; digitsBufferPtr1[iLen2] = (uint)t; } else { t = -k; } // Correct result if subtracted too much if (t < 0) { --divRes; k = 0; for (j = 0, ji = i; j < length2; ++j, ++ji) { t = (long)digitsBufferPtr1[ji] + digitsBufferPtr2[j] + k; digitsBufferPtr1[ji] = (uint)t; k = t >> Constants.DigitBitCount; } if (!isMaxLength) { digitsBufferPtr1[iLen2] = (uint)(k + digitsBufferPtr1[iLen2]); } } // Maybe save div result if (divNeeded) { digitsResPtr[i] = divRes; } } if (modNeeded) { // First set correct mod length length1 = DigitHelper.GetRealDigitsLength(digitsBufferPtr1, length2); // Next maybe shift result back to the right if (shift1 != 0 && length1 != 0) { length1 = DigitOpHelper.Shr(digitsBufferPtr1, length1, digitsBufferPtr1, shift1, false); } } // Finally return length return(!divNeeded ? 0 : (digitsResPtr[maxLength] == 0 ? maxLength : ++maxLength)); }