Skip to content

Commit

Permalink
Fix an issue with complex number parsing (#104388)
Browse files Browse the repository at this point in the history
  • Loading branch information
tannergooding authored Jul 6, 2024
1 parent 5505150 commit e125e93
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2113,7 +2113,7 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
return false;
}

if (!double.TryParse(s.Slice(openBracket + 1, semicolon), style, provider, out double real))
if (!double.TryParse(s.Slice(openBracket + 1, semicolon - openBracket - 1), style, provider, out double real))
{
result = default;
return false;
Expand All @@ -2126,7 +2126,7 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
semicolon += 1;
}

if (!double.TryParse(s.Slice(semicolon + 1, closeBracket - semicolon), style, provider, out double imaginary))
if (!double.TryParse(s.Slice(semicolon + 1, closeBracket - semicolon - 1), style, provider, out double imaginary))
{
result = default;
return false;
Expand Down
114 changes: 114 additions & 0 deletions src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,120 @@ public static void SqrtMinusOne()
Assert.Equal(Complex.Sqrt(-1.0), Complex.ImaginaryOne);
}

public static IEnumerable<object[]> Parse_Valid_TestData()
{
NumberStyles defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;

NumberFormatInfo emptyFormat = NumberFormatInfo.CurrentInfo;

var dollarSignCommaSeparatorFormat = new NumberFormatInfo()
{
CurrencySymbol = "$",
CurrencyGroupSeparator = ","
};

var decimalSeparatorFormat = new NumberFormatInfo()
{
NumberDecimalSeparator = "."
};

NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo;

yield return new object[] { "-123", defaultStyle, null, -123.0 };
yield return new object[] { "0", defaultStyle, null, 0.0 };
yield return new object[] { "123", defaultStyle, null, 123.0 };
yield return new object[] { " 123 ", defaultStyle, null, 123.0 };
yield return new object[] { (567.89).ToString(), defaultStyle, null, 567.89 };
yield return new object[] { (-567.89).ToString(), defaultStyle, null, -567.89 };
yield return new object[] { "1E23", defaultStyle, null, 1E23 };
yield return new object[] { "9007199254740997.0", defaultStyle, invariantFormat, 9007199254740996.0 };
yield return new object[] { "9007199254740997.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 9007199254740996.0 };
yield return new object[] { "9007199254740997.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 9007199254740996.0 };
yield return new object[] { "9007199254740997.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
yield return new object[] { "9007199254740997.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
yield return new object[] { "9007199254740997.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
yield return new object[] { "5.005", defaultStyle, invariantFormat, 5.005 };
yield return new object[] { "5.050", defaultStyle, invariantFormat, 5.05 };
yield return new object[] { "5.005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5.005 };
yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, 5.0 };
yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5.005 };

yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, 0.234 };
yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 234.0 };
yield return new object[] { new string('0', 458) + "1" + new string('0', 308) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 1E308 };
yield return new object[] { new string('0', 459) + "1" + new string('0', 308) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 1E308 };

yield return new object[] { "5005.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5005.0 };
yield return new object[] { "50050.0", defaultStyle, invariantFormat, 50050.0 };
yield return new object[] { "5005", defaultStyle, invariantFormat, 5005.0 };
yield return new object[] { "050050", defaultStyle, invariantFormat, 50050.0 };
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 };

yield return new object[] { "123", NumberStyles.Any, emptyFormat, 123.0 };
yield return new object[] { (123.567).ToString(), NumberStyles.Any, emptyFormat, 123.567 };
yield return new object[] { "123", NumberStyles.Float, emptyFormat, 123.0 };
yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0 };
yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0 };
yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, 123.123 };
yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, -123.0 };

yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, double.NaN };
yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, double.PositiveInfinity };
yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, double.NegativeInfinity };
}

[Theory]
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse(string valueScalar, NumberStyles style, IFormatProvider provider, double expectedScalar)
{
string value = $"<{valueScalar}; {valueScalar}>";
Complex expected = new Complex(expectedScalar, expectedScalar);

bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
Complex result;
if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
{
// Use Parse(string) or Parse(string, IFormatProvider)
if (isDefaultProvider)
{
Assert.True(Complex.TryParse(value, null, out result));
Assert.Equal(expected, result);

Assert.Equal(expected, Complex.Parse(value, null));
}

Assert.Equal(expected, Complex.Parse(value, provider));
}

// Use Parse(string, NumberStyles, IFormatProvider)
Assert.True(Complex.TryParse(value, style, provider, out result));
Assert.Equal(expected, result);

Assert.Equal(expected, Complex.Parse(value, style, provider));

if (isDefaultProvider)
{
// Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider)
Assert.True(Complex.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result));
Assert.Equal(expected, result);

Assert.Equal(expected, Complex.Parse(value, style, null));
Assert.Equal(expected, Complex.Parse(value, style, NumberFormatInfo.CurrentInfo));
}
}

public static IEnumerable<object[]> Valid_2_TestData()
{
foreach (double real in s_validDoubleValues)
Expand Down

0 comments on commit e125e93

Please sign in to comment.