/// <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> virtual public uint[] ToString(uint[] digits, uint length, uint numberBase, ref uint outputLength) { // Default implementation - always call pow2 converter if numberBase is pow of 2 return(numberBase == 1U << Bits.Msb(numberBase) ? _pow2StringConverter.ToString(digits, length, numberBase, ref outputLength) : null); }
/// <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> virtual public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes) { // Default implementation - always call pow2 parser if numberBase is pow of 2 return(numberBase == 1U << Bits.Msb(numberBase) ? _pow2Parser.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes) : 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> public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes) { // Calculate length of input string int bitsInChar = Bits.Msb(numberBase); uint valueLength = (uint)(endIndex - startIndex + 1); ulong valueBitLength = (ulong)valueLength * (ulong)bitsInChar; // Calculate needed digits length and first shift uint digitsLength = (uint)(valueBitLength / Constants.DigitBitCount) + 1; uint digitIndex = digitsLength - 1; int initialShift = (int)(valueBitLength % Constants.DigitBitCount); // Probably correct digits length if (initialShift == 0) { --digitsLength; } // Do parsing in big cycle uint digit; for (int i = startIndex; i <= endIndex; ++i) { digit = StrRepHelper.GetDigit(charToDigits, value[i], numberBase); // Correct initial digit shift if (initialShift == 0) { // If shift is equals to zero then char is not on digit elemtns bounds, // so just go to the previous digit initialShift = Constants.DigitBitCount - bitsInChar; --digitIndex; } else { // Here shift might be negative, but it's okay initialShift -= bitsInChar; } // Insert new digit in correct place digitsRes[digitIndex] |= initialShift < 0 ? digit >> -initialShift : digit << initialShift; // In case if shift was negative we also must modify previous digit if (initialShift < 0) { initialShift += Constants.DigitBitCount; digitsRes[--digitIndex] |= digit << initialShift; } } if (digitsRes[digitsLength - 1] == 0) { --digitsLength; } return(digitsLength); }
/// <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); }
/// <summary> /// Either returns array of given size from pool or creates it. /// </summary> /// <param name="length">Array length (always pow of 2).</param> /// <returns>Always array instance ready to use.</returns> public T[] GetArray(uint length) { int lengthLog2 = Bits.Msb(length); // Check if we can search in pool if (lengthLog2 >= _minPooledArraySizeLog2 && lengthLog2 <= _maxPooledArraySizeLog2) { // Get needed pool Stack <WeakReference> pool = _pools[lengthLog2 - _minPooledArraySizeLog2]; // Try to find at least one not collected array of given size while (pool.Count > 0) { WeakReference arrayRef; lock (pool) { // Double-guard here if (pool.Count > 0) { arrayRef = pool.Pop(); } else { // Well, we can exit here break; } } // Maybe return found array if link is alive T[] array = (T[])arrayRef.Target; if (arrayRef.IsAlive) { return(array); } } } // Array can't be found in pool - create new one return(new T[length]); }
/// <summary> /// Adds array to pool. /// </summary> /// <param name="array">Array to add (it/s length is always pow of 2).</param> public void AddArray(T[] array) { int lengthLog2 = Bits.Msb((uint)array.LongLength); // Check if we can add in pool if (lengthLog2 >= _minPooledArraySizeLog2 && lengthLog2 <= _maxPooledArraySizeLog2) { // Get needed pool Stack <WeakReference> pool = _pools[lengthLog2 - _minPooledArraySizeLog2]; // Add array to pool (only if pool size is not too big) if (pool.Count <= _maxPoolCount) { lock (pool) { // Double-guard here if (pool.Count <= _maxPoolCount) { pool.Push(new WeakReference(array)); } } } } }
/// <summary> /// Shifts <see cref="IntX" /> object. /// Determines which operation to use basing on shift sign. /// </summary> /// <param name="intX">Big integer.</param> /// <param name="shift">Bits count to shift.</param> /// <param name="toLeft">If true the shifting to the left.</param> /// <returns>Bitwise shift operation result.</returns> /// <exception cref="ArgumentNullException"><paramref name="intX" /> is a null reference.</exception> static public IntX Sh(IntX intX, long shift, bool toLeft) { // Exceptions if (ReferenceEquals(intX, null)) { throw new ArgumentNullException("intX", Strings.CantBeNullOne); } // Zero can't be shifted if (intX._length == 0) { return(new IntX()); } // Can't shift on zero value if (shift == 0) { return(new IntX(intX)); } // Determine real bits count and direction ulong bitCount; bool negativeShift; DigitHelper.ToUInt64WithSign(shift, out bitCount, out negativeShift); toLeft ^= negativeShift; // Get position of the most significant bit in intX and amount of bits in intX int msb = Bits.Msb(intX._digits[intX._length - 1]); ulong intXBitCount = (ulong)(intX._length - 1) * Constants.DigitBitCount + (ulong)msb + 1UL; // If shifting to the right and shift is too big then return zero if (!toLeft && bitCount >= intXBitCount) { return(new IntX()); } // Calculate new bit count ulong newBitCount = toLeft ? intXBitCount + bitCount : intXBitCount - bitCount; // If shifting to the left and shift is too big to fit in big integer, throw an exception if (toLeft && newBitCount > Constants.MaxBitCount) { throw new ArgumentException(Strings.IntegerTooBig, "intX"); } // Get exact length of new big integer (no normalize is ever needed here). // Create new big integer with given length uint newLength = (uint)(newBitCount / Constants.DigitBitCount + (newBitCount % Constants.DigitBitCount == 0 ? 0UL : 1UL)); IntX newInt = new IntX(newLength, intX._negative); // Get full and small shift values uint fullDigits = (uint)(bitCount / Constants.DigitBitCount); int smallShift = (int)(bitCount % Constants.DigitBitCount); // We can just copy (no shift) if small shift is zero if (smallShift == 0) { if (toLeft) { Array.Copy(intX._digits, 0, newInt._digits, fullDigits, intX._length); } else { Array.Copy(intX._digits, fullDigits, newInt._digits, 0, newLength); } } else { // Do copy with real shift in the needed direction if (toLeft) { DigitOpHelper.Shr(intX._digits, 0, intX._length, newInt._digits, fullDigits + 1, Constants.DigitBitCount - smallShift); } else { // If new result length is smaller then original length we shouldn't lose any digits if (newLength < (intX._length - fullDigits)) { newLength++; } DigitOpHelper.Shr(intX._digits, fullDigits, newLength, newInt._digits, 0, smallShift); } } return(newInt); }