/* * BSD Licence: * Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ] * Exocortex Technologies [ www.exocortex.org ] * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace Exocortex.DSP { // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org // Version: May 4, 2002 /// ///

A double-precision complex number representation.

///
[StructLayout(LayoutKind.Sequential)] public struct Complex : IComparable, ICloneable { //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// The real component of the complex number /// public double Re; /// /// The imaginary component of the complex number /// public double Im; //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Create a complex number from a real and an imaginary component /// /// /// public Complex(double real, double imaginary) { this.Re = real; this.Im = imaginary; } /// /// Create a complex number based on an existing complex number /// /// public Complex(Complex c) { this.Re = c.Re; this.Im = c.Im; } /// /// Create a complex number from a real and an imaginary component /// /// /// /// static public Complex FromRealImaginary(double real, double imaginary) { Complex c; c.Re = real; c.Im = imaginary; return c; } /// /// Create a complex number from a modulus (length) and an argument (radian) /// /// /// /// static public Complex FromModulusArgument(double modulus, double argument) { Complex c; c.Re = modulus * System.Math.Cos(argument); c.Im = modulus * System.Math.Sin(argument); return c; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- object ICloneable.Clone() { return new Complex(this); } /// /// Clone the complex number /// /// public Complex Clone() { return new Complex(this); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// The modulus (length) of the complex number /// /// public double GetModulus() { double x = this.Re; double y = this.Im; return (double)Math.Sqrt(x * x + y * y); } /// /// The squared modulus (length^2) of the complex number /// /// public double GetModulusSquared() { double x = this.Re; double y = this.Im; return (double)x * x + y * y; } /// /// The argument (radians) of the complex number /// /// public double GetArgument() { return (double)Math.Atan2(this.Im, this.Re); } //----------------------------------------------------------------------------------- /// /// Get the conjugate of the complex number /// /// public Complex GetConjugate() { return FromRealImaginary(this.Re, -this.Im); } //----------------------------------------------------------------------------------- /// /// Scale the complex number to 1. /// public void Normalize() { double modulus = this.GetModulus(); if (modulus == 0) { throw new DivideByZeroException("Can not normalize a complex number that is zero."); } this.Re = this.Re / modulus; this.Im = this.Im / modulus; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Convert to a from double precision complex number to a single precison complex number /// /// /// public static explicit operator Complex(ComplexF cF) { Complex c; c.Re = cF.Re; c.Im = cF.Im; return c; } /// /// Convert from a single precision real number to a complex number /// /// /// public static explicit operator Complex(double d) { Complex c; c.Re = d; c.Im = 0; return c; } /// /// Convert from a single precision complex to a real number /// /// /// public static explicit operator double(Complex c) { return c.Re; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Are these two complex numbers equivalent? /// /// /// /// public static bool operator ==(Complex a, Complex b) { return (a.Re == b.Re) && (a.Im == b.Im); } /// /// Are these two complex numbers different? /// /// /// /// public static bool operator !=(Complex a, Complex b) { return (a.Re != b.Re) || (a.Im != b.Im); } /// /// Get the hash code of the complex number /// /// public override int GetHashCode() { return (this.Re.GetHashCode() ^ this.Im.GetHashCode()); } /// /// Is this complex number equivalent to another object? /// /// /// public override bool Equals(object o) { if (o is Complex) { Complex c = (Complex)o; return (this == c); } return false; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Compare to other complex numbers or real numbers /// /// /// public int CompareTo(object o) { if (o == null) { return 1; // null sorts before current } if (o is Complex) { return this.GetModulus().CompareTo(((Complex)o).GetModulus()); } if (o is double) { return this.GetModulus().CompareTo((double)o); } if (o is ComplexF) { return this.GetModulus().CompareTo(((ComplexF)o).GetModulus()); } if (o is float) { return this.GetModulus().CompareTo((float)o); } throw new ArgumentException(); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// This operator doesn't do much. :-) /// /// /// public static Complex operator +(Complex a) { return a; } /// /// Negate the complex number /// /// /// public static Complex operator -(Complex a) { a.Re = -a.Re; a.Im = -a.Im; return a; } /// /// Add a complex number to a real /// /// /// /// public static Complex operator +(Complex a, double f) { a.Re = a.Re + f; return a; } /// /// Add a real to a complex number /// /// /// /// public static Complex operator +(double f, Complex a) { a.Re = a.Re + f; return a; } /// /// Add to complex numbers /// /// /// /// public static Complex operator +(Complex a, Complex b) { a.Re = a.Re + b.Re; a.Im = a.Im + b.Im; return a; } /// /// Subtract a real from a complex number /// /// /// /// public static Complex operator -(Complex a, double f) { a.Re = a.Re - f; return a; } /// /// Subtract a complex number from a real /// /// /// /// public static Complex operator -(double f, Complex a) { a.Re = (float)(f - a.Re); a.Im = (float)(0 - a.Im); return a; } /// /// Subtract two complex numbers /// /// /// /// public static Complex operator -(Complex a, Complex b) { a.Re = a.Re - b.Re; a.Im = a.Im - b.Im; return a; } /// /// Multiply a complex number by a real /// /// /// /// public static Complex operator *(Complex a, double f) { a.Re = a.Re * f; a.Im = a.Im * f; return a; } /// /// Multiply a real by a complex number /// /// /// /// public static Complex operator *(double f, Complex a) { a.Re = a.Re * f; a.Im = a.Im * f; return a; } /// /// Multiply two complex numbers together /// /// /// /// public static Complex operator *(Complex a, Complex b) { // (x + yi)(u + vi) = (xu – yv) + (xv + yu)i. double x = a.Re, y = a.Im; double u = b.Re, v = b.Im; a.Re = x * u - y * v; a.Im = x * v + y * u; return a; } /// /// Divide a complex number by a real number /// /// /// /// public static Complex operator /(Complex a, double f) { if (f == 0) { throw new DivideByZeroException(); } a.Re = a.Re / f; a.Im = a.Im / f; return a; } /// /// Divide a complex number by a complex number /// /// /// /// public static Complex operator /(Complex a, Complex b) { double x = a.Re, y = a.Im; double u = b.Re, v = b.Im; double denom = u * u + v * v; if (denom == 0) { throw new DivideByZeroException(); } a.Re = (x * u + y * v) / denom; a.Im = (y * u - x * v) / denom; return a; } /// /// Parse a complex representation in this fashion: "( %f, %f )" /// /// /// static public Complex Parse(string s) { throw new NotImplementedException("Complex Complex.Parse( string s ) is not implemented."); } /// /// Get the string representation /// /// public override string ToString() { return String.Format("( {0}, {1}i )", this.Re, this.Im); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Determine whether two complex numbers are almost (i.e. within the tolerance) equivalent. /// /// /// /// /// static public bool IsEqual(Complex a, Complex b, double tolerance) { return (Math.Abs(a.Re - b.Re) < tolerance) && (Math.Abs(a.Im - b.Im) < tolerance); } //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- /// /// Represents zero /// static public Complex Zero { get { return new Complex(0, 0); } } /// /// Represents the result of sqrt( -1 ) /// static public Complex I { get { return new Complex(0, 1); } } /// /// Represents the largest possible value of Complex. /// static public Complex MaxValue { get { return new Complex(double.MaxValue, double.MaxValue); } } /// /// Represents the smallest possible value of Complex. /// static public Complex MinValue { get { return new Complex(double.MinValue, double.MinValue); } } //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- } }