Personal tools

WikiComplex.h

From Odwiki

Jump to: navigation, search
/****************************************************************************
          File:  wikiComplex.h
       Authors:  The od[wiki] community at
                 http://www.odforce.net/wiki
 
   Description:  VEX package for complex number arithmetic.

                 Complex numbers in this VEX implementation are 
                 represented using the 'vector' data type, where 
                 the x-component is used for the real part, and 
                 the y-component for the imaginary part. However; the
                 module also defines the data type 'complex' so as to
                 make application code a little clearer and make the 
                 underlying vector type transparent -- i.e: application 
                 code should use the type 'complex' after including
                 this module.

                 Wherever it makes sense, functions are given alternative
                 versions using the suffixes 'R' (Real) and 'C' (complex)
                 to denote various combinations of data types for their
                 arguments. This lets us do complex arithmetic with mixed
                 data types... but due to the fact that we can't overload,
                 the function names start getting a little complicated, but
                 the overall pattern is consistent.

 -----------------------------------------------------------------------------
   Part of the small but growing od[wiki] library of VEX functions...
   This software is placed in the public domain and is provided as is
   without express or implied warranty.
 *****************************************************************************/





#ifndef wikiComplex_h__GUARD
#define wikiComplex_h__GUARD

#include <wikiMathConst.h>

//------------------------------------------------------------------
// Define the data type -- obviously this makes 'complex' a 
// reserved word after including this module.
//------------------------------------------------------------------
#define  complex  vector

//------------------------------------------------------------------
// Create a complex number
//------------------------------------------------------------------
complex cx_set(float re, im) {
   return set(re,im,0);
}
complex cx_setR(float re) {
   return set(re,0,0);
}
complex cx_setV(vector z) {
   return set(z.x,z.y,0);
}

//------------------------------------------------------------------
// Retrieve the real part of the complex number z
//------------------------------------------------------------------
float cx_re(complex z) {
   return z.x;
}
   
//------------------------------------------------------------------
// Retrieve the imaginary part of the complex number z
//------------------------------------------------------------------
float cx_im(complex z) {
   return z.y;
}
   
//------------------------------------------------------------------
// The distance from origin in polar coords -- a.k.a 
// 'complex modulus', or 'norm', or 'length'.
//------------------------------------------------------------------
float cx_mod(complex z) {
   float l=0.0;
   if(z.x!=0.0 || z.y!=0.0) {
      l = length(set(z.x, z.y, 0.0));
   }
   return l;
}
float cx_modR(float x) {
   return x<0.0 ? -x : x;
}

float cx_mod2(complex z) {
   float l=0.0;
   if(z.x!=0.0 || z.y!=0.0) {
      l = length2(set(z.x, z.y, 0.0));
   }
   return l;
}
float cx_mod2R(float x) {
   return x*x;
}

#define cx_norm      cx_mod
#define cx_normR     cx_modR
#define cx_norm2     cx_mod2
#define cx_norm2R    cx_mod2R
#define cx_length    cx_mod
#define cx_lengthR   cx_modR
#define cx_length2   cx_mod2
#define cx_length2R  cx_mod2R

//------------------------------------------------------------------
// Absolute Value (the magnitude of the complex number)
// An alternative implementation of cx_mod adapted from
// Numerical Recipes.
//------------------------------------------------------------------
float cx_abs(complex z) {
   float result;
   float x=abs(z.x), y=abs(z.y), d;
   if(x==0.0 && y==0) {
      result=0.0;
   } else if(x>=y) {
      d = y/x;
      result = x*sqrt(1.0+d*d);
   } else {
      d = x/y;
      result = y*sqrt(1.0+d*d);
   }
   return result;
}

//------------------------------------------------------------------
// 'Argument' (angle in radians with the x-axis in polar coords)
//------------------------------------------------------------------
float cx_arg(complex z) {
   return atan(z.y, z.x);
}

