Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public static void WriteInteger_SingleValue_HappyPath(string valueString, string
[InlineData("1", "c4820001")]
[InlineData("-1", "c4820020")]
[InlineData("1.1", "c482200b")]
[InlineData("1.000", "c4820001")]
[InlineData("1.000", "c482221903e8")]
Comment thread
pgovind marked this conversation as resolved.
[InlineData("273.15", "c48221196ab3")]
[InlineData("79228162514264337593543950335", "c48200c24cffffffffffffffffffffffff")] // decimal.MaxValue
[InlineData("7922816251426433759354395033.5", "c48220c24cffffffffffffffffffffffff")]
Expand Down
34 changes: 20 additions & 14 deletions src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,10 @@ private static unsafe bool TryParseNumber(ref char* str, char* strEnd, NumberSty
{
number.Scale++;
}
else if (digCount < maxDigCount)

if (digCount < maxDigCount)
{
// Handle a case like "53.0". We need to ignore trailing zeros in the fractional part, so we keep a count of the number of trailing zeros and update digCount later
// Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later
if (ch == '0')
{
numberOfTrailingZeros++;
Expand Down Expand Up @@ -395,17 +396,8 @@ private static unsafe bool TryParseNumber(ref char* str, char* strEnd, NumberSty
}

bool negExp = false;
if (digEnd == maxDigCount && numberOfTrailingZeros > 0 && number.HasNonZeroTail)
{
// We have a non-zero digit in the input past maxDigitCount. We already handle this properly.
number.DigitsCount = digEnd;
}
else
{
// We have trailing 0s in the fractional part. We can strip it all out
number.DigitsCount = digEnd - numberOfTrailingZeros;
}
number.Digits[number.DigitsCount] = (byte)('\0');
number.DigitsCount = digEnd;
number.Digits[digEnd] = (byte)('\0');
if ((state & StateDigits) != 0)
{
if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0))
Expand Down Expand Up @@ -449,6 +441,20 @@ private static unsafe bool TryParseNumber(ref char* str, char* strEnd, NumberSty
ch = p < strEnd ? *p : '\0';
}
}

if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail)
{
// Adjust the number buffer for trailing zeros
int numberOfFractionalDigits = digEnd - number.Scale;
if (numberOfFractionalDigits > 0)
{
numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits);
Debug.Assert(numberOfTrailingZeros >= 0);
number.DigitsCount = digEnd - numberOfTrailingZeros;
Comment thread
pgovind marked this conversation as resolved.
number.Digits[number.DigitsCount] = (byte)('\0');
}
}

while (true)
{
if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0)
Expand Down Expand Up @@ -2025,7 +2031,7 @@ private static bool TrailingZeros(ReadOnlySpan<char> value, int index)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe char* MatchNegativeSignChars(char* p, char* pEnd, NumberFormatInfo info)
{
char *ret = MatchChars(p, pEnd, info.NegativeSign);
char* ret = MatchChars(p, pEnd, info.NegativeSign);
if (ret == null && info.AllowHyphenDuringParsing && p < pEnd && *p == '-')
{
ret = p + 1;
Expand Down
8 changes: 8 additions & 0 deletions src/libraries/System.Runtime/tests/System/DecimalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,14 @@ public static void ToString_InvalidFormat_ThrowsFormatException()
Assert.Throws<FormatException>(() => f.ToString("E" + intMaxPlus1String));
}

[Theory]
[InlineData("3.00")]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume this is one of the tests we would expect to add a much longer list of values to in the future, per our recent discussion about adding much more comprehensive tests in this area.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yup. This is just the start

public void TestRoundTripDecimalToString(string input)
{
decimal d = Decimal.Parse(input, NumberStyles.Number, NumberFormatInfo.InvariantInfo);
string dString = d.ToString(CultureInfo.InvariantCulture);
Assert.Equal(input, dString);
}
public static IEnumerable<object[]> Truncate_TestData()
{
yield return new object[] { 123m, 123m };
Expand Down
7 changes: 7 additions & 0 deletions src/libraries/System.Runtime/tests/System/DoubleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ public static IEnumerable<object[]> Parse_Valid_TestData()
yield return new object[] { "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 0.0 };
yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005 };
yield return new object[] { "0.0500", defaultStyle, invariantFormat, 0.05 };
yield return new object[] { "6250000000000000000000000000000000e-12", defaultStyle, invariantFormat, 6.25e21 };
yield return new object[] { "6250000e0", defaultStyle, invariantFormat, 6.25e6 };
yield return new object[] { "6250100e-5", defaultStyle, invariantFormat, 62.501 };
yield return new object[] { "625010.00e-4", defaultStyle, invariantFormat, 62.501 };
yield return new object[] { "62500e-4", defaultStyle, invariantFormat, 6.25 };
yield return new object[] { "62500", defaultStyle, invariantFormat, 62500.0 };
yield return new object[] { "10e-3", defaultStyle, invariantFormat, 0.01 };

yield return new object[] { (123.1).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1 };
yield return new object[] { (1000.0).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0 };
Expand Down
5 changes: 5 additions & 0 deletions src/libraries/System.Runtime/tests/System/HalfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,11 @@ public static IEnumerable<object[]> Parse_Valid_TestData()
yield return new object[] { "0.000000000000000000", defaultStyle, invariantFormat, 0.0f };
yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005f };
yield return new object[] { "0.0400", defaultStyle, invariantFormat, 0.04f };
yield return new object[] { "1200e0", defaultStyle, invariantFormat, 1200.0f };
yield return new object[] { "120100e-4", defaultStyle, invariantFormat, 12.01f };
yield return new object[] { "12010.00e-4", defaultStyle, invariantFormat, 1.201f };
yield return new object[] { "12000e-4", defaultStyle, invariantFormat, 1.2f };
yield return new object[] { "1200", defaultStyle, invariantFormat, 1200.0f };

yield return new object[] { (123.1f).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1f };
yield return new object[] { (1000.0f).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0f };
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Runtime/tests/System/Int32Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,12 @@ public static IEnumerable<object[]> Parse_Valid_TestData()
yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "123" }, -123 };
yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "12312" }, 3 };
yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "12312" }, -3 };

// Test trailing zeros
yield return new object[] { "3.00", NumberStyles.Number, CultureInfo.InvariantCulture, 3 };
Comment thread
pgovind marked this conversation as resolved.
yield return new object[] { "3.00000000", NumberStyles.Number, CultureInfo.InvariantCulture, 3 };
yield return new object[] { "3.000000000", NumberStyles.Number, CultureInfo.InvariantCulture, 3 };
yield return new object[] { "3.0000000000", NumberStyles.Number, CultureInfo.InvariantCulture, 3 };
}

[Theory]
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Runtime/tests/System/SingleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ public static IEnumerable<object[]> Parse_Valid_TestData()
yield return new object[] { "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 0.0f };
yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005f };
yield return new object[] { "0.0500", defaultStyle, invariantFormat, 0.05f };
yield return new object[] { "6250000000000000000000000000000000e-12", defaultStyle, invariantFormat, 6.25e21f };
yield return new object[] { "6250000e0", defaultStyle, invariantFormat, 6.25e6f };
yield return new object[] { "6250100e-5", defaultStyle, invariantFormat, 62.501f };
yield return new object[] { "625010.00e-4", defaultStyle, invariantFormat, 62.501f };
yield return new object[] { "62500e-4", defaultStyle, invariantFormat, 6.25f };
yield return new object[] { "62500", defaultStyle, invariantFormat, 62500.0f };

yield return new object[] { (123.1f).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1f };
yield return new object[] { (1000.0f).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0f };
Expand Down