Exemplo n.º 1
0
        /// <summary>
        /// Returns a specified big integer raised to the specified power.
        /// </summary>
        /// <param name="value">Number to raise.</param>
        /// <param name="power">Power.</param>
        /// <param name="multiplyMode">Multiply mode set explicitly.</param>
        /// <returns>Number in given power.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="value" /> is a null reference.</exception>
        static public IntX Pow(IntX value, uint power, MultiplyMode multiplyMode)
        {
            // Exception
            if (ReferenceEquals(value, null))
            {
                throw new ArgumentNullException("value");
            }

            // Return one for zero pow
            if (power == 0)
            {
                return(1);
            }

            // Return the number itself from a power of one
            if (power == 1)
            {
                return(new IntX(value));
            }

            // Return zero for a zero
            if (value._length == 0)
            {
                return(new IntX());
            }

            // Get first one bit
            int msb = Bits.Msb(power);

            // Get multiplier
            IMultiplier multiplier = MultiplyManager.GetMultiplier(multiplyMode);

            // Do actual raising
            IntX res = value;

            for (uint powerMask = 1U << (msb - 1); powerMask != 0; powerMask >>= 1)
            {
                // Always square
                res = multiplier.Multiply(res, res);

                // Maybe mul
                if ((power & powerMask) != 0)
                {
                    res = multiplier.Multiply(res, value);
                }
            }
            return(res);
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Parses provided string representation of <see cref="IntX" /> object.
        /// </summary>
        /// <param name="value">Number as string.</param>
        /// <param name="startIndex">Index inside string from which to start.</param>
        /// <param name="endIndex">Index inside string on which to end.</param>
        /// <param name="numberBase">Number base.</param>
        /// <param name="charToDigits">Char->digit dictionary.</param>
        /// <param name="digitsRes">Resulting digits.</param>
        /// <returns>Parsed integer length.</returns>
        override unsafe public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes)
        {
            uint newLength = base.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes);

            // Maybe base method already parsed this number
            if (newLength != 0)
            {
                return(newLength);
            }

            // Check length - maybe use classic parser instead
            uint initialLength = (uint)digitsRes.LongLength;

            if (initialLength < Constants.FastParseLengthLowerBound || initialLength > Constants.FastParseLengthUpperBound)
            {
                return(_classicParser.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes));
            }

            uint valueLength  = (uint)(endIndex - startIndex + 1);
            uint digitsLength = 1U << Bits.CeilLog2(valueLength);

            // Prepare array for digits in other base
            uint[] valueDigits = ArrayPool <uint> .Instance.GetArray(digitsLength);

            // This second array will store integer lengths initially
            uint[] valueDigits2 = ArrayPool <uint> .Instance.GetArray(digitsLength);

            fixed(uint *valueDigitsStartPtr = valueDigits, valueDigitsStartPtr2 = valueDigits2)
            {
                // In the string first digit means last in digits array
                uint *valueDigitsPtr  = valueDigitsStartPtr + valueLength - 1;
                uint *valueDigitsPtr2 = valueDigitsStartPtr2 + valueLength - 1;

                // Reverse copy characters into digits
                fixed(char *valueStartPtr = value)
                {
                    char *valuePtr    = valueStartPtr + startIndex;
                    char *valueEndPtr = valuePtr + valueLength;

                    for (; valuePtr < valueEndPtr; ++valuePtr, --valueDigitsPtr, --valueDigitsPtr2)
                    {
                        // Get digit itself - this call will throw an exception if char is invalid
                        *valueDigitsPtr = StrRepHelper.GetDigit(charToDigits, *valuePtr, numberBase);

                        // Set length of this digit (zero for zero)
                        *valueDigitsPtr2 = *valueDigitsPtr == 0U ? 0U : 1U;
                    }
                }

                // We have retrieved lengths array from pool - it needs to be cleared before using
                DigitHelper.SetBlockDigits(valueDigitsStartPtr2 + valueLength, digitsLength - valueLength, 0);

                // Now start from the digit arrays beginning
                valueDigitsPtr  = valueDigitsStartPtr;
                valueDigitsPtr2 = valueDigitsStartPtr2;

                // Current multiplier (classic or fast) will be used
                IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier();

                // Here base in needed power will be stored
                IntX baseInt = null;

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

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

                // Outer cycle instead of recursion
                for (uint innerStep = 1, outerStep = 2; innerStep < digitsLength; innerStep <<= 1, outerStep <<= 1)
                {
                    // Maybe baseInt must be multiplied by itself
                    baseInt = baseInt == null ? numberBase : baseInt * baseInt;

                    // Using unsafe here
                    fixed(uint *baseDigitsPtr = baseInt._digits)
                    {
                        // Start from arrays beginning
                        ptr1 = valueDigitsPtr;
                        ptr2 = valueDigitsPtr2;

                        // vauleDigits array end
                        valueDigitsPtrEnd = valueDigitsPtr + digitsLength;

                        // Cycle thru all digits and their lengths
                        for (; ptr1 < valueDigitsPtrEnd; ptr1 += outerStep, ptr2 += outerStep)
                        {
                            // Get lengths of "lower" and "higher" value parts
                            loLength = *ptr2;
                            hiLength = *(ptr2 + innerStep);

                            if (hiLength != 0)
                            {
                                // We always must clear an array before multiply
                                DigitHelper.SetBlockDigits(ptr2, outerStep, 0U);

                                // Multiply per baseInt
                                hiLength = multiplier.Multiply(
                                    baseDigitsPtr,
                                    baseInt._length,
                                    ptr1 + innerStep,
                                    hiLength,
                                    ptr2);
                            }

                            // Sum results
                            if (hiLength != 0 || loLength != 0)
                            {
                                *ptr1 = DigitOpHelper.Add(
                                    ptr2,
                                    hiLength,
                                    ptr1,
                                    loLength,
                                    ptr2);
                            }
                            else
                            {
                                *ptr1 = 0U;
                            }
                        }
                    }

                    // After inner cycle valueDigits will contain lengths and valueDigits2 will contain actual values
                    // so we need to swap them here
                    tempDigits   = valueDigits;
                    valueDigits  = valueDigits2;
                    valueDigits2 = tempDigits;

                    tempPtr         = valueDigitsPtr;
                    valueDigitsPtr  = valueDigitsPtr2;
                    valueDigitsPtr2 = tempPtr;
                }
            }

            // Determine real length of converted number
            uint realLength = valueDigits2[0];

            // Copy to result
            Array.Copy(valueDigits, digitsRes, realLength);

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

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

            return(realLength);
        }