File: System\Numerics\Complex.cs
Project: ndp\fx\src\Numerics\System.Numerics.csproj (System.Numerics)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*=========================================================================
**
** Class: Complex
**
**
** Purpose: 
** This feature is intended to create Complex Number as a type 
** that can be a part of the .NET framework (base class libraries).  
** A complex number z is a number of the form z = x + yi, where x and y 
** are real numbers, and i is the imaginary unit, with the property i2= -1.
**
**
===========================================================================*/
 
using System;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
 
namespace System.Numerics {
 
#if !SILVERLIGHT
    [Serializable]
#endif // !SILVERLIGHT
    public struct Complex : IEquatable<Complex>, IFormattable {
 
        // --------------SECTION: Private Data members ----------- //
 
        private Double m_real;
        private Double m_imaginary;
 
        // ---------------SECTION: Necessary Constants ----------- //
 
        private const Double LOG_10_INV = 0.43429448190325;
 
 
        // --------------SECTION: Public Properties -------------- //
 
        public Double Real {
            get {
                return m_real;
            }
        }
 
        public Double Imaginary {
            get {
                return m_imaginary;
            }
        }
 
        public Double Magnitude {
            get {
                return Complex.Abs(this);
            }
        }
 
        public Double Phase {
            get {
                return Math.Atan2(m_imaginary, m_real);
            }
        }
 
        // --------------SECTION: Attributes -------------- //
 
        public static readonly Complex Zero = new Complex(0.0, 0.0);
        public static readonly Complex One = new Complex(1.0, 0.0);
        public static readonly Complex ImaginaryOne = new Complex(0.0, 1.0);
 
        // --------------SECTION: Constructors and factory methods -------------- //
 
        public Complex(Double real, Double imaginary)  /* Constructor to create a complex number with rectangular co-ordinates  */
        {
            this.m_real = real;
            this.m_imaginary = imaginary;
        }
 
        public static Complex FromPolarCoordinates(Double magnitude, Double phase) /* Factory method to take polar inputs and create a Complex object */
        {
            return new Complex((magnitude * Math.Cos(phase)), (magnitude * Math.Sin(phase)));
        }
 
        public static Complex Negate(Complex value) {
            return -value;
        }
 
        public static Complex Add(Complex left, Complex right) {
            return left + right;
        }
 
        public static Complex Subtract(Complex left, Complex right) {
            return left - right;
        }
 
        public static Complex Multiply(Complex left, Complex right) {
            return left * right;
        }
 
        public static Complex Divide(Complex dividend, Complex divisor) {
            return dividend / divisor;
        }
 
        // --------------SECTION: Arithmetic Operator(unary) Overloading -------------- //
        public static Complex operator -(Complex value)  /* Unary negation of a complex number */
        {
 
            return (new Complex((-value.m_real), (-value.m_imaginary)));
        }
 
        // --------------SECTION: Arithmetic Operator(binary) Overloading -------------- //       
        public static Complex operator +(Complex left, Complex right) {
            return (new Complex((left.m_real + right.m_real), (left.m_imaginary + right.m_imaginary)));
 
        }
 
        public static Complex operator -(Complex left, Complex right) {
            return (new Complex((left.m_real - right.m_real), (left.m_imaginary - right.m_imaginary)));
        }
 
        public static Complex operator *(Complex left, Complex right) {
            // Multiplication:  (a + bi)(c + di) = (ac -bd) + (bc + ad)i
            Double result_Realpart = (left.m_real * right.m_real) - (left.m_imaginary * right.m_imaginary);
            Double result_Imaginarypart = (left.m_imaginary * right.m_real) + (left.m_real * right.m_imaginary);
            return (new Complex(result_Realpart, result_Imaginarypart));
        }
 
        public static Complex operator /(Complex left, Complex right) {
            // Division : Smith's formula.
            double a = left.m_real;
            double b = left.m_imaginary;
            double c = right.m_real;
            double d = right.m_imaginary;
 
            if (Math.Abs(d) < Math.Abs(c)) {
                double doc = d / c;
                return new Complex((a + b * doc) / (c + d * doc), (b - a * doc) / (c + d * doc));
            } else {
                double cod = c / d;
                return new Complex((b + a * cod) / (d + c * cod), (-a + b * cod) / (d + c * cod));
            }
        }
 
 
        // --------------SECTION: Other arithmetic operations  -------------- //
 
