3 * Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ]
\r
4 * Exocortex Technologies [ www.exocortex.org ]
\r
5 * All rights reserved.
\r
7 * Redistribution and use in source and binary forms, with or without
\r
8 * modification, are permitted provided that the following conditions are met:
\r
10 * 1. Redistributions of source code must retain the above copyright notice,
\r
11 * this list of conditions and the following disclaimer.
\r
12 * 2. Redistributions in binary form must reproduce the above copyright
\r
13 * notice, this list of conditions and the following disclaimer in the
\r
14 * documentation and/or other materials provided with the distribution.
\r
15 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
\r
16 * may be used to endorse or promote products derived from this software
\r
17 * without specific prior written permission.
\r
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
\r
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\r
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
\r
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
\r
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
\r
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\r
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
\r
33 using System.Diagnostics;
\r
34 using System.Runtime.InteropServices;
\r
37 namespace Exocortex.DSP {
\r
39 // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org
\r
40 // Version: May 4, 2002
\r
43 /// <p>A double-precision complex number representation.</p>
\r
45 [StructLayout(LayoutKind.Sequential)]
\r
46 public struct Complex : IComparable, ICloneable {
\r
48 //-----------------------------------------------------------------------------------
\r
49 //-----------------------------------------------------------------------------------
\r
52 /// The real component of the complex number
\r
57 /// The imaginary component of the complex number
\r
61 //-----------------------------------------------------------------------------------
\r
62 //-----------------------------------------------------------------------------------
\r
65 /// Create a complex number from a real and an imaginary component
\r
67 /// <param name="real"></param>
\r
68 /// <param name="imaginary"></param>
\r
69 public Complex( double real, double imaginary ) {
\r
70 this.Re = (double) real;
\r
71 this.Im = (double) imaginary;
\r
75 /// Create a complex number based on an existing complex number
\r
77 /// <param name="c"></param>
\r
78 public Complex( Complex c ) {
\r
84 /// Create a complex number from a real and an imaginary component
\r
86 /// <param name="real"></param>
\r
87 /// <param name="imaginary"></param>
\r
88 /// <returns></returns>
\r
89 static public Complex FromRealImaginary( double real, double imaginary ) {
\r
91 c.Re = (double) real;
\r
92 c.Im = (double) imaginary;
\r
97 /// Create a complex number from a modulus (length) and an argument (radian)
\r
99 /// <param name="modulus"></param>
\r
100 /// <param name="argument"></param>
\r
101 /// <returns></returns>
\r
102 static public Complex FromModulusArgument( double modulus, double argument ) {
\r
104 c.Re = (double)( modulus * System.Math.Cos( argument ) );
\r
105 c.Im = (double)( modulus * System.Math.Sin( argument ) );
\r
109 //-----------------------------------------------------------------------------------
\r
110 //-----------------------------------------------------------------------------------
\r
112 object ICloneable.Clone() {
\r
113 return new Complex( this );
\r
116 /// Clone the complex number
\r
118 /// <returns></returns>
\r
119 public Complex Clone() {
\r
120 return new Complex( this );
\r
123 //-----------------------------------------------------------------------------------
\r
124 //-----------------------------------------------------------------------------------
\r
127 /// The modulus (length) of the complex number
\r
129 /// <returns></returns>
\r
130 public double GetModulus() {
\r
131 double x = this.Re;
\r
132 double y = this.Im;
\r
133 return (double) Math.Sqrt( x*x + y*y );
\r
137 /// The squared modulus (length^2) of the complex number
\r
139 /// <returns></returns>
\r
140 public double GetModulusSquared() {
\r
141 double x = this.Re;
\r
142 double y = this.Im;
\r
143 return (double) x*x + y*y;
\r
147 /// The argument (radians) of the complex number
\r
149 /// <returns></returns>
\r
150 public double GetArgument() {
\r
151 return (double) Math.Atan2( this.Im, this.Re );
\r
154 //-----------------------------------------------------------------------------------
\r
157 /// Get the conjugate of the complex number
\r
159 /// <returns></returns>
\r
160 public Complex GetConjugate() {
\r
161 return FromRealImaginary( this.Re, -this.Im );
\r
164 //-----------------------------------------------------------------------------------
\r
167 /// Scale the complex number to 1.
\r
169 public void Normalize() {
\r
170 double modulus = this.GetModulus();
\r
171 if( modulus == 0 ) {
\r
172 throw new DivideByZeroException( "Can not normalize a complex number that is zero." );
\r
174 this.Re = (double)( this.Re / modulus );
\r
175 this.Im = (double)( this.Im / modulus );
\r
178 //-----------------------------------------------------------------------------------
\r
179 //-----------------------------------------------------------------------------------
\r
182 /// Convert to a from double precision complex number to a single precison complex number
\r
184 /// <param name="cF"></param>
\r
185 /// <returns></returns>
\r
186 public static explicit operator Complex ( ComplexF cF ) {
\r
188 c.Re = (double) cF.Re;
\r
189 c.Im = (double) cF.Im;
\r
194 /// Convert from a single precision real number to a complex number
\r
196 /// <param name="d"></param>
\r
197 /// <returns></returns>
\r
198 public static explicit operator Complex ( double d ) {
\r
206 /// Convert from a single precision complex to a real number
\r
208 /// <param name="c"></param>
\r
209 /// <returns></returns>
\r
210 public static explicit operator double ( Complex c ) {
\r
211 return (double) c.Re;
\r
214 //-----------------------------------------------------------------------------------
\r
215 //-----------------------------------------------------------------------------------
\r
218 /// Are these two complex numbers equivalent?
\r
220 /// <param name="a"></param>
\r
221 /// <param name="b"></param>
\r
222 /// <returns></returns>
\r
223 public static bool operator==( Complex a, Complex b ) {
\r
224 return ( a.Re == b.Re ) && ( a.Im == b.Im );
\r
228 /// Are these two complex numbers different?
\r
230 /// <param name="a"></param>
\r
231 /// <param name="b"></param>
\r
232 /// <returns></returns>
\r
233 public static bool operator!=( Complex a, Complex b ) {
\r
234 return ( a.Re != b.Re ) || ( a.Im != b.Im );
\r
238 /// Get the hash code of the complex number
\r
240 /// <returns></returns>
\r
241 public override int GetHashCode() {
\r
242 return ( this.Re.GetHashCode() ^ this.Im.GetHashCode() );
\r
246 /// Is this complex number equivalent to another object?
\r
248 /// <param name="o"></param>
\r
249 /// <returns></returns>
\r
250 public override bool Equals( object o ) {
\r
251 if( o is Complex ) {
\r
252 Complex c = (Complex) o;
\r
253 return ( this == c );
\r
258 //-----------------------------------------------------------------------------------
\r
259 //-----------------------------------------------------------------------------------
\r
262 /// Compare to other complex numbers or real numbers
\r
264 /// <param name="o"></param>
\r
265 /// <returns></returns>
\r
266 public int CompareTo( object o ) {
\r
268 return 1; // null sorts before current
\r
270 if( o is Complex ) {
\r
271 return this.GetModulus().CompareTo( ((Complex)o).GetModulus() );
\r
273 if( o is double ) {
\r
274 return this.GetModulus().CompareTo( (double)o );
\r
276 if( o is ComplexF ) {
\r
277 return this.GetModulus().CompareTo( ((ComplexF)o).GetModulus() );
\r
280 return this.GetModulus().CompareTo( (float)o );
\r
282 throw new ArgumentException();
\r
285 //-----------------------------------------------------------------------------------
\r
286 //-----------------------------------------------------------------------------------
\r
289 /// This operator doesn't do much. :-)
\r
291 /// <param name="a"></param>
\r
292 /// <returns></returns>
\r
293 public static Complex operator+( Complex a ) {
\r
298 /// Negate the complex number
\r
300 /// <param name="a"></param>
\r
301 /// <returns></returns>
\r
302 public static Complex operator-( Complex a ) {
\r
309 /// Add a complex number to a real
\r
311 /// <param name="a"></param>
\r
312 /// <param name="f"></param>
\r
313 /// <returns></returns>
\r
314 public static Complex operator+( Complex a, double f ) {
\r
315 a.Re = (double)( a.Re + f );
\r
320 /// Add a real to a complex number
\r
322 /// <param name="f"></param>
\r
323 /// <param name="a"></param>
\r
324 /// <returns></returns>
\r
325 public static Complex operator+( double f, Complex a ) {
\r
326 a.Re = (double)( a.Re + f );
\r
331 /// Add to complex numbers
\r
333 /// <param name="a"></param>
\r
334 /// <param name="b"></param>
\r
335 /// <returns></returns>
\r
336 public static Complex operator+( Complex a, Complex b ) {
\r
337 a.Re = a.Re + b.Re;
\r
338 a.Im = a.Im + b.Im;
\r
343 /// Subtract a real from a complex number
\r
345 /// <param name="a"></param>
\r
346 /// <param name="f"></param>
\r
347 /// <returns></returns>
\r
348 public static Complex operator-( Complex a, double f ) {
\r
349 a.Re = (double)( a.Re - f );
\r
354 /// Subtract a complex number from a real
\r
356 /// <param name="f"></param>
\r
357 /// <param name="a"></param>
\r
358 /// <returns></returns>
\r
359 public static Complex operator-( double f, Complex a ) {
\r
360 a.Re = (float)( f - a.Re );
\r
361 a.Im = (float)( 0 - a.Im );
\r
366 /// Subtract two complex numbers
\r
368 /// <param name="a"></param>
\r
369 /// <param name="b"></param>
\r
370 /// <returns></returns>
\r
371 public static Complex operator-( Complex a, Complex b ) {
\r
372 a.Re = a.Re - b.Re;
\r
373 a.Im = a.Im - b.Im;
\r
378 /// Multiply a complex number by a real
\r
380 /// <param name="a"></param>
\r
381 /// <param name="f"></param>
\r
382 /// <returns></returns>
\r
383 public static Complex operator*( Complex a, double f ) {
\r
384 a.Re = (double)( a.Re * f );
\r
385 a.Im = (double)( a.Im * f );
\r
390 /// Multiply a real by a complex number
\r
392 /// <param name="f"></param>
\r
393 /// <param name="a"></param>
\r
394 /// <returns></returns>
\r
395 public static Complex operator*( double f, Complex a ) {
\r
396 a.Re = (double)( a.Re * f );
\r
397 a.Im = (double)( a.Im * f );
\r
403 /// Multiply two complex numbers together
\r
405 /// <param name="a"></param>
\r
406 /// <param name="b"></param>
\r
407 /// <returns></returns>
\r
408 public static Complex operator*( Complex a, Complex b ) {
\r
409 // (x + yi)(u + vi) = (xu
\96 yv) + (xv + yu)i.
\r
410 double x = a.Re, y = a.Im;
\r
411 double u = b.Re, v = b.Im;
\r
413 a.Re = (double)( x*u - y*v );
\r
414 a.Im = (double)( x*v + y*u );
\r
420 /// Divide a complex number by a real number
\r
422 /// <param name="a"></param>
\r
423 /// <param name="f"></param>
\r
424 /// <returns></returns>
\r
425 public static Complex operator/( Complex a, double f ) {
\r
427 throw new DivideByZeroException();
\r
430 a.Re = (double)( a.Re / f );
\r
431 a.Im = (double)( a.Im / f );
\r
437 /// Divide a complex number by a complex number
\r
439 /// <param name="a"></param>
\r
440 /// <param name="b"></param>
\r
441 /// <returns></returns>
\r
442 public static Complex operator/( Complex a, Complex b ) {
\r
443 double x = a.Re, y = a.Im;
\r
444 double u = b.Re, v = b.Im;
\r
445 double denom = u*u + v*v;
\r
448 throw new DivideByZeroException();
\r
451 a.Re = (double)( ( x*u + y*v ) / denom );
\r
452 a.Im = (double)( ( y*u - x*v ) / denom );
\r
458 /// Parse a complex representation in this fashion: "( %f, %f )"
\r
460 /// <param name="s"></param>
\r
461 /// <returns></returns>
\r
462 static public Complex Parse( string s ) {
\r
463 throw new NotImplementedException( "Complex Complex.Parse( string s ) is not implemented." );
\r
467 /// Get the string representation
\r
469 /// <returns></returns>
\r
470 public override string ToString() {
\r
471 return String.Format( "( {0}, {1}i )", this.Re, this.Im );
\r
474 //-----------------------------------------------------------------------------------
\r
475 //-----------------------------------------------------------------------------------
\r
478 /// Determine whether two complex numbers are almost (i.e. within the tolerance) equivalent.
\r
480 /// <param name="a"></param>
\r
481 /// <param name="b"></param>
\r
482 /// <param name="tolerance"></param>
\r
483 /// <returns></returns>
\r
484 static public bool IsEqual( Complex a, Complex b, double tolerance ) {
\r
486 ( Math.Abs( a.Re - b.Re ) < tolerance ) &&
\r
487 ( Math.Abs( a.Im - b.Im ) < tolerance );
\r
491 //----------------------------------------------------------------------------------
\r
492 //----------------------------------------------------------------------------------
\r
495 /// Represents zero
\r
497 static public Complex Zero {
\r
498 get { return new Complex( 0, 0 ); }
\r
502 /// Represents the result of sqrt( -1 )
\r
504 static public Complex I {
\r
505 get { return new Complex( 0, 1 ); }
\r
509 /// Represents the largest possible value of Complex.
\r
511 static public Complex MaxValue {
\r
512 get { return new Complex( double.MaxValue, double.MaxValue ); }
\r
516 /// Represents the smallest possible value of Complex.
\r
518 static public Complex MinValue {
\r
519 get { return new Complex( double.MinValue, double.MinValue ); }
\r
523 //----------------------------------------------------------------------------------
\r
524 //----------------------------------------------------------------------------------
\r