Single Precision C# Complex Number Class
Author: Ben Houston

This class is part of the Exocortex.DSP library.
 

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;


namespace Exocortex.DSP {

    // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org
    // Version: March 22, 2002

    /// <summary>
    /// <p>A single-precision complex number representation.</p>
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct ComplexF : IComparable, ICloneable {

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// The real component of the complex number
        /// </summary>
        public float Re;

        /// <summary>
        /// The imaginary component of the complex number
        /// </summary>
        public float Im;

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Create a complex number from a real and an imaginary component
        /// </summary>
        /// <param name="real"></param>
        /// <param name="imaginary"></param>
        public ComplexF( float real, float imaginary ) {
            this.Re        = (float) real;
            this.Im    = (float) imaginary;
        }

        /// <summary>
        /// Create a complex number based on an existing complex number
        /// </summary>
        /// <param name="c"></param>
        public ComplexF( ComplexF c ) {
            this.Re        = c.Re;
            this.Im    = c.Im;
        }

        /// <summary>
        /// Create a complex number from a real and an imaginary component
        /// </summary>
        /// <param name="real"></param>
        /// <param name="imaginary"></param>
        /// <returns></returns>
        static public ComplexF    FromRealImaginary( float real, float imaginary ) {
            ComplexF c;
            c.Re        = (float) real;
            c.Im = (float) imaginary;
            return c;
        }

        /// <summary>
        /// Create a complex number from a modulus (length) and an argument (radian)
        /// </summary>
        /// <param name="modulus"></param>
        /// <param name="argument"></param>
        /// <returns></returns>
        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 );
        }
        /// <summary>
        /// Clone the complex number
        /// </summary>
        /// <returns></returns>
        public ComplexF    Clone() {
            return    new ComplexF( this );
        }
        
        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// The modulus (length) of the complex number
        /// </summary>
        /// <returns></returns>
        public float    GetModulus() {
            float    x    = this.Re;
            float    y    = this.Im;
            return    (float) Math.Sqrt( x*x + y*y );
        }

        /// <summary>
        /// The squared modulus (length^2) of the complex number
        /// </summary>
        /// <returns></returns>
        public float    GetModulusSquared() {
            float    x    = this.Re;
            float    y    = this.Im;
            return    (float) x*x + y*y;
        }

        /// <summary>
        /// The argument (radians) of the complex number
        /// </summary>
        /// <returns></returns>
        public float    GetArgument() {
            return (float) Math.Atan2( this.Im, this.Re );
        }

        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Get the conjugate of the complex number
        /// </summary>
        /// <returns></returns>
        public ComplexF GetConjugate() {
            return FromRealImaginary( this.Re, -this.Im );
        }

        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Scale the complex number to 1.
        /// </summary>
        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 );
        }

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Convert to a from double precision complex number to a single precison complex number
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static explicit operator ComplexF ( Complex c ) {
            ComplexF cF;
            cF.Re    = (float) c.Re;
            cF.Im    = (float) c.Im;
            return cF;
        }
        
        /// <summary>
        /// Convert from a single precision real number to a complex number
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        public static explicit operator ComplexF ( float f ) {
            ComplexF c;
            c.Re        = (float) f;
            c.Im    = (float) 0;
            return c;
        }

        /// <summary>
        /// Convert from a single precision complex to a real number
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static explicit operator float ( ComplexF c ) {
            return (float) c.Re;
        }
        
        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Are these two complex numbers equivalent?
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool    operator==( ComplexF a, ComplexF b ) {
            return    ( a.Re == b.Re ) && ( a.Im == b.Im );
        }

        /// <summary>
        /// Are these two complex numbers different?
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool    operator!=( ComplexF a, ComplexF b ) {
            return    ( a.Re != b.Re ) || ( a.Im != b.Im );
        }

        /// <summary>
        /// Get the hash code of the complex number
        /// </summary>
        /// <returns></returns>
        public override int        GetHashCode() {
            return    ( this.Re.GetHashCode() ^ this.Im.GetHashCode() );
        }

        /// <summary>
        /// Is this complex number equivalent to another object?
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool    Equals( object o ) {
            if( o is ComplexF ) {
                ComplexF c = (ComplexF) o;
                return   ( this == c );
            }
            return    false;
        }

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Compare to other complex numbers or real numbers
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public int    CompareTo( object o ) {
            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 );
            }
            return    0;
        }

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// This operator doesn't do much. :-)
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static ComplexF operator+( ComplexF a ) {
            return a;
        }

        /// <summary>
        /// Negate the complex number
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static ComplexF operator-( ComplexF a ) {
            a.Re    = -a.Re;
            a.Im    = -a.Im;
            return a;
        }

        /// <summary>
        /// Add a complex number to a real
        /// </summary>
        /// <param name="a"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static ComplexF operator+( ComplexF a, float f ) {
            a.Re    = (float)( a.Re + f );
            return a;
        }

        /// <summary>
        /// Add a real to a complex number
        /// </summary>
        /// <param name="f"></param>
        /// <param name="a"></param>
        /// <returns></returns>
        public static ComplexF operator+( float f, ComplexF a ) {
            a.Re    = (float)( a.Re + f );
            return a;
        }

        /// <summary>
        /// Add to complex numbers
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static ComplexF operator+( ComplexF a, ComplexF b ) {
            a.Re    = a.Re + b.Re;
            a.Im    = a.Im + b.Im;
            return a;
        }

        /// <summary>
        /// Subtract a real from a complex number
        /// </summary>
        /// <param name="a"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static ComplexF operator-( ComplexF a, float f ) {
            a.Re    = (float)( a.Re - f );
            return a;
        }

        /// <summary>
        /// Subtract a complex number from a real
        /// </summary>
        /// <param name="f"></param>
        /// <param name="a"></param>
        /// <returns></returns>
        public static ComplexF operator-( float f, ComplexF a ) {
            a.Re    = (float)( a.Re - f );
            return a;
        }

        /// <summary>
        /// Subtract two complex numbers
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static ComplexF operator-( ComplexF a, ComplexF b ) {
            a.Re    = a.Re - b.Re;
            a.Im    = a.Im - b.Im;
            return a;
        }

        /// <summary>
        /// Multiply a complex number by a real
        /// </summary>
        /// <param name="a"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static ComplexF operator*( ComplexF a, float f ) {
            a.Re    = (float)( a.Re * f );
            a.Im    = (float)( a.Im * f );
            return a;
        }
        
        /// <summary>
        /// Multiply a real by a complex number
        /// </summary>
        /// <param name="f"></param>
        /// <param name="a"></param>
        /// <returns></returns>
        public static ComplexF operator*( float f, ComplexF a ) {
            a.Re    = (float)( a.Re * f );
            a.Im    = (float)( a.Im * f );
            return a;
        }
        
        /// <summary>
        /// Multiply two complex numbers together
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Divide a complex number by a real number
        /// </summary>
        /// <param name="a"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static ComplexF operator/( ComplexF a, float f ) {
            if( f == 0 ) {
                throw new DivideByZeroException();
            }
            a.Re    = (float)( a.Re / f );
            a.Im    = (float)( a.Im / f );
            return a;
        }
        
        /// <summary>
        /// Divide a complex number by a complex number
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Parse a complex representation in this fashion: "( %f, %f )"
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        static public ComplexF Parse( string s ) {
            throw new NotImplementedException( "ComplexF ComplexF.Parse( string s ) is not implemented." );
        }
        
        /// <summary>
        /// Get the string representation
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            return    String.Format( "( {0}, {1}i )", this.Re, this.Im );
        }

        //-----------------------------------------------------------------------------------
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// Determine whether two complex numbers are almost (i.e. within the tolerance) equivalent.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        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 );

        }
        
        //----------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------

        /// <summary>
        /// Represents zero
        /// </summary>
        static public ComplexF    Zero {
            get    {    return    ComplexF.FromRealImaginary( 0, 0 );    }
        }

        /// <summary>
        /// Represents the result of sqrt( -1 )
        /// </summary>
        static public ComplexF    I {
            get {    return    ComplexF.FromRealImaginary( 0, 1 );    }
        }

        /// <summary>
        /// Represents the largest possible value of ComplexF.
        /// </summary>
        static public ComplexF    MaxValue {
            get {    return    ComplexF.FromRealImaginary( float.MaxValue, float.MaxValue );    }
        }

        /// <summary>
        /// Represents the smallest possible value of ComplexF.
        /// </summary>
        static public ComplexF    MinValue {
            get {    return    ComplexF.FromRealImaginary( float.MinValue, float.MinValue );    }
        }


        //----------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------
    }

}