//------------------------------------------------------------------
// Conjugate (mult of conjugate pairs produce a real)
// Conjugate appears "flipped" across the real axis.
//------------------------------------------------------------------
complex cx_conj(complex z) {
   return cx_set(z.x, -z.y);
}

//------------------------------------------------------------------
// Inverse
//------------------------------------------------------------------
complex cx_inv(complex z) {
   float re,im,s;
   if(abs(z.x)>=abs(z.y)) {
      s  = 1.0 / (z.x + z.y*(z.y/z.x));
      re = s;
      im = s * (-z.y/z.x);
   } else {
      s  = 1.0 / (z.x*(z.x/z.y) + z.y);
      re = s * (z.x/z.y);
      im = -s;
   }
   return cx_set(re,im);
}

//------------------------------------------------------------------
// Negation (-z)
//------------------------------------------------------------------
complex cx_neg(complex z) {
   return cx_set(-z.x,-z.y);
}
complex cx_negR(float x) {
   return cx_setR(-x);
}

//------------------------------------------------------------------
// Addition (a+user posted image
//------------------------------------------------------------------
complex cx_add(complex a, user posted image {
   return cx_set(a.x+b.x, a.y+b.y);
}
complex cx_addR(complex a; float user posted image {
   return cx_set(a.x+b, a.y);
}
complex cx_addRC(float a; complex user posted image {
   return cx_set(a+b.x, b.y);
}

//------------------------------------------------------------------
// Subtraction (a-user posted image
//------------------------------------------------------------------
complex cx_sub(complex a, user posted image {
   return cx_set(a.x-b.x, a.y-b.y);
}
complex cx_subR(complex a; float user posted image {
   return cx_set(a.x-b, a.y);
}
complex cx_subRC(float a; complex user posted image {
   return cx_set(a-b.x, -b.y);
}

//------------------------------------------------------------------
// Multiplication (a*user posted image
//------------------------------------------------------------------
complex cx_mul(complex a, user posted image {
   return cx_set(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
}
complex cx_mulR(complex a; float user posted image {
   return cx_set(a.x*b, a.y*user posted image;
}
complex cx_mulRC(float a; complex user posted image {
   return cx_set(a*b.x, a*b.y);
}

//------------------------------------------------------------------
// Division (a/b)
// Adapted from numerical Recipes
// This does not check for division by zero!
//------------------------------------------------------------------
complex cx_div(complex a, user posted image {
   float re,im,s;
   if(abs(b.x) >= abs(b.y)) {
      float byox = b.y/b.x;
      s  = 1.0 / (b.x + b.y*byox);
      re = s * (a.x + a.y*byox);
      im = s * (a.y - a.x*byox);
   } else {
      float bxoy = b.x/b.y;
      s  = 1.0 / (b.x*bxoy + b.y);
      re = s * (a.x*bxoy + a.y);
      im = s * (a.y*bxoy - a.x);
   }
   return cx_set(re,im);
}
complex cx_divR(complex a; float user posted image {
   float l2 = b*b;
   return l2==0.0 ? 0.0 : cx_set((a.x*user posted image/l2, (a.y*user posted image/l2);
}
complex cx_divRC(float a; complex user posted image {
   return cx_div(cx_setR(a),user posted image;
}

//------------------------------------------------------------------
// Exponential
//------------------------------------------------------------------
complex cx_exp(complex z) {
   return cx_set(exp(z.x)*cos(z.y), exp(z.x)*sin(z.y));
}
complex cx_expR(float x) {
   return cx_setR(exp(x));
}


//------------------------------------------------------------------
// Power
//------------------------------------------------------------------
// complex raised to complex power
complex cx_pow(complex base, exp) {
   float re  = log(cx_abs(base)),
         im  = cx_arg(base),
         re2 = (re*exp.x) - (im*exp.y), 
         im2 = (re*exp.y) + (im*exp.x), 
         ere = exp(re2);
   return cx_set(ere*cos(im2), ere*sin(im2));
}
// complex raised to a real power
complex cx_powR(complex base; float exp) {
   float re  = log(cx_abs(base)),
         im  = cx_arg(base),
         ere = exp(re);
   return cx_set(ere*cos(im), ere*sin(im));
}
// real raised to complex power
complex cx_powRC(float base; complex exp) {
   float re  = log(cx_abs(base)),
         im  = WM_PI_2,                // atan2(0,base)
         re2 = (re*exp.x) - (im*exp.y), 
         im2 = (re*exp.y) + (im*exp.x), 
         ere = exp(re2);
   return cx_set(ere*cos(im2), ere*sin(im2));
}


//------------------------------------------------------------------
// Natural Logarithm (principal branch, where {-pi < arg <= pi} )
//------------------------------------------------------------------
complex cx_log(complex z) {
   return cx_set(log(cx_mod(z)), cx_arg(z));
}
complex cx_logR(float x) {
   return cx_setR(log(x));
}


//------------------------------------------------------------------
// Square Root (one of the two roots)
//------------------------------------------------------------------
complex cx_sqrt(complex z) {
   float re,im,tmp;
   float mag = cx_abs(z);
   if(mag>0.0) {
      if(z.x>0.0) {
         tmp = sqrt(0.5*(mag+z.x));
         re  = tmp;
         im  = 0.5*z.y / tmp;
      } else {
         tmp = sqrt(0.5*(mag-z.x));
         if(z.y<0.0) tmp=-tmp;
         re  = 0.5*z.y / tmp;
         im  = tmp;
      }
   } else {
      re = im = 0.0;
   }
   return cx_set(re,im);
}

complex cx_sqrtR(float x) {
   complex z;
   if(x>=0) {
      z = x==0.0 ? 0.0 : cx_setR(sqrt(x));
   } else {
      z = cx_sqrt(cx_setR(x));
   }
   return z;
}

//------------------------------------------------------------------
// Nth Root
//------------------------------------------------------------------
complex cx_root(complex z; float n) {
   float p    = 1.0/n;
   float th_n = cx_arg(z)*p;
   return cx_set(pow(cx_mod(z),p)*cos(th_n), sin(th_n));
}
complex cx_rootR(float x; float n) {
   return cx_root(cx_setR(x),n);
}

//------------------------------------------------------------------
// Sine
//------------------------------------------------------------------
complex cx_sin(complex z) {
   return cx_set(cosh(z.y)*sin(z.x), sinh(z.y)*cos(z.x));
}
complex cx_sinR(float x) {
   return cx_setR(sin(x));
}

//------------------------------------------------------------------
// Cosine
//------------------------------------------------------------------
complex cx_cos(complex z) {
   return cx_set(cosh(z.y)*cos(z.x), -sinh(z.y)*sin(z.x));
}
complex cx_cosR(float x) {
   return cx_setR(cos(x));
}

//------------------------------------------------------------------
// Tangent
//------------------------------------------------------------------
complex cx_tan(complex z) {
   return cx_div(cx_sin(z),cx_cos(z));
}
complex cx_tanR(float x) {
   return cx_setR(tan(x));
}

//------------------------------------------------------------------
// Hyperbolic Sine
//------------------------------------------------------------------
complex cx_sinh(complex z) {
   return cx_set(sinh(z.x)*cos(z.y),cosh(z.x)*sin(z.y));
}
complex cx_sinhR(float x) {
   return cx_setR(sinh(x));
}

//------------------------------------------------------------------
// Hyperbolic Cosine
//------------------------------------------------------------------
complex cx_cosh(complex z) {
   return cx_set(cosh(z.x)*cos(z.y),sinh(z.x)*sin(z.y));
}
complex cx_coshR(float z) {
   return cx_setR(cosh(x));
}


#endif // End wikiComplex_h__GUARD