public void Multiply_OutputsInputAsFirstLine(int a, int b) { var result = multiplier.Multiply(a, b); result.Steps .Should().HaveCount(1, "left operand is already 1"); result.Steps.Single().Left .Should().Be(a, "the input should be the first line of output"); result.Steps.Single().Right .Should().Be(b, "the input should be the first line of output"); }
/// <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); }
public void DoMath() { switch (selectOperator) { case "+": Console.WriteLine(adder.Add()); break; case "-": Console.WriteLine(subtractor.Subtract( )); break; case "*": Console.WriteLine(multiplier.Multiply()); break; case "/": Console.WriteLine(divider.Divide()); break; case "^": Console.WriteLine(exponenter.Exponent()); break; default: break; } }
public decimal Calculate(string text) { var query = _queryParser.Parse(text); var result = 0m; switch (query.Operation) { case "x": result = _multiplier.Multiply(query.FirstNumber, query.SecondNumber); break; case "+": result = _adder.Add(query.FirstNumber, query.SecondNumber); break; case "-": result = _subtractor.Subtract(query.FirstNumber, query.SecondNumber); break; case "/": result = _divider.Divide(query.FirstNumber, query.SecondNumber); break; } return(result); }
private List <TestMethodInstance> GetMethodInstance(IEnumerable <object[]> param, List <TestMethodInstance> result, object classInstance, IMultiplier methodMultiplier) { foreach (var parametersValue in param) { // TODO : move everything to a multiplier construct, ie InvocationCount * whatever else. ? // for each invoc count for (var i = 0; i < Attribute.InvocationCount; i++) { // multiply the tests if needed, for instance if multiple browers are needed var res = methodMultiplier.Multiply(Method); if (res.Count == 0) { var metadata = new Dictionary <string, object>(); result.Add(new TestMethodInstance(Attribute, metadata, parametersValue, classInstance, Method)); } else { foreach (var o in res) { var metadata = new Dictionary <string, object>(); metadata[methodMultiplier.Key()] = o; result.Add(new TestMethodInstance(Attribute, metadata, parametersValue, classInstance, Method)); } } } } return(result); }
internal void Run(int left, int right) { System.Console.WriteLine( formatter.FormatToString( multiplier.Multiply(left, right) ) ); }
public override async Task <GetProductResponse> MultiplyNumber(MultiplyNumberRequest request, ServerCallContext context) { _logger.LogInformation($"Multiplication requested for number {request.Number}"); return(new GetProductResponse { Value = await _multiplier.Multiply(request.Number) }); }
/// <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> /// Multiplies two big integers using pointers. /// </summary> /// <param name="digitsPtr1">First big integer digits.</param> /// <param name="length1">First big integer length.</param> /// <param name="digitsPtr2">Second big integer digits.</param> /// <param name="length2">Second big integer length.</param> /// <param name="digitsResPtr">Resulting big integer digits.</param> /// <returns>Resulting big integer real length.</returns> override unsafe public uint Multiply(uint *digitsPtr1, uint length1, uint *digitsPtr2, uint length2, uint *digitsResPtr) { // Check length - maybe use classic multiplier instead if (length1 < Constants.AutoFhtLengthLowerBound || length2 < Constants.AutoFhtLengthLowerBound || length1 > Constants.AutoFhtLengthUpperBound || length2 > Constants.AutoFhtLengthUpperBound) { return(_classicMultiplier.Multiply(digitsPtr1, length1, digitsPtr2, length2, digitsResPtr)); } uint newLength = length1 + length2; // Do FHT for first big integer double[] data1 = FhtHelper.ConvertDigitsToDouble(digitsPtr1, length1, newLength); FhtHelper.Fht(data1, (uint)data1.LongLength); // Compare digits double[] data2; if (digitsPtr1 == digitsPtr2 || DigitOpHelper.Cmp(digitsPtr1, length1, digitsPtr2, length2) == 0) { // Use the same FHT for equal big integers data2 = data1; } else { // Do FHT over second digits data2 = FhtHelper.ConvertDigitsToDouble(digitsPtr2, length2, newLength); FhtHelper.Fht(data2, (uint)data2.LongLength); } // Perform multiplication and reverse FHT FhtHelper.MultiplyFhtResults(data1, data2, (uint)data1.LongLength); FhtHelper.ReverseFht(data1, (uint)data1.LongLength); // Convert to digits fixed(double *slice1 = data1) { FhtHelper.ConvertDoubleToDigits(slice1, (uint)data1.LongLength, newLength, digitsResPtr); } // Return double arrays back to pool ArrayPool <double> .Instance.AddArray(data1); if (data2 != data1) { ArrayPool <double> .Instance.AddArray(data2); } // Maybe check for validity using classic multiplication if (IntX.GlobalSettings.ApplyFhtValidityCheck) { uint lowerDigitCount = System.Math.Min(length2, System.Math.Min(length1, Constants.FhtValidityCheckDigitCount)); // Validate result by multiplying lowerDigitCount digits using classic algorithm and comparing uint[] validationResult = new uint[lowerDigitCount * 2]; fixed(uint *validationResultPtr = validationResult) { _classicMultiplier.Multiply(digitsPtr1, lowerDigitCount, digitsPtr2, lowerDigitCount, validationResultPtr); if (DigitOpHelper.Cmp(validationResultPtr, lowerDigitCount, digitsResPtr, lowerDigitCount) != 0) { throw new FhtMultiplicationException(string.Format(Strings.FhtMultiplicationError, length1, length2)); } } } return(digitsResPtr[newLength - 1] == 0 ? --newLength : newLength); }
/// <summary> /// Generates integer opposite to the given one using approximation. /// Uses algorithm from Khuth vol. 2 3rd Edition (4.3.3). /// </summary> /// <param name="digitsPtr">Initial big integer digits.</param> /// <param name="length">Initial big integer length.</param> /// <param name="maxLength">Precision length.</param> /// <param name="bufferPtr">Buffer in which shifted big integer may be stored.</param> /// <param name="newLength">Resulting big integer length.</param> /// <param name="rightShift">How much resulting big integer is shifted to the left (or: must be shifted to the right).</param> /// <returns>Resulting big integer digits.</returns> static unsafe public uint[] GetIntegerOpposite( uint *digitsPtr, uint length, uint maxLength, uint *bufferPtr, out uint newLength, out ulong rightShift) { // Maybe initially shift original digits a bit to the left // (it must have MSB on 2nd position in the highest digit) int msb = Bits.Msb(digitsPtr[length - 1]); rightShift = (ulong)(length - 1) * Constants.DigitBitCount + (ulong)msb + 1U; if (msb != 2) { // Shift to the left (via actually right shift) int leftShift = (2 - msb + Constants.DigitBitCount) % Constants.DigitBitCount; length = DigitOpHelper.Shr(digitsPtr, length, bufferPtr + 1, Constants.DigitBitCount - leftShift, true) + 1U; } else { // Simply use the same digits without any shifting bufferPtr = digitsPtr; } // Calculate possible result length int lengthLog2 = Bits.CeilLog2(maxLength); uint newLengthMax = 1U << (lengthLog2 + 1); int lengthLog2Bits = lengthLog2 + Bits.Msb(Constants.DigitBitCount); // Create result digits uint[] resultDigits = ArrayPool <uint> .Instance.GetArray(newLengthMax); //new uint[newLengthMax]; uint resultLength; // Create temporary digits for squared result (twice more size) uint[] resultDigitsSqr = ArrayPool <uint> .Instance.GetArray(newLengthMax); //new uint[newLengthMax]; uint resultLengthSqr; // Create temporary digits for squared result * buffer uint[] resultDigitsSqrBuf = new uint[newLengthMax + length]; uint resultLengthSqrBuf; // We will always use current multiplier IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier(); // Fix some digits fixed(uint *resultPtrFixed = resultDigits, resultSqrPtrFixed = resultDigitsSqr, resultSqrBufPtr = resultDigitsSqrBuf) { uint *resultPtr = resultPtrFixed; uint *resultSqrPtr = resultSqrPtrFixed; // Cache two first digits uint bufferDigitN1 = bufferPtr[length - 1]; uint bufferDigitN2 = bufferPtr[length - 2]; // Prepare result. // Initially result = floor(32 / (4*v1 + 2*v2 + v3)) / 4 // (last division is not floored - here we emulate fixed point) resultDigits[0] = 32 / bufferDigitN1; resultLength = 1; // Prepare variables uint nextBufferTempStorage = 0; int nextBufferTempShift; uint nextBufferLength = 1U; uint *nextBufferPtr = &nextBufferTempStorage; ulong bitsAfterDotResult; ulong bitsAfterDotResultSqr; ulong bitsAfterDotNextBuffer; ulong bitShift; uint shiftOffset; uint *tempPtr; uint[] tempDigits; // Iterate 'till result will be precise enough for (int k = 0; k < lengthLog2Bits; ++k) { // Get result squared resultLengthSqr = multiplier.Multiply( resultPtr, resultLength, resultPtr, resultLength, resultSqrPtr); // Calculate current result bits after dot bitsAfterDotResult = (1UL << k) + 1UL; bitsAfterDotResultSqr = bitsAfterDotResult << 1; // Here we will get the next portion of data from bufferPtr if (k < 4) { // For now buffer intermediate has length 1 and we will use this fact nextBufferTempShift = 1 << (k + 1); nextBufferTempStorage = bufferDigitN1 << nextBufferTempShift | bufferDigitN2 >> (Constants.DigitBitCount - nextBufferTempShift); // Calculate amount of bits after dot (simple formula here) bitsAfterDotNextBuffer = (ulong)nextBufferTempShift + 3UL; } else { // Determine length to get from bufferPtr nextBufferLength = System.Math.Min((1U << (k - 4)) + 1U, length); nextBufferPtr = bufferPtr + (length - nextBufferLength); // Calculate amount of bits after dot (simple formula here) bitsAfterDotNextBuffer = (ulong)(nextBufferLength - 1U) * Constants.DigitBitCount + 3UL; } // Multiply result ^ 2 and nextBuffer + calculate new amount of bits after dot resultLengthSqrBuf = multiplier.Multiply( resultSqrPtr, resultLengthSqr, nextBufferPtr, nextBufferLength, resultSqrBufPtr); bitsAfterDotNextBuffer += bitsAfterDotResultSqr; // Now calculate 2 * result - resultSqrBufPtr --bitsAfterDotResult; --bitsAfterDotResultSqr; // Shift result on a needed amount of bits to the left bitShift = bitsAfterDotResultSqr - bitsAfterDotResult; shiftOffset = (uint)(bitShift / Constants.DigitBitCount); resultLength = shiftOffset + 1U + DigitOpHelper.Shr( resultPtr, resultLength, resultSqrPtr + shiftOffset + 1U, Constants.DigitBitCount - (int)(bitShift % Constants.DigitBitCount), true); // Swap resultPtr and resultSqrPtr pointers tempPtr = resultPtr; resultPtr = resultSqrPtr; resultSqrPtr = tempPtr; tempDigits = resultDigits; resultDigits = resultDigitsSqr; resultDigitsSqr = tempDigits; DigitHelper.SetBlockDigits(resultPtr, shiftOffset, 0U); bitShift = bitsAfterDotNextBuffer - bitsAfterDotResultSqr; shiftOffset = (uint)(bitShift / Constants.DigitBitCount); if (shiftOffset < resultLengthSqrBuf) { // Shift resultSqrBufPtr on a needed amount of bits to the right resultLengthSqrBuf = DigitOpHelper.Shr( resultSqrBufPtr + shiftOffset, resultLengthSqrBuf - shiftOffset, resultSqrBufPtr, (int)(bitShift % Constants.DigitBitCount), false); // Now perform actual subtraction resultLength = DigitOpHelper.Sub( resultPtr, resultLength, resultSqrBufPtr, resultLengthSqrBuf, resultPtr); } else { // Actually we can assume resultSqrBufPtr == 0 here and have nothing to do } } } // Return some arrays to pool ArrayPool <uint> .Instance.AddArray(resultDigitsSqr); rightShift += (1UL << lengthLog2Bits) + 1UL; newLength = resultLength; return(resultDigits); }
/// <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); }
public T Multiply(T valueX, T valueY) { return(_multiplier.Multiply(valueX, valueY)); }
/// <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); }