        public static Double Abs(Complex value) {
 
            if(Double.IsInfinity(value.m_real) || Double.IsInfinity(value.m_imaginary)) {
                return double.PositiveInfinity;
            }
 
            // |value| == sqrt(a^2 + b^2)
            // sqrt(a^2 + b^2) == a/a * sqrt(a^2 + b^2) = a * sqrt(a^2/a^2 + b^2/a^2)
            // Using the above we can factor out the square of the larger component to dodge overflow.
 
 
            double c = Math.Abs(value.m_real);
            double d = Math.Abs(value.m_imaginary);
 
            if (c > d) {
                double r = d / c;
                return c * Math.Sqrt(1.0 + r * r);
            } else if (d == 0.0) {
                return c;  // c is either 0.0 or NaN
            } else {
                double r = c / d;
                return d * Math.Sqrt(1.0 + r * r);
            }
        }
        public static Complex Conjugate(Complex value) {
            // Conjugate of a Complex number: the conjugate of x+i*y is x-i*y 
 
            return (new Complex(value.m_real, (-value.m_imaginary)));
 
        }
        public static Complex Reciprocal(Complex value) {
            // Reciprocal of a Complex number : the reciprocal of x+i*y is 1/(x+i*y)
            if ((value.m_real == 0) && (value.m_imaginary == 0)) {
                return Complex.Zero;
            }
 
            return Complex.One / value;
        }
 
        // --------------SECTION: Comparison Operator(binary) Overloading -------------- //
 
        public static bool operator ==(Complex left, Complex right) {
            return ((left.m_real == right.m_real) && (left.m_imaginary == right.m_imaginary));
 
 
        }
        public static bool operator !=(Complex left, Complex right) {
            return ((left.m_real != right.m_real) || (left.m_imaginary != right.m_imaginary));
 
        }
 
        // --------------SECTION: Comparison operations (methods implementing IEquatable<ComplexNumber>,IComparable<ComplexNumber>) -------------- //
 
        public override bool Equals(object obj) {
            if (!(obj is Complex)) return false;
            return this == ((Complex)obj);
        }
        public bool Equals(Complex value) {
            return ((this.m_real.Equals(value.m_real)) && (this.m_imaginary.Equals(value.m_imaginary)));
 
        }
 
        // --------------SECTION: Type-casting basic numeric data-types to ComplexNumber  -------------- //
 
        public static implicit operator Complex(Int16 value) {
            return (new Complex(value, 0.0));
        }
        public static implicit operator Complex(Int32 value) {
            return (new Complex(value, 0.0));
        }
        public static implicit operator Complex(Int64 value) {
            return (new Complex(value, 0.0));
        }
        [CLSCompliant(false)]
        public static implicit operator Complex(UInt16 value) {
            return (new Complex(value, 0.0));
        }
        [CLSCompliant(false)]
        public static implicit operator Complex(UInt32 value) {
            return (new Complex(value, 0.0));
        }
        [CLSCompliant(false)]
        public static implicit operator Complex(UInt64 value) {
            return (new Complex(value, 0.0));
        }
        [CLSCompliant(false)]
        public static implicit operator Complex(SByte value) {
            return (new Complex(value, 0.0));
        }
        public static implicit operator Complex(Byte value) {
            return (new Complex(value, 0.0));
        }
        public static implicit operator Complex(Single value) {
            return (new Complex(value, 0.0));
        }
        public static implicit operator Complex(Double value) {
            return (new Complex(value, 0.0));
        }
        public static explicit operator Complex(BigInteger value) {
            return (new Complex((Double)value, 0.0));
        }
        public static explicit operator Complex(Decimal value) {
            return (new Complex((Double)value, 0.0));
        }
 
 
        // --------------SECTION: Formattig/Parsing options  -------------- //
 
        public override String ToString() {
            return (String.Format(CultureInfo.CurrentCulture, "({0}, {1})", this.m_real, this.m_imaginary));
        }
 
        public String ToString(String format) {
            return (String.Format(CultureInfo.CurrentCulture, "({0}, {1})", this.m_real.ToString(format, CultureInfo.CurrentCulture), this.m_imaginary.ToString(format, CultureInfo.CurrentCulture)));
        }
 
        public String ToString(IFormatProvider provider) {
            return (String.Format(provider, "({0}, {1})", this.m_real, this.m_imaginary));
        }
 
        public String ToString(String format, IFormatProvider provider) {
            return (String.Format(provider, "({0}, {1})", this.m_real.ToString(format, provider), this.m_imaginary.ToString(format, provider)));
        }
 
 
        public override Int32 GetHashCode() {
            Int32 n1 = 99999997;
            Int32 hash_real = this.m_real.GetHashCode() % n1;
            Int32 hash_imaginary = this.m_imaginary.GetHashCode();
            Int32 final_hashcode = hash_real ^ hash_imaginary;
            return (final_hashcode);
        }
 
 
 
