Browse Source

globalization: complex ToString and Parse

Signed-off-by: Christoph Ruegg <git@cdrnet.ch>
pull/2/head
Christoph Ruegg 17 years ago
parent
commit
aa4ec83404
  1. 186
      src/Numerics/Complex.cs
  2. 189
      src/UnitTests/ComplexTests/ComplexTest.cs
  3. 282
      src/UnitTests/ComplexTests/ComplexTextHandlingTest.cs
  4. 1
      src/UnitTests/UnitTests.csproj

186
src/Numerics/Complex.cs

@ -29,9 +29,9 @@
namespace MathNet.Numerics namespace MathNet.Numerics
{ {
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Properties; using Properties;
/// <summary> /// <summary>
@ -73,14 +73,6 @@ namespace MathNet.Numerics
{ {
#region fields #region fields
/// <summary>
/// Regular expression used to parse strings into complex numbers.
/// </summary>
private static readonly Regex _parseExpression =
new Regex(
@"^((?<r>(([-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity)))|(?<i>(([-+]?((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity))?[i]))|(?<r>(([-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity)))(?<i>(([-+]((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|[-+](NaN)|([-+]Infinity))?[i])))$",
RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
/// <summary> /// <summary>
/// Represents imaginary unit number. /// Represents imaginary unit number.
/// </summary> /// </summary>
@ -121,7 +113,7 @@ namespace MathNet.Numerics
#region Constructor #region Constructor
/// <summary> /// <summary>
/// Initializes a new instance of the Complex struct with the given real /// Initializes a new instance of the Complex structure with the given real
/// and imaginary parts. /// and imaginary parts.
/// </summary> /// </summary>
/// <param name="real"> /// <param name="real">
@ -149,8 +141,7 @@ namespace MathNet.Numerics
/// infinite real and imaginary part. If you need more formal complex /// infinite real and imaginary part. If you need more formal complex
/// number handling (according to the Riemann Sphere and the extended /// number handling (according to the Riemann Sphere and the extended
/// complex plane C*, or using directed infinity) please check out the /// complex plane C*, or using directed infinity) please check out the
/// alternative MathNet.PreciseNumerics and MathNet.Symbolics packages /// alternative Math.NET symbolics packages instead.
/// instead.
/// </remarks> /// </remarks>
/// <value>A value representing the infinity value.</value> /// <value>A value representing the infinity value.</value>
public static Complex Infinity public static Complex Infinity
@ -242,10 +233,13 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Gets a value indicating whether the provided <c>Complex</c> evaluates to a /// Gets a value indicating whether the provided <c>Complex</c>evaluates
/// value that is not a number. /// to a value that is not a number.
/// </summary> /// </summary>
/// <value><c>true</c> if this instance is NaN; otherwise, <c>false</c>.</value> /// <value>
/// <c>true</c> if this instance is <see cref="NaN"/>; otherwise,
/// <c>false</c>.
/// </value>
public bool IsNaN public bool IsNaN
{ {
get { return double.IsNaN(_real) || double.IsNaN(_imag); } get { return double.IsNaN(_real) || double.IsNaN(_imag); }
@ -644,14 +638,16 @@ namespace MathNet.Numerics
/// </param> /// </param>
public string ToString(string format, IFormatProvider formatProvider) public string ToString(string format, IFormatProvider formatProvider)
{ {
var numberFormatInfo = formatProvider.GetNumberFormatInfo();
if (IsNaN) if (IsNaN)
{ {
return "NaN"; return numberFormatInfo.NaNSymbol;
} }
if (IsInfinity) if (IsInfinity)
{ {
return "Infinity"; return numberFormatInfo.PositiveInfinitySymbol;
} }
var ret = new StringBuilder(); var ret = new StringBuilder();
@ -678,6 +674,11 @@ namespace MathNet.Numerics
ret.Append(_imag.ToString(format, formatProvider)).Append("i"); ret.Append(_imag.ToString(format, formatProvider)).Append("i");
} }
if (ret.Length == 0)
{
ret.Append((0.0).ToString(format, formatProvider));
}
return ret.ToString(); return ret.ToString();
} }
@ -1041,9 +1042,9 @@ namespace MathNet.Numerics
#region Parse Functions #region Parse Functions
/// <summary> /// <summary>
/// Creates a complex number based on a string. The string can be in the following /// Creates a complex number based on a string. The string can be in the
/// formats(without the quotes): 'n', 'ni', 'n +/- ni', 'n,n', 'n,ni,' '(n,n)', or /// following formats (without the quotes): 'n', 'ni', 'n +/- ni',
/// '(n,ni)', where n is a real number. /// 'ni +/- n', 'n,n', 'n,ni,' '(n,n)', or '(n,ni)', where n is a double.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A complex number containing the value specified by the given string. /// A complex number containing the value specified by the given string.
@ -1057,9 +1058,9 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Creates a complex number based on a string. The string can be in the following /// Creates a complex number based on a string. The string can be in the
/// formats(without the quotes): 'n', 'ni', 'n +/- ni', 'n,n', 'n,ni,' '(n,n)', or /// following formats (without the quotes): 'n', 'ni', 'n +/- ni',
/// '(n,ni)', where n is a double. /// 'ni +/- n', 'n,n', 'n,ni,' '(n,n)', or '(n,ni)', where n is a double.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A complex number containing the value specified by the given string. /// A complex number containing the value specified by the given string.
@ -1068,7 +1069,8 @@ namespace MathNet.Numerics
/// the string to parse. /// the string to parse.
/// </param> /// </param>
/// <param name="formatProvider"> /// <param name="formatProvider">
/// An <see cref="IFormatProvider"/> that supplies culture-specific formatting information. /// An <see cref="IFormatProvider"/> that supplies culture-specific
/// formatting information.
/// </param> /// </param>
public static Complex Parse(string value, IFormatProvider formatProvider) public static Complex Parse(string value, IFormatProvider formatProvider)
{ {
@ -1083,8 +1085,6 @@ namespace MathNet.Numerics
throw new FormatException(); throw new FormatException();
} }
value = value.Replace(" ", string.Empty);
// strip out parens // strip out parens
if (value.StartsWith("(", StringComparison.Ordinal)) if (value.StartsWith("(", StringComparison.Ordinal))
{ {
@ -1093,77 +1093,137 @@ namespace MathNet.Numerics
throw new FormatException(); throw new FormatException();
} }
value = value.Substring(1, value.Length - 2); value = value.Substring(1, value.Length - 2).Trim();
} }
// check if one character strings are valid // keywords
if (value.Length == 1) var numberFormatInfo = formatProvider.GetNumberFormatInfo();
var textInfo = formatProvider.GetTextInfo();
var keywords =
new[]
{ {
if (String.Compare(value, "i", StringComparison.OrdinalIgnoreCase) == 0) textInfo.ListSeparator, numberFormatInfo.NaNSymbol,
numberFormatInfo.NegativeInfinitySymbol, numberFormatInfo.PositiveInfinitySymbol,
"+", "-", "i", "j"
};
// lexing
var tokens = new LinkedList<string>();
GlobalizationHelper.Tokenize(tokens.AddFirst(value), keywords, 0);
var token = tokens.First;
// parse the left part
bool isLeftPartImaginary;
double leftPart = ParsePart(ref token, out isLeftPartImaginary, formatProvider);
if (token == null)
{ {
return new Complex(0, 1); return isLeftPartImaginary ? new Complex(0, leftPart) : new Complex(leftPart, 0);
} }
return new Complex(Double.Parse(value, formatProvider), 0.0); // parse the right part
} if (token.Value == textInfo.ListSeparator)
{
// format: real,imag
token = token.Next;
if (value.Equals("-i")) if (isLeftPartImaginary)
{ {
return new Complex(0, -1); // left must not contain 'i', right doesn't matter.
throw new FormatException();
} }
var real = 0.0; bool isRightPartImaginary;
var imag = 0.0; double rightPart = ParsePart(ref token, out isRightPartImaginary, formatProvider);
var index = value.IndexOf(',');
if (index > -1) return new Complex(leftPart, rightPart);
}
else
{ {
real = double.Parse(value.Substring(0, index), formatProvider); // format: real + imag
var imagStr = value.Substring(index + 1, value.Length - index - 1); bool isRightPartImaginary;
if (imagStr.EndsWith("i")) double rightPart = ParsePart(ref token, out isRightPartImaginary, formatProvider);
if (!(isLeftPartImaginary ^ isRightPartImaginary))
{ {
imagStr = imagStr.Substring(0, imagStr.Length - 1); // either left or right part must contain 'i', but not both.
throw new FormatException();
} }
imag = double.Parse(imagStr, formatProvider); return isLeftPartImaginary ? new Complex(rightPart, leftPart) : new Complex(leftPart, rightPart);
} }
else }
/// <summary>
/// Parse a part (real or complex) from a complex number.
/// </summary>
/// <param name="token">Start Token.</param>
/// <param name="imaginary">Is set to <c>true</c> if the part identified itself as being imaginary.</param>
/// <param name="format">
/// An <see cref="IFormatProvider"/> that supplies culture-specific
/// formatting information.
/// </param>
/// <returns>Resulting part as double.</returns>
/// <exception cref="FormatException"/>
private static double ParsePart(ref LinkedListNode<string> token, out bool imaginary, IFormatProvider format)
{ {
var matchResult = _parseExpression.Match(value); imaginary = false;
if (matchResult.Success) if (token == null)
{ {
var realStr = matchResult.Groups["r"].Value; throw new FormatException();
if (!string.IsNullOrEmpty(realStr)) }
// handle prefix modifiers
if (token.Value == "+")
{ {
if (realStr.StartsWith("+")) token = token.Next;
if (token == null)
{ {
realStr = realStr.Substring(1); throw new FormatException();
} }
real = double.Parse(realStr, formatProvider);
} }
var imagStr = matchResult.Groups["i"].Value; bool negative = false;
if (token.Value == "-")
if (!string.IsNullOrEmpty(imagStr))
{ {
if (imagStr.StartsWith("+")) negative = true;
token = token.Next;
if (token == null)
{ {
imagStr = imagStr.Substring(1); throw new FormatException();
}
} }
imagStr = imagStr.Substring(0, imagStr.Length - 1); // handle prefix imaginary symbol
imag = double.Parse(imagStr, formatProvider); if (String.Compare(token.Value, "i", StringComparison.OrdinalIgnoreCase) == 0
|| String.Compare(token.Value, "j", StringComparison.OrdinalIgnoreCase) == 0)
{
imaginary = true;
token = token.Next;
if (token == null)
{
return negative ? -1 : 1;
} }
} }
else
double value = GlobalizationHelper.ParseDouble(ref token, format.GetCultureInfo());
// handle suffix imaginary symbol
if (token != null && String.Compare(token.Value, "i", StringComparison.OrdinalIgnoreCase) == 0)
{ {
if (imaginary)
{
// only one time allowed: either prefix or suffix, or neither.
throw new FormatException(); throw new FormatException();
} }
imaginary = true;
token = token.Next;
} }
return new Complex(real, imag); return negative ? -value : value;
} }
/// <summary> /// <summary>

189
src/UnitTests/ComplexTests/ComplexTest.cs

@ -1,8 +1,34 @@
namespace MathNet.Numerics.UnitTests // <copyright file="ComplexTest.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.UnitTests.ComplexTests
{ {
using System; using System;
using System.Globalization;
using MbUnit.Framework; using MbUnit.Framework;
[TestFixture] [TestFixture]
@ -130,7 +156,6 @@
a = new Complex(0.0, 0.0); a = new Complex(0.0, 0.0);
b = new Complex(0.0, 1.0); b = new Complex(0.0, 1.0);
AssertEx.That(() => a.Power(b).IsNaN); AssertEx.That(() => a.Power(b).IsNaN);
} }
[Test] [Test]
@ -200,18 +225,6 @@
AssertHelpers.AlmostEqual(Complex.Zero, complex.SquareRoot(), 15); AssertHelpers.AlmostEqual(Complex.Zero, complex.SquareRoot(), 15);
} }
[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] [Test]
[MultipleAsserts] [MultipleAsserts]
public void CanConvertDoubleToComplex() public void CanConvertDoubleToComplex()
@ -221,68 +234,6 @@
Assert.AreEqual(1.1, new Complex(1.1, 0)); Assert.AreEqual(1.1, new Complex(1.1, 0));
} }
[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);
}
[Test]
public void CanParseStringToComplex()
{
var actual = Complex.Parse("-1 -2i");
Assert.AreEqual(new Complex(-1,-2), actual);
}
[Test]
public void ParseThrowsFormatExceptionIfMissingClosingParen()
{
Assert.Throws<FormatException>(() => Complex.Parse("(1,2"));
}
[Test] [Test]
[MultipleAsserts] [MultipleAsserts]
public void CanCreateComplexNumberUsingTheConstructor() public void CanCreateComplexNumberUsingTheConstructor()
@ -310,43 +261,6 @@
Assert.AreEqual(-2.2, complex.Imaginary, "Imaginary part is -2.2."); Assert.AreEqual(-2.2, complex.Imaginary, "Imaginary part is -2.2.");
} }
[Test]
[MultipleAsserts]
public void CanCreateStringFromComplexNumber()
{
Assert.AreEqual("NaN", Complex.NaN.ToString());
Assert.AreEqual("Infinity", Complex.Infinity.ToString());
Assert.AreEqual("1.1", new Complex(1.1, 0).ToString());
Assert.AreEqual("-1.1i", new Complex(0, -1.1).ToString());
Assert.AreEqual("1.1i", new Complex(0, 1.1).ToString());
Assert.AreEqual("1.1 + 1.1i", new Complex(1.1, 1.1).ToString());
}
[Test]
[MultipleAsserts]
public void CanCreateStringUsingFormatProvider()
{
var provider = CultureInfo.GetCultureInfo("tr-TR");
Assert.AreEqual("NaN", Complex.NaN.ToString(provider));
Assert.AreEqual("Infinity", Complex.Infinity.ToString(provider));
Assert.AreEqual("1,1", new Complex(1.1, 0).ToString(provider));
Assert.AreEqual("-1,1i", new Complex(0, -1.1).ToString(provider));
Assert.AreEqual("1,1i", new Complex(0, 1.1).ToString(provider));
Assert.AreEqual("1,1 + 1,1i", new Complex(1.1, 1.1).ToString(provider));
}
[Test]
[MultipleAsserts]
public void CanCreateStringUsingNumberFormat()
{
Assert.AreEqual("NaN", Complex.NaN.ToString("#.000"));
Assert.AreEqual("Infinity", Complex.Infinity.ToString("#.000"));
Assert.AreEqual("1.100", new Complex(1.1, 0).ToString("#.000"));
Assert.AreEqual("-1.100i", new Complex(0, -1.1).ToString("#.000"));
Assert.AreEqual("1.100i", new Complex(0, 1.1).ToString("#.000"));
Assert.AreEqual("1.100 + 1.100i", new Complex(1.1, 1.1).ToString("#.000"));
}
[Test] [Test]
public void CanDetermineIfImaginaryUnit() public void CanDetermineIfImaginaryUnit()
{ {
@ -532,51 +446,6 @@
Assert.AreEqual(complex, +complex); Assert.AreEqual(complex, +complex);
} }
[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("")]
[Row("+")]
[Row("1i+2")]
[Row(null)]
public void TryParseReturnsFalseWhenGiveBadValue(string str)
{
Complex z;
var ret = Complex.TryParse(str, out z);
Assert.IsFalse(ret);
Assert.AreEqual(0, z.Real);
Assert.AreEqual(0, z.Imaginary);
}
[Test] [Test]
public void WithModulusArgumentThrowsArgumentOutOfRangeException() public void WithModulusArgumentThrowsArgumentOutOfRangeException()
{ {

282
src/UnitTests/ComplexTests/ComplexTextHandlingTest.cs

@ -0,0 +1,282 @@
// <copyright file="ComplexGlobalizedTextTest.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.UnitTests.ComplexTests
{
using System;
using System.Globalization;
using MbUnit.Framework;
[TestFixture]
public class ComplexTextHandlingTest
{
[Test]
[Row(1, -2, "1 -2i")]
[Row(1, 2, "1 + 2i")]
[Row(1, 0, "1")]
[Row(0, -2, "-2i")]
[Row(0, 2, "2i")]
[Row(0, 2, "2i")]
[Row(0, 0, "0")]
[Row(Double.NaN, Double.NaN, "{1}")]
[Row(Double.NaN, 0, "{1}")]
[Row(0, Double.NaN, "{1}")]
[Row(Double.PositiveInfinity, Double.PositiveInfinity, "{2}")]
[Row(1.1, 0, "1{0}1")]
[Row(-1.1, 0, "-1{0}1")]
[Row(0, 1.1, "1{0}1i")]
[Row(0, -1.1, "-1{0}1i")]
[Row(1.1, 1.1, "1{0}1 + 1{0}1i")]
public void CanFormatComplexToString(double real, double imag, string expected)
{
var numberFormat = NumberFormatInfo.CurrentInfo;
var a = new Complex(real, imag);
Assert.AreEqual(
String.Format(
expected,
numberFormat.NumberDecimalSeparator,
numberFormat.NaNSymbol,
numberFormat.PositiveInfinitySymbol),
a.ToString());
}
[Test]
[MultipleAsserts]
[Row("en-US", "NaN", "Infinity", "1.1")]
[Row("tr-TR", "NaN", "Infinity", "1,1")]
[Row("de-DE", "n. def.", "+unendlich", "1,1")]
[Row("de-CH", "n. def.", "+unendlich", "1.1")]
[Row("he-IL", "לא מספר", "אינסוף חיובי", "1.1")]
public void CanFormatComplexToStringWithCulture(
string cultureName, string nan, string infinity, string number)
{
var provider = CultureInfo.GetCultureInfo(cultureName);
Assert.AreEqual(nan, Complex.NaN.ToString(provider));
Assert.AreEqual(infinity, Complex.Infinity.ToString(provider));
Assert.AreEqual("0", Complex.Zero.ToString(provider));
Assert.AreEqual(String.Format("{0}", number), new Complex(1.1, 0).ToString(provider));
Assert.AreEqual(String.Format("-{0}", number), new Complex(-1.1, 0).ToString(provider));
Assert.AreEqual(String.Format("-{0}i", number), new Complex(0, -1.1).ToString(provider));
Assert.AreEqual(String.Format("{0}i", number), new Complex(0, 1.1).ToString(provider));
Assert.AreEqual(String.Format("{0} + {0}i", number), new Complex(1.1, 1.1).ToString(provider));
}
[Test]
[MultipleAsserts]
public void CanFormatComplexToStringWithFormat()
{
Assert.AreEqual("0", String.Format("{0:G}", Complex.Zero));
Assert.AreEqual("1 + 2i", String.Format("{0:G}", new Complex(1, 2)));
Assert.AreEqual("001 + 002i", String.Format("{0:000;minus 000;zero}", new Complex(1, 2)));
Assert.AreEqual("minus 002i", String.Format("{0:000;minus 000;zero}", new Complex(0, -2)));
Assert.AreEqual("zero", String.Format("{0:000;minus 000;zero}", Complex.Zero));
Assert.AreEqual("0", Complex.Zero.ToString("G"));
Assert.AreEqual("1 + 2i", new Complex(1, 2).ToString("G"));
Assert.AreEqual("001 + 002i", new Complex(1, 2).ToString("#000;minus 000;zero"));
Assert.AreEqual("minus 002i", new Complex(0, -2).ToString("#000;minus 000;zero"));
Assert.AreEqual("zero", Complex.Zero.ToString("#000;minus 000;zero"));
}
[Test]
[MultipleAsserts]
public void CanFormatComplexToStringWithFormatInvariant()
{
var culture = CultureInfo.InvariantCulture;
Assert.AreEqual("NaN", String.Format(culture, "{0:.000}", Complex.NaN));
Assert.AreEqual(".000", String.Format(culture, "{0:.000}", Complex.Zero));
Assert.AreEqual("1.100", String.Format(culture, "{0:.000}", new Complex(1.1, 0)));
Assert.AreEqual("1.100 + 1.100i", String.Format(culture, "{0:.000}", new Complex(1.1, 1.1)));
Assert.AreEqual("NaN", Complex.NaN.ToString("#.000", culture));
Assert.AreEqual("Infinity", Complex.Infinity.ToString("#.000", culture));
Assert.AreEqual(".000", Complex.Zero.ToString("#.000", culture));
Assert.AreEqual("1.100", new Complex(1.1, 0).ToString("#.000", culture));
Assert.AreEqual("-1.100i", new Complex(0, -1.1).ToString("#.000", culture));
Assert.AreEqual("1.100i", new Complex(0, 1.1).ToString("#.000", culture));
Assert.AreEqual("1.100 + 1.100i", new Complex(1.1, 1.1).ToString("#.000", culture));
}
[Test]
[Row("-1 -2i", -1, -2, "en-US")]
[Row("-1 - 2i ", -1, -2, "de-CH")]
public void CanParseStringToComplexWithCulture(
string text, double expectedReal, double expectedImaginary, string cultureName)
{
Complex parsed = Complex.Parse(text, CultureInfo.GetCultureInfo(cultureName));
Assert.AreEqual(expectedReal, parsed.Real);
Assert.AreEqual(expectedImaginary, parsed.Imaginary);
}
[Test]
[Row("1", 1, 0)]
[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 , - 2 i ", -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)]
[Row("(-1E+1 -2e+2i)", -10, -200)]
[Row("(-1e-1,-2e-2i)", -0.1, -0.02)]
public void CanTryParseStringToComplexWithInvariant(string str, double expectedReal, double expectedImaginary)
{
var invariantCulture = CultureInfo.InvariantCulture;
Complex z;
var ret = Complex.TryParse(str, invariantCulture, out z);
Assert.IsTrue(ret);
Assert.AreEqual(expectedReal, z.Real);
Assert.AreEqual(expectedImaginary, z.Imaginary);
}
[Test]
public void ParseThrowsFormatExceptionIfMissingClosingParen()
{
Assert.Throws<FormatException>(() => Complex.Parse("(1,2"));
}
[Test]
public void TryParseCanHandleSymbols()
{
Complex z;
var ni = NumberFormatInfo.CurrentInfo;
var separator = CultureInfo.CurrentCulture.TextInfo.ListSeparator;
var ret = Complex.TryParse(
ni.NegativeInfinitySymbol + separator + ni.PositiveInfinitySymbol, out z);
Assert.IsTrue(ret, "A1");
Assert.AreEqual(double.NegativeInfinity, z.Real, "A2");
Assert.AreEqual(double.PositiveInfinity, z.Imaginary, "A3");
ret = Complex.TryParse(ni.NaNSymbol + separator + ni.NaNSymbol, out z);
Assert.IsTrue(ret, "B1");
Assert.AreEqual(double.NaN, z.Real, "B2");
Assert.AreEqual(double.NaN, z.Imaginary, "B3");
ret = Complex.TryParse(ni.NegativeInfinitySymbol + "+" + ni.PositiveInfinitySymbol + "i", out z);
Assert.IsTrue(ret, "C1");
Assert.AreEqual(double.NegativeInfinity, z.Real, "C2");
Assert.AreEqual(double.PositiveInfinity, z.Imaginary, "C3");
ret = Complex.TryParse(ni.NaNSymbol + "+" + ni.NaNSymbol + "i", out z);
Assert.IsTrue(ret, "D1");
Assert.AreEqual(double.NaN, z.Real, "D2");
Assert.AreEqual(double.NaN, z.Imaginary, "D3");
ret = Complex.TryParse(
double.MaxValue.ToString("R") + " " + double.MinValue.ToString("R") + "i",
out z);
Assert.IsTrue(ret, "E1");
Assert.AreEqual(double.MaxValue, z.Real, "E2");
Assert.AreEqual(double.MinValue, z.Imaginary, "E3");
}
[Test]
[Row("en-US")]
[Row("tr-TR")]
[Row("de-DE")]
[Row("de-CH")]
[Row("he-IL")]
public void TryParseCanHandleSymbolsWithCulture(string cultureName)
{
Complex z;
var culture = CultureInfo.GetCultureInfo(cultureName);
var ni = culture.NumberFormat;
var separator = culture.TextInfo.ListSeparator;
var ret = Complex.TryParse(
ni.NegativeInfinitySymbol + separator + ni.PositiveInfinitySymbol, culture, out z);
Assert.IsTrue(ret, "A1");
Assert.AreEqual(double.NegativeInfinity, z.Real, "A2");
Assert.AreEqual(double.PositiveInfinity, z.Imaginary, "A3");
ret = Complex.TryParse(ni.NaNSymbol + separator + ni.NaNSymbol, culture, out z);
Assert.IsTrue(ret, "B1");
Assert.AreEqual(double.NaN, z.Real, "B2");
Assert.AreEqual(double.NaN, z.Imaginary, "B3");
ret = Complex.TryParse(ni.NegativeInfinitySymbol + "+" + ni.PositiveInfinitySymbol + "i", culture, out z);
Assert.IsTrue(ret, "C1");
Assert.AreEqual(double.NegativeInfinity, z.Real, "C2");
Assert.AreEqual(double.PositiveInfinity, z.Imaginary, "C3");
ret = Complex.TryParse(ni.NaNSymbol + "+" + ni.NaNSymbol + "i", culture, out z);
Assert.IsTrue(ret, "D1");
Assert.AreEqual(double.NaN, z.Real, "D2");
Assert.AreEqual(double.NaN, z.Imaginary, "D3");
ret = Complex.TryParse(
double.MaxValue.ToString("R", culture) + " " + double.MinValue.ToString("R", culture) + "i",
culture,
out z);
Assert.IsTrue(ret, "E1");
Assert.AreEqual(double.MaxValue, z.Real, "E2");
Assert.AreEqual(double.MinValue, z.Imaginary, "E3");
}
[Test]
[Row("")]
[Row("+")]
[Row("1-")]
[Row("i+")]
[Row("1/2i")]
[Row("1i+2i")]
[Row("i1i")]
[Row("(1i,2)")]
[Row("1e+")]
[Row("1e")]
[Row("1,")]
[Row(",1")]
[Row(null)]
public void TryParseReturnsFalseWhenGiveBadValueWithInvariant(string str)
{
Complex z;
var ret = Complex.TryParse(str, CultureInfo.InvariantCulture, out z);
Assert.IsFalse(ret);
Assert.AreEqual(0, z.Real);
Assert.AreEqual(0, z.Imaginary);
}
}
}

1
src/UnitTests/UnitTests.csproj

@ -62,6 +62,7 @@
<Compile Include="ArgumentCheckContract.cs" /> <Compile Include="ArgumentCheckContract.cs" />
<Compile Include="AssertHelpers.cs" /> <Compile Include="AssertHelpers.cs" />
<Compile Include="CombinatoricsTests\CombinatoricsCountingTest.cs" /> <Compile Include="CombinatoricsTests\CombinatoricsCountingTest.cs" />
<Compile Include="ComplexTests\ComplexTextHandlingTest.cs" />
<Compile Include="ComplexTests\ComplexTest.cs" /> <Compile Include="ComplexTests\ComplexTest.cs" />
<Compile Include="DistributionTests\CommonDistributionTests.cs" /> <Compile Include="DistributionTests\CommonDistributionTests.cs" />
<Compile Include="DistributionTests\Continuous\BetaTests.cs" /> <Compile Include="DistributionTests\Continuous\BetaTests.cs" />

Loading…
Cancel
Save