/* * 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 single-precision complex number representation.

///
[StructLayout(LayoutKind.Sequential)] public struct ComplexF : IComparable, ICloneable { //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// The real component of the complex number /// public float Re; /// /// The imaginary component of the complex number /// public float Im; //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Create a complex number from a real and an imaginary component /// /// /// public ComplexF(float real, float imaginary) { this.Re = real; this.Im = imaginary; } /// /// Create a complex number based on an existing complex number /// /// public ComplexF(ComplexF c) { this.Re = c.Re; this.Im = c.Im; } /// /// Create a complex number from a real and an imaginary component /// /// /// /// static public ComplexF FromRealImaginary(float real, float imaginary) { ComplexF c; c.Re = real; c.Im = imaginary; return c; } /// /// Create a complex number from a modulus (length) and an argument (radian) /// /// /// /// static public ComplexF FromModulusArgument(float modulus, float argument) { ComplexF c; c.Re = (float)(modulus * System.Math.Cos(argument)); c.Im = (float)(modulus * System.Math.Sin(argument)); return c; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- object ICloneable.Clone() { return new ComplexF(this); } /// /// Clone the complex number /// /// public ComplexF Clone() { return new ComplexF(this); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// The modulus (length) of the complex number /// /// public float GetModulus() { float x = this.Re; float y = this.Im; return (float)Math.Sqrt(x * x + y * y); } /// /// The squared modulus (length^2) of the complex number /// /// public float GetModulusSquared() { float x = this.Re; float y = this.Im; return (float)x * x + y * y; } /// /// The argument (radians) of the complex number /// /// public float GetArgument() { return (float)Math.Atan2(this.Im, this.Re); } //----------------------------------------------------------------------------------- /// /// Get the conjugate of the complex number /// /// public ComplexF 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 = (float)(this.Re / modulus); this.Im = (float)(this.Im / modulus); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Convert to a from double precision complex number to a single precison complex number /// /// /// public static explicit operator ComplexF(Complex c) { ComplexF cF; cF.Re = (float)c.Re; cF.Im = (float)c.Im; return cF; } /// /// Convert from a single precision real number to a complex number /// /// /// public static explicit operator ComplexF(float f) { ComplexF c; c.Re = f; c.Im = 0; return c; } /// /// Convert from a single precision complex to a real number /// /// /// public static explicit operator float(ComplexF c) { return c.Re; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// Are these two complex numbers equivalent? /// /// /// /// public static bool operator ==(ComplexF a, ComplexF b) { return (a.Re == b.Re) && (a.Im == b.Im); } /// /// Are these two complex numbers different? /// /// /// /// public static bool operator !=(ComplexF a, ComplexF 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 ComplexF) { ComplexF c = (ComplexF)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 ComplexF) { return this.GetModulus().CompareTo(((ComplexF)o).GetModulus()); } if (o is float) { return this.GetModulus().CompareTo((float)o); } if (o is Complex) { return this.GetModulus().CompareTo(((Complex)o).GetModulus()); } if (o is double) { return this.GetModulus().CompareTo((double)o); } throw new ArgumentException(); } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- /// /// This operator doesn't do much. :-) /// /// /// public static ComplexF operator +(ComplexF a) { return a; } /// /// Negate the complex number /// /// /// public static ComplexF operator -(ComplexF a) { a.Re = -a.Re; a.Im = -a.Im; return a; } /// /// Add a complex number to a real /// /// /// /// public static ComplexF operator +(ComplexF a, float f) { a.Re = a.Re + f; return a; } /// /// Add a real to a complex number /// /// /// /// public static ComplexF operator +(float f, ComplexF a) { a.Re = a.Re + f; return a; } /// /// Add to complex numbers /// /// /// /// public static ComplexF operator +(ComplexF a, ComplexF b) { a.Re = a.Re + b.Re; a.Im = a.Im + b.Im; return a; } /// /// Subtract a real from a complex number /// /// /// /// public static ComplexF operator -(ComplexF a, float f) { a.Re = a.Re - f; return a; } /// /// Subtract a complex number from a real /// /// /// /// public static ComplexF operator -(float f, ComplexF a) { a.Re = f - a.Re; a.Im = 0 - a.Im; return a; } /// /// Subtract two complex numbers /// /// /// /// public static ComplexF operator -(ComplexF a, ComplexF b) { a.Re = a.Re - b.Re; a.Im = a.Im - b.Im; return a; } /// /// Multiply a complex number by a real /// /// /// /// public static ComplexF operator *(ComplexF a, float f) { a.Re = a.Re * f; a.Im = a.Im * f; return a; } /// /// Multiply a real by a complex number /// /// /// /// public static ComplexF operator *(float f, ComplexF a) { a.Re = a.Re * f; a.Im = a.Im * f; return a; } /// /// Multiply two complex numbers together /// /// /// /// public static ComplexF operator *(ComplexF a, ComplexF 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 = (float)(x * u - y * v); a.Im = (float)(x * v + y * u); return a; } /// /// Divide a complex number by a real number /// /// /// /// public static ComplexF operator /(ComplexF a, float 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 ComplexF operator /(ComplexF a, ComplexF 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 = (float)((x * u + y * v) / denom); a.Im = (float)((y * u - x * v) / denom); return a; } /// /// Parse a complex representation in this fashion: "( %f, %f )" /// /// /// static public ComplexF Parse(string s) { throw new NotImplementedException("ComplexF ComplexF.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(ComplexF a, ComplexF b, float tolerance) { return (Math.Abs(a.Re - b.Re) < tolerance) && (Math.Abs(a.Im - b.Im) < tolerance); } //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- /// /// Represents zero /// static public ComplexF Zero { get { return new ComplexF(0, 0); } } /// /// Represents the result of sqrt( -1 ) /// static public ComplexF I { get { return new ComplexF(0, 1); } } /// /// Represents the largest possible value of ComplexF. /// static public ComplexF MaxValue { get { return new ComplexF(float.MaxValue, float.MaxValue); } } /// /// Represents the smallest possible value of ComplexF. /// static public ComplexF MinValue { get { return new ComplexF(float.MinValue, float.MinValue); } } //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- } }