Skip to content

Commit

Permalink
Don't throw an overflow exception unnecessarily
Browse files Browse the repository at this point in the history
  • Loading branch information
tannergooding committed May 30, 2024
1 parent f320969 commit 8bf392e
Showing 1 changed file with 64 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -496,22 +496,22 @@ internal BigInteger(int n, uint[]? rgu)
/// <param name="negative">The bool indicating the sign of the value.</param>
private BigInteger(ReadOnlySpan<uint> value, bool negative)
{
// Try to conserve space as much as possible by checking for wasted leading span entries
// sometimes the span has leading zeros from bit manipulation operations & and ^

int length = value.LastIndexOfAnyExcept(0u) + 1;
value = value[..length];

if (value.Length > MaxLength)
{
ThrowHelper.ThrowOverflowException();
}

int len;

// Try to conserve space as much as possible by checking for wasted leading span entries
// sometimes the span has leading zeros from bit manipulation operations & and ^
for (len = value.Length; len > 0 && value[len - 1] == 0; len--);

if (len == 0)
if (value.Length == 0)
{
this = s_bnZeroInt;
this = default;
}
else if (len == 1 && value[0] < kuMaskHighBit)
else if (value.Length == 1 && value[0] < kuMaskHighBit)
{
// Values like (Int32.MaxValue+1) are stored as "0x80000000" and as such cannot be packed into _sign
_sign = negative ? -(int)value[0] : (int)value[0];
Expand All @@ -525,7 +525,7 @@ private BigInteger(ReadOnlySpan<uint> value, bool negative)
else
{
_sign = negative ? -1 : +1;
_bits = value.Slice(0, len).ToArray();
_bits = value.ToArray();
}
AssertValid();
}
Expand All @@ -536,87 +536,88 @@ private BigInteger(ReadOnlySpan<uint> value, bool negative)
/// <param name="value"></param>
private BigInteger(Span<uint> value)
{
bool isNegative;
int length;

if ((value.Length > 0) && ((int)value[^1] < 0))
{
isNegative = true;
length = value.LastIndexOfAnyExcept(uint.MaxValue) + 1;

if ((length == 0) || ((int)value[length - 1] > 0))
{
// We ne need to preserve the sign bit
length++;
}
Debug.Assert((int)value[length - 1] < 0);
}
else
{
isNegative = false;
length = value.LastIndexOfAnyExcept(0u) + 1;
}
value = value[..length];

if (value.Length > MaxLength)
{
ThrowHelper.ThrowOverflowException();
}

int dwordCount = value.Length;
bool isNegative = dwordCount > 0 && ((value[dwordCount - 1] & kuMaskHighBit) == kuMaskHighBit);

// Try to conserve space as much as possible by checking for wasted leading span entries
while (dwordCount > 0 && value[dwordCount - 1] == 0) dwordCount--;

if (dwordCount == 0)
if (value.Length == 0)
{
// BigInteger.Zero
// 0
this = s_bnZeroInt;
AssertValid();
return;
}
if (dwordCount == 1)
else if (value.Length == 1)
{
if (unchecked((int)value[0]) < 0 && !isNegative)
if (isNegative)
{
_bits = new uint[1];
_bits[0] = value[0];
_sign = +1;
if (value[0] == uint.MaxValue)
{
// -1
this = s_bnMinusOneInt;
}
else if (value[0] == kuMaskHighBit)
{
// int.MinValue
this = s_bnMinInt;
}
else
{
_sign = unchecked((int)value[0]);
_bits = null;
}
}
// Handle the special cases where the BigInteger likely fits into _sign
else if (int.MinValue == unchecked((int)value[0]))
else if (unchecked((int)value[0]) < 0)
{
this = s_bnMinInt;
_sign = +1;
_bits = [value[0]];
}
else
{
_sign = unchecked((int)value[0]);
_bits = null;
}
AssertValid();
return;
}

if (!isNegative)
else
{
// Handle the simple positive value cases where the input is already in sign magnitude
_sign = +1;
value = value.Slice(0, dwordCount);
_bits = value.ToArray();
AssertValid();
return;
}

// Finally handle the more complex cases where we must transform the input into sign magnitude
NumericsHelpers.DangerousMakeTwosComplement(value); // mutates val
if (isNegative)
{
NumericsHelpers.DangerousMakeTwosComplement(value);

// Pack _bits to remove any wasted space after the twos complement
int len = value.Length;
while (len > 0 && value[len - 1] == 0) len--;
// Retrim any leading zeros carried from the sign
length = value.LastIndexOfAnyExcept(0u) + 1;
value = value[..length];

// The number is represented by a single dword
if (len == 1 && unchecked((int)(value[0])) > 0)
{
if (value[0] == 1 /* abs(-1) */)
{
this = s_bnMinusOneInt;
}
else if (value[0] == kuMaskHighBit /* abs(Int32.MinValue) */)
{
this = s_bnMinInt;
_sign = -1;
}
else
{
_sign = (-1) * ((int)value[0]);
_bits = null;
_sign = +1;
}
}
else
{
_sign = -1;
_bits = value.Slice(0, len).ToArray();
_bits = value.ToArray();
}
AssertValid();
return;
}

public static BigInteger Zero { get { return s_bnZeroInt; } }
Expand Down

0 comments on commit 8bf392e

Please sign in to comment.