diff --git a/src/Managed.UnitTests/ComplexTests/ComplexTest.cs b/src/Managed.UnitTests/ComplexTests/ComplexTest.cs index f535cebf..23d04de8 100644 --- a/src/Managed.UnitTests/ComplexTests/ComplexTest.cs +++ b/src/Managed.UnitTests/ComplexTests/ComplexTest.cs @@ -593,5 +593,114 @@ Assert.Throws( () => Complex.WithModulusArgument(-1, 1), "Throws exception because modulus is negative."); } + + + [Test] + [Row(1,-2,"1 -2i")] + [Row(1, 2, "1 + 2i")] + [Row(1, 0, "1")] + [Row(0, -2, "-2i")] + [Row(0, 2, "2i")] + public void CanConvertComplexToString(double real, double imag, string expected) + { + var a = new Complex(real, imag); + Assert.AreEqual(expected, a.ToString()); + } + + [Test] + [Row("")] + [Row("+")] + [Row("1i+2")] + [Row(null)] + public void TryParseReturnsFalseWhenGiveBadValue(string str) + { + Complex z; + bool ret = Complex.TryParse(str, out z); + Assert.IsFalse(ret); + Assert.AreEqual(0, z.Real); + Assert.AreEqual(0, z.Imaginary); + } + + [Test] + public void TryParseCanHandleSymbols() + { + Complex z; + var ni = new NumberFormatInfo(); + var ret = Complex.TryParse(ni.NegativeInfinitySymbol + "," + ni.PositiveInfinitySymbol, out z); + Assert.IsTrue(ret); + Assert.AreEqual(double.NegativeInfinity, z.Real); + Assert.AreEqual(double.PositiveInfinity, z.Imaginary); + + ret = Complex.TryParse(ni.NaNSymbol + "," + ni.NaNSymbol, out z); + Assert.IsTrue(ret); + Assert.AreEqual(double.NaN, z.Real); + Assert.AreEqual(double.NaN, z.Imaginary); + + ret = Complex.TryParse(ni.NegativeInfinitySymbol + "+" + ni.PositiveInfinitySymbol + "i", out z); + Assert.IsTrue(ret); + Assert.AreEqual(double.NegativeInfinity, z.Real); + Assert.AreEqual(double.PositiveInfinity, z.Imaginary); + + ret = Complex.TryParse(ni.NaNSymbol + "+" + ni.NaNSymbol + "i", out z); + Assert.IsTrue(ret); + Assert.AreEqual(double.NaN, z.Real); + Assert.AreEqual(double.NaN, z.Imaginary); + + ret = Complex.TryParse(double.MaxValue.ToString("R") + " " + double.MinValue.ToString("R") + "i", out z); + Assert.IsTrue(ret); + Assert.AreEqual(double.MaxValue, z.Real); + Assert.AreEqual(double.MinValue, z.Imaginary); + + } + + [Test] + [Row("-1", -1, 0)] + [Row("-i", 0, -1)] + [Row("i", 0, 1)] + [Row("2i", 0, 2)] + [Row("1 + 2i", 1, 2)] + [Row("1+2i", 1, 2)] + [Row("1 - 2i", 1, -2)] + [Row("1-2i", 1, -2)] + [Row("1,2", 1, 2)] + [Row("1 , 2", 1, 2)] + [Row("1,2i", 1, 2)] + [Row("-1, -2i", -1, -2)] + [Row("(+1,2i)", 1, 2)] + [Row("(-1 , -2)", -1, -2)] + [Row("(-1 , -2i)", -1, -2)] + [Row("(+1e1 , -2e-2i)", 10, -0.02)] + [Row("(-1E1 -2e2i)", -10, -200)] + [Row("(-1e+1 -2e2i)", -10, -200)] + [Row("(-1e1 -2e+2i)", -10, -200)] + [Row("(-1e-1 -2E2i)", -0.1, -200)] + [Row("(-1e1 -2e-2i)", -10, -0.02)] + [Row("(-1E+1 -2e+2i)", -10, -200)] + [Row("(-1e-1,-2e-2i)", -0.1, -0.02)] + [Row("(+1 +2i)", 1, 2)] + public void CanConvertStringToComplexUsingTryParse(string str, double expectedReal, double expectedImag) + { + Complex z; + var ret = Complex.TryParse(str, out z); + Assert.IsTrue(ret); + Assert.AreEqual(expectedReal, z.Real); + Assert.AreEqual(expectedImag, z.Imaginary); + + ret = Complex.TryParse("(-1E+1 -2e+2i)", out z); + Assert.IsTrue(ret); + Assert.AreEqual(-10, z.Real); + Assert.AreEqual(-200, z.Imaginary); + + ret = Complex.TryParse("(-1e-1,-2e-2i)", out z); + Assert.IsTrue(ret); + Assert.AreEqual(-.1, z.Real); + Assert.AreEqual(-.02, z.Imaginary); + + ret = Complex.TryParse("(+1 +2i)", out z); + Assert.IsTrue(ret); + Assert.AreEqual(1, z.Real); + Assert.AreEqual(2, z.Imaginary); + } + } } \ No newline at end of file diff --git a/src/Managed/Complex.cs b/src/Managed/Complex.cs index 2ff5fc02..49b3e806 100644 --- a/src/Managed/Complex.cs +++ b/src/Managed/Complex.cs @@ -1062,27 +1062,6 @@ namespace MathNet.Numerics #endregion - #region Trigonometric Functions - - /// - /// Trigonometric Sine (sin, Sinus) of this Complex. - /// - /// - /// The sine of the complex number. - /// - public Complex Sine() - { - if (this.IsReal) - { - return new Complex(Math.Sin(this._real), 0.0); - } - - return new Complex( - Math.Sin(this._real) * Math.Cosh(this._imag), Math.Cos(this._real) * Math.Sinh(this._imag)); - } - - #endregion - #region IPrecisionSupport /// @@ -1107,5 +1086,169 @@ namespace MathNet.Numerics } #endregion + + #region Parse Functions + /// + /// Creates a complex number based on a string. The string can be in the following + /// formats(without the quotes): 'n', 'ni', 'n +/- ni', 'n,n', 'n,ni,' '(n,n)', or + /// '(n,ni)', where n is a real number. + /// + /// A complex number containing the value specified by the given string. + /// The string to parse. + public static Complex Parse(string value) + { + return Parse(value, null); + } + + /// + /// Creates a complex number based on a string. The string can be in the following + /// formats(without the quotes): 'n', 'ni', 'n +/- ni', 'n,n', 'n,ni,' '(n,n)', or + /// '(n,ni)', where n is a double. + /// + /// A complex number containing the value specified by the given string. + /// the string to parse. + /// An IFormatProvider that supplies culture-specific formatting information. + public static Complex Parse(string value, IFormatProvider formatProvider) + { + if (value == null) + { + throw new ArgumentNullException(value); + } + + value = value.Trim(); + if (value.Length == 0) + { + throw new FormatException(); + } + + value = value.Replace(" ", string.Empty); + + // strip out parens + if (value.StartsWith("(", StringComparison.Ordinal)) + { + if (!value.EndsWith(")", StringComparison.Ordinal)) + { + throw new FormatException(); + } + + value = value.Substring(1, value.Length - 2); + } + + // check if one character strings are valid + if (value.Length == 1) + { + if (String.Compare(value, "i", StringComparison.OrdinalIgnoreCase) == 0) + { + return new Complex(0, 1); + } + + return new Complex(Double.Parse(value, formatProvider), 0.0); + } + + if (value.Equals("-i")) + { + return new Complex(0, -1); + } + + var real = 0.0; + var imag = 0.0; + + var index = value.IndexOf(','); + + if (index > -1) + { + real = double.Parse(value.Substring(0, index), formatProvider); + var imagStr = value.Substring(index + 1, value.Length - index - 1); + if (imagStr.EndsWith("i")) + { + imagStr = imagStr.Substring(0, imagStr.Length - 1); + } + + imag = double.Parse(imagStr, formatProvider); + } + else + { + var matchResult = ParseExpression.Match(value); + if (matchResult.Success) + { + var realStr = matchResult.Groups["r"].Value; + if (!string.IsNullOrEmpty(realStr)) + { + if (realStr.StartsWith("+")) + { + realStr = realStr.Substring(1); + } + + real = double.Parse(realStr, formatProvider); + } + + var imagStr = matchResult.Groups["i"].Value; + + if (!string.IsNullOrEmpty(imagStr)) + { + if (imagStr.StartsWith("+")) + { + imagStr = imagStr.Substring(1); + } + + imagStr = imagStr.Substring(0, imagStr.Length - 1); + imag = double.Parse(imagStr, formatProvider); + } + } + else + { + throw new FormatException(); + } + } + + return new Complex(real, imag); + } + + /// + /// Converts the string representation of a complex number to a double-precision complex number equivalent. + /// A return value indicates whether the conversion succeeded or failed. + /// + /// A string containing a complex number to convert. + /// The parsed value. + /// If the conversion succeeds, the result will contain a complex number equivalent to value. + /// Otherwise the result will contain complex32.Zero. This parameter is passed uninitialized + public static bool TryParse(string value, out Complex result) + { + return TryParse(value, null, out result); + } + + /// + /// Converts the string representation of a complex number to double-precision complex number equivalent. + /// A return value indicates whether the conversion succeeded or failed. + /// + /// A string containing a complex number to convert. + /// An IFormatProvider that supplies culture-specific formatting information about value. + /// The parsed value. + /// + /// If the conversion succeeds, the result will contain a complex number equivalent to value. + /// Otherwise the result will contain complex32.Zero. This parameter is passed uninitialized + /// + public static bool TryParse(string value, IFormatProvider formatProvider, out Complex result) + { + bool ret; + try + { + result = Parse(value, formatProvider); + ret = true; + } + catch (ArgumentNullException) + { + result = zero; + ret = false; + } + catch (FormatException) + { + result = zero; + ret = false; + } + + return ret; + } + #endregion } } \ No newline at end of file