/*  
**  complex.h		C++ Runtime 
**
**  Copyright (C)	Microway, Inc. 1987 - 1994.
**			P.O. BOX 79
**			Kingston, MA. 02364
**			(508) 746 - 7341 Voice
**			(508) 746 - 4678 FAX
**			e-mail tech@microway.com
**
**  This program is the property of Microway, Inc, its contents are
**  proprietary information and no part of it is to be disclosed to anyone
**  except employees of Microway, Inc., or as agreed in writing by the
**  President of Microway, Inc.
*/

#ifndef __COMPLEX_H
# define __COMPLEX_H
# include <math.h>
# ifdef __mih			/* iostreams depends on multiple inheritance */
#  include <iostream.h>
# else
#  include <stream.h>
# endif
extern "C++" {			/* Use new 2.0 names, even in 1.2 */

class c_exception;

class complex {
    double re, im;

public:
    complex( double r, double i=0.0 ) { re = r; im = i; }
    complex() { re=0; im=0; }

    friend complex operator+( complex, complex );
    friend complex operator-( complex );
    friend complex operator-( complex, complex );
    friend complex operator*( complex, double );
    friend complex operator*( double, complex );
    friend complex operator*( complex, complex );
    friend complex operator/( complex, double );
    friend complex operator/( complex, complex );
    complex operator+=( complex);
    complex operator-=( complex);
    complex operator*=( double );
    complex operator*=( complex);
    complex operator/=( double );
    complex operator/=( complex);
    friend int operator==( complex, complex );
    friend int operator!=( complex, complex );

    friend double real( const complex & );
    friend double imag( const complex & );
    friend double norm( const complex & );
    friend double arg( const complex & );
    friend complex polar( double, double t=0.0 );

    friend double abs( const complex & );
    friend complex conj( const complex & );

    friend complex sqrt( complex );
    friend complex pow( complex, int );
    friend complex pow( complex, double );
    friend complex pow( complex, complex );
    friend complex exp( complex );
    friend complex log( complex );

    friend complex cos( complex );
    friend complex sin( complex );
    friend complex tan( complex );
    friend complex cosh( complex );
    friend complex sinh( complex );
    friend complex tanh( complex );

    friend int complex_error( c_exception & );

    void print() {
       cout << "( " << re << " , " << im << " )\n";
       }
};

complex acos( complex );	    // These don't need to be friends
complex asin( complex );
complex atan( complex );
complex acosh( complex );
complex asinh( complex );
complex atanh( complex );

inline double abs( const complex &x ) {
return( sqrt(x.re*x.re + x.im*x.im ));
}

inline complex operator+( complex x, complex y ) {
return( complex( x.re+y.re, x.im+y.im ));
}

inline complex operator-( complex x, complex y ) {
return( complex( x.re-y.re, x.im-y.im ));
}

inline complex operator-( complex x ) {
return( complex( -x.re, -x.im ));
}

inline complex operator*( complex x, double y ) {
return( complex( x.re*y, x.im*y ));
}

inline complex operator*( double x, complex y ) {
return( complex( x*y.re, x*y.im ));
}

inline complex operator*( complex x, complex y ) {
return( complex( x.re*y.re - x.im*y.im, x.im*y.re + x.re*y.im ));
}

inline complex operator/( complex x, double y ) {
return( complex( x.re/y, x.im/y ));
}

inline complex complex::operator+=( complex y ) {
    re += y.re;
    im += y.im;
return( *this );
}

inline complex complex::operator-=( complex y ) {
    re -= y.re;
    im -= y.im;
return( *this );
}

inline complex complex::operator*=( double y ) {
    re *= y;
    im *= y;
return( *this );
}

inline complex complex::operator*=( complex y ) {
    double temp = re*y.re - im*y.im;
    im = re*y.im + im*y.re;
    re = temp;
return( *this );
}

inline complex complex::operator/=( double y ) {
    re /= y;
    im /= y;
return( *this );
}

inline int operator==( complex x, complex y ) {
return ( x.re==y.re && x.im==y.im );
}

inline int operator!=( complex x, complex y ) {
return ( x.re!=y.re || x.im!=y.im );
}

inline double real( const complex &x ) {
return( x.re );
}

inline double imag( const complex &x ) {
return( x.im );
}

inline complex conj( const complex &x ) {
return( complex( x.re, -x.im ));
}

inline double norm( const complex & x ) {
return( sqrt(x.re*x.re + x.im*x.im ));
}

inline double arg( const complex &x ) {
return( atan2( x.im, x.re ));
}

inline complex polar( double r, double theta=0.0 ) {
return( complex( r*cos(theta), r*sin(theta)));
}

inline complex tan( complex a ) {
return( sin(a)/cos(a) );
}

inline complex tanh( complex a ) {
return( sinh(a)/cosh(a) );
}

inline complex operator^( complex x, complex y) { return(pow(x,y)); }
inline complex operator^( complex x, double y)	{ return(pow(x,y)); }
inline complex operator^( double x, complex y)	{ return(pow(x,y)); }
inline complex operator^=(complex &x, complex y) { x = pow(x,y); return( x );}
inline complex operator^=(complex &x, double y)  { x = pow(x,y); return( x );}

inline ostream &operator<<(ostream &o, complex c)
    { return o << "(" << real(c) << "," << imag(c) << ")" ; }
istream &operator>>(istream &i, complex &c);

enum {SING=1,OVERFLOW=2,UNDERFLOW=3};	/* S. never bothers to define these */

class c_exception {
    int     type;
    char    *name;
    complex arg1;
    complex arg2;
    complex retval;
public:
    c_exception(char *n, const complex &a1, const complex &a2= 0) {
	type = 0; name = n; arg1 = a1; arg2 = a2 ; retval = 0;
    }
    complex getret() { return retval; }
    friend int complex_error( c_exception & );
};

}
#endif
