Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix BigInteger.Parse returning incorrect values for exponents above 1000 #73643

Merged
merged 8 commits into from
Aug 12, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -517,15 +517,19 @@ private static unsafe bool ParseNumber(ref char* str, char* strEnd, NumberStyles
{
exp = exp * 10 + (ch - '0');
ch = ++p < strEnd ? *p : '\0';
if (exp > 1000)
{
exp = 9999;
while (char.IsAsciiDigit(ch))
{
ch = ++p < strEnd ? *p : '\0';
}
}
} while (char.IsAsciiDigit(ch));
} while (char.IsAsciiDigit(ch) && (exp < int.MaxValue / 10));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to limit this to 999,999,999 like we did for ToString("G#########")?

Copy link
Contributor Author

@dakersnar dakersnar Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be safer in case there is any incrementing that happens elsewhere that I hadn't noticed. Would that require updating documentation somewhere?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely a similar breaking change doc to what we did for ToString.


if (char.IsAsciiDigit(ch))
{
// We still had remaining characters but bailed early because
// the exponent was going to overflow. If exp is exactly 214748364
// then we can technically handle one more character being 0-7
// but the additional complexity might not be worthwhile.

Debug.Assert(exp >= 214748364);
throw new PlatformNotSupportedException();
}

if (negExp)
{
exp = -exp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,38 @@ public static void CustomFormatPerMille()
RunCustomFormatToStringTests(s_random, "#\u2030000000", CultureInfo.CurrentCulture.NumberFormat.NegativeSign, 6, PerMilleSymbolFormatter);
}

public static IEnumerable<object[]> RunFormatScientificNotationToBigIntegerAndViceVersaData()
{
yield return new object[] { "1E+1000", "1E+1000" };
yield return new object[] { "1E+1001", "1E+1001" };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tannergooding I was not able to get a test with "1E+2147483639" to work locally, I think it ran for too long.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's fine, as long as we have some basic tests that values over 1E+1000 work it should be good enough

Testing the extreme edge cases is going to run into lots of issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a couple bigger test cases.

}

[Theory]
[MemberData(nameof(RunFormatScientificNotationToBigIntegerAndViceVersaData))]
public static void RunFormatScientificNotationToBigIntegerAndViceVersa(string testingValue, string expectedResult)
{
BigInteger parsedValue;
string actualResult;

parsedValue = BigInteger.Parse(testingValue, NumberStyles.AllowExponent);
actualResult = parsedValue.ToString("E0");

Assert.Equal(expectedResult, actualResult);
}

public static IEnumerable<object[]> RunFormatScientificNotationToBigIntegerThrowsExceptionData()
{
yield return new object[] { "1E+2147483647" };
yield return new object[] { "1E+21474836492" };
}

[Theory]
[MemberData(nameof(RunFormatScientificNotationToBigIntegerThrowsExceptionData))]
public static void RunFormatScientificNotationToBigIntegerThrowsException(string testingValue)
{
Assert.Throws<PlatformNotSupportedException>(() => BigInteger.Parse(testingValue, NumberStyles.AllowExponent));
}

private static void RunSimpleProviderToStringTests(Random random, string format, NumberFormatInfo provider, int precision, StringFormatter formatter)
{
string test;
Expand Down