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. 204
      src/Numerics/Complex.cs
  2. 191
      src/UnitTests/ComplexTests/ComplexTest.cs
  3. 282
      src/UnitTests/ComplexTests/ComplexTextHandlingTest.cs
  4. 1
      src/UnitTests/UnitTests.csproj

204
src/Numerics/Complex.cs

@ -29,9 +29,9 @@
namespace MathNet.Numerics
{
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using Properties;
/// <summary>
@ -73,14 +73,6 @@ namespace MathNet.Numerics
{
#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>
/// Represents imaginary unit number.
/// </summary>
@ -121,7 +113,7 @@ namespace MathNet.Numerics
#region Constructor
/// <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.
/// </summary>
/// <param name="real">
@ -149,8 +141,7 @@ namespace MathNet.Numerics
/// infinite real and imaginary part. If you need more formal complex
/// number handling (according to the Riemann Sphere and the extended
/// complex plane C*, or using directed infinity) please check out the
/// alternative MathNet.PreciseNumerics and MathNet.Symbolics packages
/// instead.
/// alternative Math.NET symbolics packages instead.
/// </remarks>
/// <value>A value representing the infinity value.</value>
public static Complex Infinity
@ -242,10 +233,13 @@ namespace MathNet.Numerics
}
/// <summary>
/// Gets a value indicating whether the provided <c>Complex</c> evaluates to a
/// value that is not a number.
/// Gets a value indicating whether the provided <c>Complex</c>evaluates
/// to a value that is not a number.
/// </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
{
get { return double.IsNaN(_real) || double.IsNaN(_imag); }
@ -644,14 +638,16 @@ namespace MathNet.Numerics
/// </param>
public string ToString(string format, IFormatProvider formatProvider)
{
var numberFormatInfo = formatProvider.GetNumberFormatInfo();
if (IsNaN)
{
return "NaN";
return numberFormatInfo.NaNSymbol;
}
if (IsInfinity)
{
return "Infinity";
return numberFormatInfo.PositiveInfinitySymbol;
}
var ret = new StringBuilder();
@ -678,6 +674,11 @@ namespace MathNet.Numerics
ret.Append(_imag.ToString(format, formatProvider)).Append("i");
}
if (ret.Length == 0)
{
ret.Append((0.0).ToString(format, formatProvider));
}
return ret.ToString();
}
@ -1041,9 +1042,9 @@ namespace MathNet.Numerics
#region Parse Functions
/// <summary>
/// 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.
/// Creates a complex number based on a string. The string can be in the
/// following formats (without the quotes): 'n', 'ni', 'n +/- ni',
/// 'ni +/- n', 'n,n', 'n,ni,' '(n,n)', or '(n,ni)', where n is a double.
/// </summary>
/// <returns>
/// A complex number containing the value specified by the given string.
@ -1057,9 +1058,9 @@ namespace MathNet.Numerics
}
/// <summary>
/// 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.
/// Creates a complex number based on a string. The string can be in the
/// following formats (without the quotes): 'n', 'ni', 'n +/- ni',
/// 'ni +/- n', 'n,n', 'n,ni,' '(n,n)', or '(n,ni)', where n is a double.
/// </summary>
/// <returns>
/// A complex number containing the value specified by the given string.
@ -1068,7 +1069,8 @@ namespace MathNet.Numerics
/// the string to parse.
/// </param>
/// <param name="formatProvider">
/// An <see cref="IFormatProvider"/> that supplies culture-specific formatting information.
/// An <see cref="IFormatProvider"/> that supplies culture-specific
/// formatting information.
/// </param>
public static Complex Parse(string value, IFormatProvider formatProvider)
{
@ -1083,8 +1085,6 @@ namespace MathNet.Numerics
throw new FormatException();
}
value = value.Replace(" ", string.Empty);
// strip out parens
if (value.StartsWith("(", StringComparison.Ordinal))
{
@ -1093,77 +1093,137 @@ namespace MathNet.Numerics
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
if (value.Length == 1)
{
if (String.Compare(value, "i", StringComparison.OrdinalIgnoreCase) == 0)
// keywords
var numberFormatInfo = formatProvider.GetNumberFormatInfo();
var textInfo = formatProvider.GetTextInfo();
var keywords =
new[]
{
return new Complex(0, 1);
}
return new Complex(Double.Parse(value, formatProvider), 0.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 isLeftPartImaginary ? new Complex(0, leftPart) : new Complex(leftPart, 0);
}
if (value.Equals("-i"))
// parse the right part
if (token.Value == textInfo.ListSeparator)
{
return new Complex(0, -1);
}
// format: real,imag
token = token.Next;
var real = 0.0;
var imag = 0.0;
if (isLeftPartImaginary)
{
// left must not contain 'i', right doesn't matter.
throw new FormatException();
}
var index = value.IndexOf(',');
bool isRightPartImaginary;
double rightPart = ParsePart(ref token, out isRightPartImaginary, formatProvider);
if (index > -1)
return new Complex(leftPart, rightPart);
}
else
{
real = double.Parse(value.Substring(0, index), formatProvider);
var imagStr = value.Substring(index + 1, value.Length - index - 1);
if (imagStr.EndsWith("i"))
// format: real + imag
bool isRightPartImaginary;
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)
{
imaginary = false;
if (token == null)
{
throw new FormatException();
}
// handle prefix modifiers
if (token.Value == "+")
{
var matchResult = _parseExpression.Match(value);
if (matchResult.Success)
token = token.Next;
if (token == null)
{
var realStr = matchResult.Groups["r"].Value;
if (!string.IsNullOrEmpty(realStr))
{
if (realStr.StartsWith("+"))
{
realStr = realStr.Substring(1);
}
throw new FormatException();
}
}
real = double.Parse(realStr, formatProvider);
}
bool negative = false;
if (token.Value == "-")
{
negative = true;
token = token.Next;
var imagStr = matchResult.Groups["i"].Value;
if (token == null)
{
throw new FormatException();
}
}
if (!string.IsNullOrEmpty(imagStr))
{
if (imagStr.StartsWith("+"))
{
imagStr = imagStr.Substring(1);
}
// handle prefix imaginary symbol
if (String.Compare(token.Value, "i", StringComparison.OrdinalIgnoreCase) == 0
|| String.Compare(token.Value, "j", StringComparison.OrdinalIgnoreCase) == 0)
{
imaginary = true;
token = token.Next;
imagStr = imagStr.Substring(0, imagStr.Length - 1);
imag = double.Parse(imagStr, formatProvider);
}
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();
}
imaginary = true;
token = token.Next;
}
return new Complex(real, imag);
return negative ? -value : value;
}
/// <summary>
@ -1226,4 +1286,4 @@ namespace MathNet.Numerics
#endregion
}
}
}

