示例#1
0
        /// <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);
			}
		}
示例#3
0
 /// <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);
示例#4
0
        /// <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);
            }
        }
示例#5
0
        /// <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));
            }
        }
示例#6
0
        /// <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;
                }
            }
        }
示例#7
0
        /// <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);
		}
示例#9
0
        /// <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);
        }
示例#10
0
        /// <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);
        }
示例#11
0
        /// <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;
        }
示例#12
0
        /// <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;
        }
示例#13
0
 /// <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);
示例#14
0
        /// <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));
        }