Beispiel #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)
        {
            // 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>
        /// Converts digits from internal representaion into given base.
        /// </summary>
        /// <param name="digits">Big integer digits.</param>
        /// <param name="length">Big integer length.</param>
        /// <param name="numberBase">Base to use for output.</param>
        /// <param name="outputLength">Calculated output length (will be corrected inside).</param>
        /// <returns>Conversion result (later will be transformed to string).</returns>
        override unsafe public uint[] ToString(uint[] digits, uint length, uint numberBase, ref uint outputLength)
        {
            uint[] outputArray = base.ToString(digits, length, numberBase, ref outputLength);

            // Maybe base method already converted this number
            if (outputArray != null)
            {
                return(outputArray);
            }

            // Check length - maybe use classic converter instead
            if (length < Constants.FastConvertLengthLowerBound || length > Constants.FastConvertLengthUpperBound)
            {
                return(_classicStringConverter.ToString(digits, length, numberBase, ref outputLength));
            }

            int  resultLengthLog2 = Bits.CeilLog2(outputLength);
            uint resultLength     = 1U << resultLengthLog2;

            // Create and initially fill array for transofmed numbers storing
            uint[] resultArray = ArrayPool <uint> .Instance.GetArray(resultLength);

            Array.Copy(digits, resultArray, length);

            // Create and initially fill array with lengths
            uint[] resultArray2 = ArrayPool <uint> .Instance.GetArray(resultLength);

            resultArray2[0] = length;

            IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier();
            IDivider    divider    = DivideManager.GetCurrentDivider();

            // Generate all needed pows of numberBase in stack
            Stack baseIntStack = new Stack(resultLengthLog2);
            IntX  baseInt      = null;

            for (int i = 0; i < resultLengthLog2; ++i)
            {
                baseInt = baseInt == null ? numberBase : multiplier.Multiply(baseInt, baseInt);
                baseIntStack.Push(baseInt);
            }

            // Create temporary buffer for second digits when doing div operation
            uint[] tempBuffer = new uint[baseInt._length];

            // We will use unsafe code here
            fixed(uint *resultPtr1Const = resultArray, resultPtr2Const = resultArray2, tempBufferPtr = tempBuffer)
            {
                // Results pointers which will be modified (on swap)
                uint *resultPtr1 = resultPtr1Const;
                uint *resultPtr2 = resultPtr2Const;

                // Temporary variables used on swapping
                uint[] tempArray;
                uint * tempPtr;

                // Variables used in cycle
                uint *ptr1, ptr2, ptr1end;
                uint  loLength;

                // Outer cycle instead of recursion
                for (uint innerStep = resultLength >> 1, outerStep = resultLength; innerStep > 0; innerStep >>= 1, outerStep >>= 1)
                {
                    // Prepare pointers
                    ptr1    = resultPtr1;
                    ptr2    = resultPtr2;
                    ptr1end = resultPtr1 + resultLength;

                    // Get baseInt from stack and fix it too
                    baseInt = (IntX)baseIntStack.Pop();
                    fixed(uint *baseIntPtr = baseInt._digits)
                    {
                        // Cycle thru all digits and their lengths
                        for (; ptr1 < ptr1end; ptr1 += outerStep, ptr2 += outerStep)
                        {
                            // Divide ptr1 (with length in *ptr2) by baseIntPtr here.
                            // Results are stored in ptr2 & (ptr2 + innerStep), lengths - in *ptr1 and (*ptr1 + innerStep)
                            loLength            = *ptr2;
                            *(ptr1 + innerStep) = divider.DivMod(
                                ptr1,
                                ptr2,
                                ref loLength,
                                baseIntPtr,
                                tempBufferPtr,
                                baseInt._length,
                                ptr2 + innerStep,
                                DivModResultFlags.Div | DivModResultFlags.Mod,
                                -2);
                            *ptr1 = loLength;
                        }
                    }

                    // After inner cycle resultArray will contain lengths and resultArray2 will contain actual values
                    // so we need to swap them here
                    tempArray    = resultArray;
                    resultArray  = resultArray2;
                    resultArray2 = tempArray;

                    tempPtr    = resultPtr1;
                    resultPtr1 = resultPtr2;
                    resultPtr2 = tempPtr;
                }

                // Retrieve real output length
                outputLength = DigitHelper.GetRealDigitsLength(resultArray2, outputLength);

                // Create output array
                outputArray = new uint[outputLength];

                // Copy each digit but only if length is not null
                fixed(uint *outputPtr = outputArray)
                {
                    for (uint i = 0; i < outputLength; ++i)
                    {
                        if (resultPtr2[i] != 0)
                        {
                            outputPtr[i] = resultPtr1[i];
                        }
                    }
                }
            }

            // Return temporary arrays to pool
            ArrayPool <uint> .Instance.AddArray(resultArray);

            ArrayPool <uint> .Instance.AddArray(resultArray2);

            return(outputArray);
        }