Skip to content

Commit

Permalink
Merge pull request dotnet#1436 from axelheer/biginteger-performance
Browse files Browse the repository at this point in the history
Improve performance of BigInteger.Multiply
  • Loading branch information
KrzysztofCwalina committed Apr 28, 2015
2 parents ddd5f19 + dd71d2f commit 4b56539
Show file tree
Hide file tree
Showing 8 changed files with 505 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>
<!-- References are resolved from packages.config -->
<ItemGroup>
<Compile Include="System\Numerics\BigIntegerCalculator.AddSub.cs" />
<Compile Include="System\Numerics\BigIntegerCalculator.SquMul.cs" />
<Compile Include="System\Numerics\BigInteger.cs" />
<Compile Include="System\Numerics\BigIntegerBuilder.cs" />
<Compile Include="System\Numerics\BigNumber.cs" />
Expand Down
44 changes: 39 additions & 5 deletions src/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1618,12 +1618,46 @@ public static explicit operator Decimal(BigInteger value)
left.AssertValid();
right.AssertValid();

int sign = +1;
BigIntegerBuilder reg1 = new BigIntegerBuilder(left, ref sign);
BigIntegerBuilder reg2 = new BigIntegerBuilder(right, ref sign);
uint[] result;

if (left._bits != null)
{
if (right._bits != null)
{
if (left._bits == right._bits)
{
result = BigIntegerCalculator.Square(left._bits);
}
else
{
if (left._bits.Length < right._bits.Length)
{
result = BigIntegerCalculator.Multiply(right._bits, left._bits);
}
else
{
result = BigIntegerCalculator.Multiply(left._bits, right._bits);
}
}
}
else
{
result = BigIntegerCalculator.Multiply(left._bits, NumericsHelpers.Abs(right._sign));
}
}
else
{
if (right._bits != null)
{
result = BigIntegerCalculator.Multiply(right._bits, NumericsHelpers.Abs(left._sign));
}
else
{
result = BigIntegerCalculator.Multiply(NumericsHelpers.Abs(left._sign), NumericsHelpers.Abs(right._sign));
}
}

reg1.Mul(ref reg2);
return reg1.GetInteger(sign);
return new BigInteger(result, (left._sign < 0) ^ (right._sign < 0));
}

public static BigInteger operator /(BigInteger dividend, BigInteger divisor)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Diagnostics;
using System.Security;

namespace System.Numerics
{
internal static partial class BigIntegerCalculator
{
[SecuritySafeCritical]
private unsafe static void Add(uint* left, int leftLength,
uint* right, int rightLength,
uint* bits, int bitsLength)
{
Debug.Assert(leftLength >= 0);
Debug.Assert(rightLength >= 0);
Debug.Assert(leftLength >= rightLength);
Debug.Assert(bitsLength == leftLength + 1);

// Executes the "grammar-school" algorithm for computing z = a + b.
// While calculating z_i = a_i + b_i we take care of overflow:
// Since a_i + b_i + c <= 2(2^32 - 1) + 1 = 2^33 - 1, our carry c
// has always the value 1 or 0; hence, we're safe here.

int i = 0;
long carry = 0L;

// adds the bits
for (; i < rightLength; i++)
{
long digit = (left[i] + carry) + right[i];
bits[i] = (uint)digit;
carry = digit >> 32;
}
for (; i < leftLength; i++)
{
long digit = left[i] + carry;
bits[i] = (uint)digit;
carry = digit >> 32;
}
bits[i] = (uint)carry;
}

[SecuritySafeCritical]
private unsafe static void AddSelf(uint* left, int leftLength,
uint* right, int rightLength)
{
Debug.Assert(leftLength >= 0);
Debug.Assert(rightLength >= 0);
Debug.Assert(leftLength >= rightLength);

// Executes the "grammar-school" algorithm for computing z = a + b.
// Same as above, but we're writing the result directly to a and
// stop execution, if we're out of b and c is already 0.

int i = 0;
long carry = 0L;

// adds the bits
for (; i < rightLength; i++)
{
long digit = (left[i] + carry) + right[i];
left[i] = (uint)digit;
carry = digit >> 32;
}
for (; carry != 0 && i < leftLength; i++)
{
long digit = left[i] + carry;
left[i] = (uint)digit;
carry = digit >> 32;
}
}
}
}
Loading

0 comments on commit 4b56539

Please sign in to comment.