        // --------------SECTION: Trigonometric operations (methods implementing ITrigonometric)  -------------- //
 
        public static Complex Sin(Complex value) {
            double a = value.m_real;
            double b = value.m_imaginary;
            return new Complex(Math.Sin(a) * Math.Cosh(b), Math.Cos(a) * Math.Sinh(b));
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sinh", Justification = "Microsoft: Existing Name")]
        public static Complex Sinh(Complex value) /* Hyperbolic sin */
        {
            double a = value.m_real;
            double b = value.m_imaginary;
            return new Complex(Math.Sinh(a) * Math.Cos(b), Math.Cosh(a) * Math.Sin(b));
 
        }
        public static Complex Asin(Complex value) /* Arcsin */
        {
            return (-ImaginaryOne) * Log(ImaginaryOne * value + Sqrt(One - value * value));
        }
 
        public static Complex Cos(Complex value) {
            double a = value.m_real;
            double b = value.m_imaginary;
            return new Complex(Math.Cos(a) * Math.Cosh(b), - (Math.Sin(a) * Math.Sinh(b)));
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cosh", Justification = "Microsoft: Existing Name")]
        public static Complex Cosh(Complex value) /* Hyperbolic cos */
        {
            double a = value.m_real;
            double b = value.m_imaginary;
            return new Complex(Math.Cosh(a) * Math.Cos(b), Math.Sinh(a) * Math.Sin(b));
        }
        public static Complex Acos(Complex value) /* Arccos */
        {
            return (-ImaginaryOne) * Log(value + ImaginaryOne*Sqrt(One - (value * value)));
 
        }
        public static Complex Tan(Complex value) {
            return (Sin(value) / Cos(value));
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tanh", Justification = "Microsoft: Existing Name")]
        public static Complex Tanh(Complex value) /* Hyperbolic tan */
        {
            return (Sinh(value) / Cosh(value));
        }
        public static Complex Atan(Complex value) /* Arctan */
        {
            Complex Two = new Complex(2.0, 0.0);
            return (ImaginaryOne / Two) * (Log(One - ImaginaryOne * value) - Log(One + ImaginaryOne * value));
        }
 
        // --------------SECTION: Other numerical functions  -------------- //        
 
        public static Complex Log(Complex value) /* Log of the complex number value to the base of 'e' */
        {
            return (new Complex((Math.Log(Abs(value))), (Math.Atan2(value.m_imaginary, value.m_real))));
 
        }
        public static Complex Log(Complex value, Double baseValue) /* Log of the complex number to a the base of a double */
        {
            return (Log(value) / Log(baseValue));
        }
        public static Complex Log10(Complex value) /* Log to the base of 10 of the complex number */
        {
 
            Complex temp_log = Log(value);
            return (Scale(temp_log, (Double)LOG_10_INV));
 
        }
        public static Complex Exp(Complex value) /* The complex number raised to e */
        {
            Double temp_factor = Math.Exp(value.m_real);
            Double result_re = temp_factor * Math.Cos(value.m_imaginary);
            Double result_im = temp_factor * Math.Sin(value.m_imaginary);
            return (new Complex(result_re, result_im));
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sqrt", Justification = "Microsoft: Existing Name")]
        public static Complex Sqrt(Complex value) /* Square root ot the complex number */
        {
            return Complex.FromPolarCoordinates(Math.Sqrt(value.Magnitude), value.Phase / 2.0);
        }
 
        public static Complex Pow(Complex value, Complex power) /* A complex number raised to another complex number */
        {
 
            if (power == Complex.Zero) {
                return Complex.One;
            }
 
            if (value == Complex.Zero) {
                return Complex.Zero;
            }
 
            double a = value.m_real;
            double b = value.m_imaginary;
            double c = power.m_real;
            double d = power.m_imaginary;
 
            double rho = Complex.Abs(value);
            double theta = Math.Atan2(b, a);
            double newRho = c * theta + d * Math.Log(rho);
 
            double t = Math.Pow(rho, c) * Math.Pow(Math.E, -d * theta);
 
            return new Complex(t * Math.Cos(newRho), t * Math.Sin(newRho));
        }
 
        public static Complex Pow(Complex value, Double power) // A complex number raised to a real number 
        {
            return Pow(value, new Complex(power, 0));
        }
 
 
 
        //--------------- SECTION: Private member functions for internal use -----------------------------------//
 
        private static Complex Scale(Complex value, Double factor) {
 
            Double result_re = factor * value.m_real;
            Double result_im = factor * value.m_imaginary;
            return (new Complex(result_re, result_im));
        }
 
    }
}