Skip to content

Commit 3d0baeb

Browse files
Fix an issue with complex number parsing (#104499)
Co-authored-by: Tanner Gooding <[email protected]>
1 parent 57bd35a commit 3d0baeb

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,7 +2125,7 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
21252125
return false;
21262126
}
21272127

2128-
if (!double.TryParse(s.Slice(openBracket + 1, semicolon), style, provider, out double real))
2128+
if (!double.TryParse(s.Slice(openBracket + 1, semicolon - openBracket - 1), style, provider, out double real))
21292129
{
21302130
result = default;
21312131
return false;
@@ -2138,7 +2138,7 @@ public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatPro
21382138
semicolon += 1;
21392139
}
21402140

2141-
if (!double.TryParse(s.Slice(semicolon + 1, closeBracket - semicolon), style, provider, out double imaginary))
2141+
if (!double.TryParse(s.Slice(semicolon + 1, closeBracket - semicolon - 1), style, provider, out double imaginary))
21422142
{
21432143
result = default;
21442144
return false;

src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,120 @@ public static void SqrtMinusOne()
7070
Assert.Equal(Complex.Sqrt(-1.0), Complex.ImaginaryOne);
7171
}
7272

73+
public static IEnumerable<object[]> Parse_Valid_TestData()
74+
{
75+
NumberStyles defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
76+
77+
NumberFormatInfo emptyFormat = NumberFormatInfo.CurrentInfo;
78+
79+
var dollarSignCommaSeparatorFormat = new NumberFormatInfo()
80+
{
81+
CurrencySymbol = "$",
82+
CurrencyGroupSeparator = ","
83+
};
84+
85+
var decimalSeparatorFormat = new NumberFormatInfo()
86+
{
87+
NumberDecimalSeparator = "."
88+
};
89+
90+
NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo;
91+
92+
yield return new object[] { "-123", defaultStyle, null, -123.0 };
93+
yield return new object[] { "0", defaultStyle, null, 0.0 };
94+
yield return new object[] { "123", defaultStyle, null, 123.0 };
95+
yield return new object[] { " 123 ", defaultStyle, null, 123.0 };
96+
yield return new object[] { (567.89).ToString(), defaultStyle, null, 567.89 };
97+
yield return new object[] { (-567.89).ToString(), defaultStyle, null, -567.89 };
98+
yield return new object[] { "1E23", defaultStyle, null, 1E23 };
99+
yield return new object[] { "9007199254740997.0", defaultStyle, invariantFormat, 9007199254740996.0 };
100+
yield return new object[] { "9007199254740997.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 9007199254740996.0 };
101+
yield return new object[] { "9007199254740997.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 9007199254740996.0 };
102+
yield return new object[] { "9007199254740997.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
103+
yield return new object[] { "9007199254740997.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
104+
yield return new object[] { "9007199254740997.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, 9007199254740998.0 };
105+
yield return new object[] { "5.005", defaultStyle, invariantFormat, 5.005 };
106+
yield return new object[] { "5.050", defaultStyle, invariantFormat, 5.05 };
107+
yield return new object[] { "5.005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5.005 };
108+
yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, 5.0 };
109+
yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5.005 };
110+
111+
yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, 0.234 };
112+
yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 234.0 };
113+
yield return new object[] { new string('0', 458) + "1" + new string('0', 308) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 1E308 };
114+
yield return new object[] { new string('0', 459) + "1" + new string('0', 308) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 1E308 };
115+
116+
yield return new object[] { "5005.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 5005.0 };
117+
yield return new object[] { "50050.0", defaultStyle, invariantFormat, 50050.0 };
118+
yield return new object[] { "5005", defaultStyle, invariantFormat, 5005.0 };
119+
yield return new object[] { "050050", defaultStyle, invariantFormat, 50050.0 };
120+
yield return new object[] { "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, 0.0 };
121+
yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005 };
122+
yield return new object[] { "0.0500", defaultStyle, invariantFormat, 0.05 };
123+
yield return new object[] { "6250000000000000000000000000000000e-12", defaultStyle, invariantFormat, 6.25e21 };
124+
yield return new object[] { "6250000e0", defaultStyle, invariantFormat, 6.25e6 };
125+
yield return new object[] { "6250100e-5", defaultStyle, invariantFormat, 62.501 };
126+
yield return new object[] { "625010.00e-4", defaultStyle, invariantFormat, 62.501 };
127+
yield return new object[] { "62500e-4", defaultStyle, invariantFormat, 6.25 };
128+
yield return new object[] { "62500", defaultStyle, invariantFormat, 62500.0 };
129+
yield return new object[] { "10e-3", defaultStyle, invariantFormat, 0.01 };
130+
131+
yield return new object[] { (123.1).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1 };
132+
yield return new object[] { (1000.0).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0 };
133+
134+
yield return new object[] { "123", NumberStyles.Any, emptyFormat, 123.0 };
135+
yield return new object[] { (123.567).ToString(), NumberStyles.Any, emptyFormat, 123.567 };
136+
yield return new object[] { "123", NumberStyles.Float, emptyFormat, 123.0 };
137+
yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0 };
138+
yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0 };
139+
yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, 123.123 };
140+
yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, -123.0 };
141+
142+
yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, double.NaN };
143+
yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, double.PositiveInfinity };
144+
yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, double.NegativeInfinity };
145+
}
146+
147+
[Theory]
148+
[MemberData(nameof(Parse_Valid_TestData))]
149+
public static void Parse(string valueScalar, NumberStyles style, IFormatProvider provider, double expectedScalar)
150+
{
151+
string value = $"<{valueScalar}; {valueScalar}>";
152+
Complex expected = new Complex(expectedScalar, expectedScalar);
153+
154+
bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo;
155+
Complex result;
156+
if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None)
157+
{
158+
// Use Parse(string) or Parse(string, IFormatProvider)
159+
if (isDefaultProvider)
160+
{
161+
Assert.True(Complex.TryParse(value, null, out result));
162+
Assert.Equal(expected, result);
163+
164+
Assert.Equal(expected, Complex.Parse(value, null));
165+
}
166+
167+
Assert.Equal(expected, Complex.Parse(value, provider));
168+
}
169+
170+
// Use Parse(string, NumberStyles, IFormatProvider)
171+
Assert.True(Complex.TryParse(value, style, provider, out result));
172+
Assert.Equal(expected, result);
173+
174+
Assert.Equal(expected, Complex.Parse(value, style, provider));
175+
176+
if (isDefaultProvider)
177+
{
178+
// Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider)
179+
Assert.True(Complex.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result));
180+
Assert.Equal(expected, result);
181+
182+
Assert.Equal(expected, Complex.Parse(value, style, null));
183+
Assert.Equal(expected, Complex.Parse(value, style, NumberFormatInfo.CurrentInfo));
184+
}
185+
}
186+
73187
public static IEnumerable<object[]> Valid_2_TestData()
74188
{
75189
foreach (double real in s_validDoubleValues)

0 commit comments

Comments
 (0)