191
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.Globalization;
using MbUnit.Framework;
[TestFixture]
@ -129,8 +155,7 @@
AssertHelpers.AlmostEqual(new Complex(double.PositiveInfinity, double.PositiveInfinity), a.Power(b), 15);
a = new Complex(0.0, 0.0);
b = new Complex(0.0, 1.0);
AssertEx.That(()=>a.Power(b).IsNaN);
AssertEx.That(() => a.Power(b).IsNaN);
}
[Test]
@ -200,18 +225,6 @@
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]
[MultipleAsserts]
public void CanConvertDoubleToComplex()
@ -221,68 +234,6 @@
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]
[MultipleAsserts]
public void CanCreateComplexNumberUsingTheConstructor()
@ -310,43 +261,6 @@
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]
public void CanDetermineIfImaginaryUnit()
{
@ -532,51 +446,6 @@
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]
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="AssertHelpers.cs" />
<Compile Include="CombinatoricsTests\CombinatoricsCountingTest.cs" />
<Compile Include="ComplexTests\ComplexTextHandlingTest.cs" />
<Compile Include="ComplexTests\ComplexTest.cs" />
<Compile Include="DistributionTests\CommonDistributionTests.cs" />
<Compile Include="DistributionTests\Continuous\BetaTests.cs" />

Loading…
Cancel
Save