// // 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. // namespace MathNet.Numerics { using System; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using MathNet.Numerics.Properties; /// /// Complex numbers class. /// /// /// /// The class Complex provides all elementary operations /// on complex numbers. All the operators +, -, /// *, /, ==, != are defined in the /// canonical way. Additional complex trigonometric functions such /// as , ... /// are also provided. Note that the Complex structures /// has two special constant values and /// . /// /// /// In order to avoid possible ambiguities resulting from a /// Complex(double, double) constructor, the static methods /// and /// are provided instead. /// /// /// /// Complex x = Complex.FromRealImaginary(1d, 2d); /// Complex y = Complex.FromModulusArgument(1d, Math.Pi); /// Complex z = (x + y) / (x - y); /// /// /// /// For mathematical details about complex numbers, please /// have a look at the /// Wikipedia /// /// [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Complex : IFormattable, IEquatable, IPrecisionSupport { #region fields /// /// Regular expression used to parse strings into complex numbers. /// private static readonly Regex ParseExpression = new Regex( @"^((?(([-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity)))|(?(([-+]?((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity))?[i]))|(?(([-+]?(\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|(NaN)|([-+]?Infinity)))(?(([-+]((\d+\.?\d*|\d*\.?\d+)([Ee][-+]?[0-9]+)?)|[-+](NaN)|([-+]Infinity))?[i])))$", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); /// /// Represents imaginary unit number. /// private static readonly Complex i = new Complex(0, 1); /// /// Represents a infinite complex number /// private static readonly Complex infinity = new Complex(double.PositiveInfinity, double.PositiveInfinity); /// /// Represents not-a-number. /// private static readonly Complex nan = new Complex(Double.NaN, Double.NaN); /// /// Representing the one value. /// private static readonly Complex one = new Complex(1.0, 0.0); /// /// Representing the zero value. /// private static readonly Complex zero = new Complex(0.0, 0.0); /// /// The real component of the complex number. /// private readonly double _real; /// /// The imaginary component of the complex number. /// private readonly double _imag; #endregion fields #region Constructor /// /// Initializes a new instance of the Complex struct with the given real /// and imaginary parts. /// /// /// The value for the real component. /// /// /// The value for the imaginary component. /// public Complex(double real, double imaginary) { this._real = real; this._imag = imaginary; } #endregion #region Properties /// /// Gets a value representing the infinity value. This field is constant. /// /// The infinity. /// /// The semantic associated to this value is a Complex of /// 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. /// /// A value representing the infinity value. public static Complex Infinity { get { return infinity; } } /// /// Gets a value representing not-a-number. This field is constant. /// /// A value representing not-a-number. public static Complex NaN { get { return nan; } } /// /// Gets a value representing the imaginary unit number. This field is constant. /// /// A value representing the imaginary unit number. public static Complex I { get { return i; } } /// /// Gets a value representing the zero value. This field is constant. /// /// A value representing the zero value. public static Complex Zero { get { return new Complex(0.0, 0.0); } } /// /// Gets a value representing the 1 value. This field is constant. /// /// A value representing the 1 value. public static Complex One { get { return one; } } #endregion Properties /// /// Gets the real component of the complex number. /// /// The real component of the complex number. public double Real { get { return this._real; } } /// /// Gets the real imaginary component of the complex number. /// /// The real imaginary component of the complex number. public double Imaginary { get { return this._imag; } } /// /// Gets a value indicating whether whether the Complex is zero. /// /// true if this instance is zero; otherwise, false. public bool IsZero { get { return this._real.AlmostZero() && this._imag.AlmostZero(); } } /// /// Gets a value indicating whether the Complex is one. /// /// true if this instance is one; otherwise, false. public bool IsOne { get { return this._real.AlmostEqual(1.0) && this._imag.AlmostZero(); } } /// /// Gets a value indicating whether the Complex is the imaginary unit. /// /// true if this instance is I; otherwise, false. public bool IsI { get { return this._real.AlmostZero() && this._imag.AlmostEqual(1.0); } } /// /// Gets a value indicating whether the provided Complex evaluates to a /// value that is not a number. /// /// true if this instance is NaN; otherwise, false. public bool IsNaN { get { return double.IsNaN(this._real) || double.IsNaN(this._imag); } } /// /// Gets a value indicating whether the provided Complex evaluates to an /// infinite value. /// /// /// true if this instance is infinite; otherwise, false. /// /// /// True if it either evaluates to a complex infinity /// or to a directed infinity. /// public bool IsInfinity { get { return double.IsInfinity(this._real) || double.IsInfinity(this._imag); } } /// /// Gets a value indicating whether the provided Complex is real. /// /// true if this instance is a real number; otherwise, false. public bool IsReal { get { return this._imag.AlmostZero(); } } /// /// Gets a value indicating whether the provided Complex is real and not negative, that is >= 0. /// /// /// true if this instance is real nonnegative number; otherwise, false. /// public bool IsRealNonNegative { get { return this._imag.AlmostZero() && this._real >= 0; } } /// /// Gets the conjugate of this Complex. /// /// /// The semantic of setting the conjugate is such that /// /// // a, b of type Complex /// a.Conjugate = b; /// /// is equivalent to /// /// // a, b of type Complex /// a = b.Conjugate /// /// public Complex Conjugate { get { return new Complex(this._real, -this._imag); } } /// /// Gets or modulus of this Complex. /// /// public double Modulus { get { return Math.Sqrt((this._real * this._real) + (this._imag * this._imag)); } } /// /// Gets the squared modulus of this Complex. /// /// public double ModulusSquared { get { return (this._real * this._real) + (this._imag * this._imag); } } /// /// Gets argument of this Complex. /// /// /// Argument always returns a value bigger than negative Pi and /// smaller or equal to Pi. If this Complex is zero, the Complex /// is assumed to be positive _real with an argument of zero. /// public double Argument { get { if (this.IsReal && this._real < 0) { return Math.PI; } return this.IsRealNonNegative ? 0 : Math.Atan2(this._imag, this._real); } } /// /// Gets the unity of this complex (same argument, but on the unit circle; exp(I*arg)) /// public Complex Sign { get { if (double.IsPositiveInfinity(this._real) && double.IsPositiveInfinity(this._imag)) { return new Complex(Constants.Sqrt1Over2, Constants.Sqrt1Over2); } if (double.IsPositiveInfinity(this._real) && double.IsNegativeInfinity(this._imag)) { return new Complex(Constants.Sqrt1Over2, -Constants.Sqrt1Over2); } if (double.IsNegativeInfinity(this._real) && double.IsPositiveInfinity(this._imag)) { return new Complex(-Constants.Sqrt1Over2, -Constants.Sqrt1Over2); } if (double.IsNegativeInfinity(this._real) && double.IsNegativeInfinity(this._imag)) { return new Complex(-Constants.Sqrt1Over2, Constants.Sqrt1Over2); } // don't replace this with "Modulus"! var mod = SpecialFunctions.Hypotenuse(this._real, this._imag); if (mod.AlmostZero()) { return Zero; } return new Complex(this._real / mod, this._imag / mod); } } #region Exponential Functions /// /// Exponential of this Complex (exp(x), E^x). /// /// /// The exponential of this complex number. /// public Complex Exponential() { var exp = Math.Exp(_real); if (IsReal) { return new Complex(exp, 0.0); } return new Complex(exp * Trig.Cosine(_imag), exp * Trig.Sine(_imag)); } /// /// Natural Logarithm of this Complex (Base E). /// /// /// The natural logarithm of this complex number. /// public Complex NaturalLogarithm() { if (IsRealNonNegative) { return new Complex(Math.Log(_real), 0.0); } return new Complex(0.5 * Math.Log(ModulusSquared), Argument); } /// /// Raise this Complex to the given value. /// /// /// The exponent. /// /// /// The complex number raised to the given exponent. /// public Complex Power(Complex exponent) { if (IsZero) { if (exponent.IsZero) { return One; } if (exponent.Real > 0.0) { return Zero; } if (exponent.Real < 0) { if (exponent.Imaginary.AlmostZero()) { return new Complex(double.PositiveInfinity, 0.0); } return new Complex(double.PositiveInfinity, double.PositiveInfinity); } return NaN; } return (exponent * NaturalLogarithm()).Exponential(); } /// /// Raise this Complex to the inverse of the given value. /// /// /// The root exponent. /// /// /// The complex raised to the inverse of the given exponent. /// public Complex Root(Complex rootexponent) { return Power(1 / rootexponent); } /// /// The Square (power 2) of this Complex /// /// /// The square of this complex number. /// public Complex Square() { if (IsReal) { return new Complex(_real * _real, 0.0); } return new Complex((_real * _real) - (_imag * _imag), 2 * _real * _imag); } /// /// The Square Root (power 1/2) of this Complex /// /// /// The square root of this complex number. /// public Complex SquareRoot() { if (IsRealNonNegative) { return new Complex(Math.Sqrt(_real), 0.0); } Complex result; var absReal = Math.Abs(Real); var absImag = Math.Abs(Imaginary); double w; if (absReal >= absImag) { var ratio = Imaginary / Real; w = Math.Sqrt(absReal) * Math.Sqrt(0.5 * (1.0 + Math.Sqrt(1.0 + (ratio * ratio)))); } else { var ratio = Real / Imaginary; w = Math.Sqrt(absImag) * Math.Sqrt(0.5 * (Math.Abs(ratio) + Math.Sqrt(1.0 + (ratio * ratio)))); } if (Real >= 0.0) { result = new Complex(w, Imaginary / (2.0 * w)); } else if (Imaginary >= 0.0) { result = new Complex(absImag / (2.0 * w), w); } else { result = new Complex(absImag / (2.0 * w), -w); } return result; } #endregion #region Static Initializers /// /// Constructs a Complex from its real /// and imaginary parts. /// /// /// The value for the real component. /// /// /// The value for the imaginary component. /// /// /// A new Complex with the given values. /// public static Complex WithRealImaginary(double real, double imaginary) { return new Complex(real, imaginary); } /// /// Constructs a Complex from its modulus and /// argument. /// /// /// Must be non-negative. /// /// /// Real number. /// /// /// A new Complex from the given values. /// public static Complex WithModulusArgument(double modulus, double argument) { if (modulus < 0.0) { throw new ArgumentOutOfRangeException("modulus", modulus, Resources.ArgumentNotNegative); } return new Complex(modulus * Math.Cos(argument), modulus * Math.Sin(argument)); } #endregion #region IFormattable Members /// /// A string representation of this complex number. /// /// /// The string representation of this complex number. /// public override string ToString() { return this.ToString(null, null); } /// /// A string representation of this complex number. /// /// /// The string representation of this complex number formatted as specified by the /// format string. /// /// /// A format specification. /// public string ToString(string format) { return this.ToString(format, null); } /// /// A string representation of this complex number. /// /// /// The string representation of this complex number formatted as specified by the /// format provider. /// /// /// An IFormatProvider that supplies culture-specific formatting information. /// public string ToString(IFormatProvider formatProvider) { return this.ToString(null, formatProvider); } /// /// A string representation of this complex number. /// /// /// The string representation of this complex number formatted as specified by the /// format string and format provider. /// /// /// if the n, is not a number. /// /// /// if s, is . /// /// /// A format specification. /// /// /// An IFormatProvider that supplies culture-specific formatting information. /// public string ToString(string format, IFormatProvider formatProvider) { if (this.IsNaN) { return "NaN"; } if (this.IsInfinity) { return "Infinity"; } var ret = new StringBuilder(); if (!this._real.AlmostZero()) { ret.Append(this._real.ToString(format, formatProvider)); } if (!this._imag.AlmostZero()) { if (!this._real.AlmostZero()) { if (this._imag < 0) { ret.Append(" "); } else { ret.Append(" + "); } } ret.Append(this._imag.ToString(format, formatProvider)).Append("i"); } return ret.ToString(); } #endregion #region IEquatable Members /// /// Checks if two complex numbers are equal. Two complex numbers are equal if their /// corresponding real and imaginary components are equal. /// /// /// Returns true if the two objects are the same object, or if their corresponding /// real and imaginary components are equal, false otherwise. /// /// /// The complex number to compare to with. /// public bool Equals(Complex other) { if (this.IsNaN || other.IsNaN) { return false; } if (this.IsInfinity && other.IsInfinity) { return true; } return this._real.AlmostEqual(other._real) && this._imag.AlmostEqual(other._imag); } /// /// The hash code for the complex number. /// /// /// The hash code of the complex number. /// /// /// The hash code is calculated as /// System.Math.Exp(ComplexMath.Absolute(complexNumber)). /// public override int GetHashCode() { return this._real.GetHashCode() ^ (-this._imag.GetHashCode()); } /// /// Checks if two complex numbers are equal. Two complex numbers are equal if their /// corresponding real and imaginary components are equal. /// /// /// Returns true if the two objects are the same object, or if their corresponding /// real and imaginary components are equal, false otherwise. /// /// /// The complex number to compare to with. /// public override bool Equals(object obj) { return (obj is Complex) && this.Equals((Complex)obj); } #endregion #region Operators /// /// Equality test. /// /// One of complex numbers to compare. /// The other complex numbers to compare. /// true if the real and imaginary components of the two complex numbers are equal; false otherwise. public static bool operator ==(Complex complex1, Complex complex2) { return complex1.Equals(complex2); } /// /// Inequality test. /// /// One of complex numbers to compare. /// The other complex numbers to compare. /// true if the real or imaginary components of the two complex numbers are not equal; false otherwise. public static bool operator !=(Complex complex1, Complex complex2) { return !complex1.Equals(complex2); } /// /// Unary addition. /// /// The complex number to operate on. /// Returns the same complex number. public static Complex operator +(Complex summand) { return summand; } /// /// Unary minus. /// /// The complex number to operate on. /// The negated value of the . public static Complex operator -(Complex subtrahend) { return new Complex(-subtrahend._real, -subtrahend._imag); } /// Addition operator. Adds two complex numbers together. /// The result of the addition. /// One of the complex numbers to add. /// The other complex numbers to add. public static Complex operator +(Complex summand1, Complex summand2) { return new Complex(summand1._real + summand2._real, summand1._imag + summand2._imag); } /// Subtraction operator. Subtracts two complex numbers. /// The result of the subtraction. /// The complex number to subtract from. /// The complex number to subtract. public static Complex operator -(Complex minuend, Complex subtrahend) { return new Complex(minuend._real - subtrahend._real, minuend._imag - subtrahend._imag); } /// Addition operator. Adds a complex number and double together. /// The result of the addition. /// The complex numbers to add. /// The double value to add. public static Complex operator +(Complex summand1, double summand2) { return new Complex(summand1._real + summand2, summand1._imag); } /// Subtraction operator. Subtracts double value from a complex value. /// The result of the subtraction. /// The complex number to subtract from. /// The double value to subtract. public static Complex operator -(Complex minuend, double subtrahend) { return new Complex(minuend._real - subtrahend, minuend._imag); } /// Addition operator. Adds a complex number and double together. /// The result of the addition. /// The double value to add. /// The complex numbers to add. public static Complex operator +(double summand1, Complex summand2) { return new Complex(summand2._real + summand1, summand2._imag); } /// Subtraction operator. Subtracts complex value from a double value. /// The result of the subtraction. /// The double vale to subtract from. /// The complex value to subtract. public static Complex operator -(double minuend, Complex subtrahend) { return new Complex(minuend - subtrahend._real, -subtrahend._imag); } /// Multiplication operator. Multiplies two complex numbers. /// The result of the multiplication. /// One of the complex numbers to multiply. /// The other complex number to multiply. public static Complex operator *(Complex multiplicand, Complex multiplier) { return new Complex( (multiplicand._real * multiplier._real) - (multiplicand._imag * multiplier._imag), (multiplicand._real * multiplier._imag) + (multiplicand._imag * multiplier._real)); } /// Multiplication operator. Multiplies a complex number with a double value. /// The result of the multiplication. /// The double value to multiply. /// The complex number to multiply. public static Complex operator *(double multiplicand, Complex multiplier) { return new Complex(multiplier._real * multiplicand, multiplier._imag * multiplicand); } /// Multiplication operator. Multiplies a complex number with a double value. /// The result of the multiplication. /// The complex number to multiply. /// The double value to multiply. public static Complex operator *(Complex multiplicand, double multiplier) { return new Complex(multiplicand._real * multiplier, multiplicand._imag * multiplier); } /// Division operator. Divides a complex number by another. /// The result of the division. /// The dividend. /// The divisor. public static Complex operator /(Complex dividend, Complex divisor) { if (divisor.IsZero) { return Infinity; } var modSquared = divisor.ModulusSquared; return new Complex( ((dividend._real * divisor._real) + (dividend._imag * divisor._imag)) / modSquared, ((dividend._imag * divisor._real) - (dividend._real * divisor._imag)) / modSquared); } /// Division operator. Divides a double value by a complex number. /// The result of the division. /// The dividend. /// The divisor. public static Complex operator /(double dividend, Complex divisor) { if (divisor.IsZero) { return Infinity; } var zmod = divisor.ModulusSquared; return new Complex(dividend * divisor._real / zmod, -dividend * divisor._imag / zmod); } /// Division operator. Divides a complex number by a double value. /// The result of the division. /// The dividend. /// The divisor. public static Complex operator /(Complex dividend, double divisor) { if (divisor.AlmostZero()) { return Infinity; } return new Complex(dividend._real / divisor, dividend._imag / divisor); } /// /// Implicit conversion of a real double to a real Complex. /// /// The double value to convert. /// The result of the conversion. public static implicit operator Complex(double number) { return new Complex(number, 0.0); } /// /// Unary addition. /// /// /// Returns the same complex number. /// public Complex Plus() { return this; } /// /// Unary minus. /// /// /// The negated value of this complex number. /// public Complex Negate() { return -this; } /// /// Adds a complex number to this one. /// /// /// The result of the addition. /// /// /// The other complex number to add. /// public Complex Add(Complex other) { return this + other; } /// /// Subtracts a complex number from this one. /// /// /// The result of the subtraction. /// /// /// The other complex number to subtract from this one. /// public Complex Subtract(Complex other) { return this - other; } /// /// Multiplies this complex number with this one. /// /// /// The result of the multiplication. /// /// /// The complex number to multiply. /// public Complex Multiply(Complex multiplier) { return this * multiplier; } /// /// Divides this complex number by another. /// /// /// The result of the division. /// /// /// The divisor. /// public Complex Divide(Complex divisor) { return this / divisor; } #endregion #region IPrecisionSupport /// /// Returns a Norm of a value of this type, which is appropriate for measuring how /// close this value is to zero. /// /// /// A norm of this value. /// double IPrecisionSupport.Norm() { return ModulusSquared; } /// /// Returns a Norm of the difference of two values of this type, which is /// appropriate for measuring how close together these two values are. /// /// /// The value to compare with. /// /// /// A norm of the difference between this and the other value. /// double IPrecisionSupport.NormOfDifference(Complex otherValue) { return (this - otherValue).ModulusSquared; } #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 } }