//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: MBN 10/25/89 -- Initial design and implementation
// Updated: MBN 03/04/90 -- Added execption for DIVIDE_BY_ZERO
// Updated: MJF 07/31/90 -- Added terse print
// 
// The Complex  class implements  Complex  numbers  and arithmetic.   A Complex
// object has the same  precision and range of  values  as  the system built-in
// type double.  Implicit conversion  to  the  system defined types short, int,
// long, float,    and  double   is supported by   overloaded  operator  member
// functions.  Although   the  Complex class  makes   judicous use   of  inline
// functions and deals only with floating point values, the user is warned that
// the Complex double arithmetic class is still  slower than  the built-in real
// data types.
//
// The Complex   class implements common   arithmetic   exception  handling and
// provides  the  application  with support  for   detecting negative infinity,
// positive  infinity, overflow, and underflow as  a  result of some arithmetic
// expression. If one  of these conditions  or  an attempt   to  convert from a
// Complex with no value to a built-in type is detected,  an Error exception is
// raised. The application programmer can provide an exception handler  to take
// care of this problem. If no  such handler is  available, an error message is
// printed and the application terminates.
//
// The Complex class requires several constants be defined to insure precision
// and accuracy   of conversion.  The   preprocessor  symbols MINSHORT, MININT,
// MINLONG, MAXSHORT, MAXINT, and MAXLONG  are calculated  in the <COOL/misc.h>
// header file  via various  bit  manipulation  macros. The  symbols  MINFLOAT,
// MINDOUBLE,  MAXFLOAT,  and MAXDOUBLE  are  system dependent  and cannot   be
// calculated.  Most systems typically have  values  for these constants in the
// system header  file <values.h>.  Values  for a  specific  machine should  be
// copied into the <COOL/misc.h> header file as necessary.
//
// The private data section of the Complex class contains two double  data type
// slots,  one for  the real portion  and one for the  imaginary portion.   The
// Complex  class  also contains   a   private  data slot  providing arithmetic
// exception status.  There are four constructors for the  Complex class.   The
// first is a simple inline constructor that  initializes the state and private
// data slots.  The second  takes two integers (short, int,  or long)  and uses
// them  as the initial value for  the object. The  second argument is optional
// and if not supplied, defaults to zero.  The third takes  two reals (float or
// double) and uses  them as  the  initial  value for  the object.  The  second
// argument is optional  and  if not supplied, defaults  to zero.  Finally, the
// fourth takes a const reference to another Complex object and  duplicates its
// state and value.
//
// The Complex  class provides overloaded  operators for addition, subtraction,
// multiplication,  division,  cosine, sine,  hyperbolic cosine  and hyperbolic
// sine.  Also available are  inequality  and equality,  assignment, increment,
// decrement, unary minus, and  output.  Methods to get  the real and imaginary
// part are supported.  Finally,  five virtual operator conversion functions to
// short, int, long, float, and double are provided.

#ifndef COMPLEX_H				// If no Complex definition
#define COMPLEX_H				// define the Complex symbol

#ifndef GENERIC_H				// If no definition for class
#include <cool/Generic.h>			// include definition file
#endif

#if defined(DOS)
extern "C" {
#include <math.h>		// include the standard math library
}
#else
#include <math.h>		// include the standard math library
#endif

class Complex {
private:
  double r;					// Real portion
  double i;					// Imaginary portion
  N_status state;				// Exception status

protected:
  void minus_infinity (const char*) CONST;	// Raise - infinity exception
  void plus_infinity (const char*) CONST;	// Raise + infinity exception
  void overflow (const char*) CONST;		// Raise overflow error
  void underflow (const char*) CONST;		// Raise overflow error
  void no_conversion (const char*) CONST;	// Raise no conversion error
  void divide_by_zero (const char*) CONST;	// Raise divide by zero

public:
  inline Complex ();				// Simple constructor
  inline Complex (double, double ip = 0.0);	// Constructor with doubles
  inline Complex (const Complex&);		// Constructor with reference

  inline double real () CONST;			// Get the numerator
  inline double imaginary () CONST;		// Get the denominator
  inline N_status status () CONST;		// Return Number status
  
  Complex& operator= (const Complex&);		// Overload assignment
  inline Boolean operator== (const Complex&) CONST; // Overload equality
  inline Boolean operator!= (const Complex&) CONST; // Overload inequality

  inline Complex invert () CONST;		// Return reciprical of complex
  inline Complex operator-() CONST;		// Unary minus operator
  inline Complex conjugate () CONST;		// Conjugate of complex number
  inline Boolean operator!() CONST;		// Logical NOT operator

  inline friend Complex operator+ (const Complex&, const Complex&);
  inline friend Complex operator- (const Complex&, const Complex&);
  inline friend Complex operator* (const Complex&, const Complex&);
  friend Complex operator/ (const Complex&, const Complex&);	 

  inline void operator+= (const Complex&);	// Overload add/assigne
  inline void operator-= (const Complex&);	// Overload subtract/assigne
  inline void operator*= (const Complex&);	// Overload multi/assigne
  inline void operator/= (const Complex&);	// Overload divide/assigne

  inline Complex& operator++ ();		// Overload increment
  inline Complex& operator-- ();		// Overload decrement

  friend ostream& operator<< (ostream&, const Complex&); 
  inline friend ostream& operator<< (ostream&, const Complex*);

  void print(ostream&);				// terse print

  inline Complex cos () CONST;			// Cosine of a complex 
  inline Complex sin () CONST;			// Sine of a complex
  inline Complex tan () CONST;			// Tangent of a complex
  inline Complex cosh () CONST;			// Hyperbolic cosine of complex
  inline Complex sinh () CONST;			// Hyperbolic sine of complex
  inline Complex tanh () CONST;			// Hyperbolic tangent
  
#ifdef __cplusplus
  operator short ();				// Virtual implicit conversion
  operator int ();				// Virtual implicit conversion
  operator long ();				// Virtual implicit conversion
  operator float ();				// Virtual implicit conversion
  operator double ();				// Virtual implicit conversion
#else
  int operator int ();				// Virtual implicit conversion
  long operator long ();			// Virtual implicit conversion
  double operator double ();			// Virtual implicit conversion
#endif  
};


// Complex -- Simple constructor
// Input:     None
// Output:    None

inline Complex::Complex () {
  this->r = this->i = 0.0;			// Initialize data slots
  this->state = N_OK;				// Set status to OK
}


// Complex -- Constructor that takes a floating point real part and optional
//            floating point imaginary part to make a complex number
// Input:     Double for real part, optional double for imaginary part
// Output:    None

inline Complex::Complex (double rp, double ip) {
  this->r = rp;					// Set real part
  this->i = ip;					// Set imaginary part
  this->state = N_OK;				// Set status to OK
}


// Complex -- Constructor that duplicates the value of another complex object
// Input:     Reference to complex object
// Output:    None

inline Complex::Complex (const Complex& c) {
  this->r = c.r;				// Copy real part
  this->i = c.i;				// Copy imaginary part
  this->state = c.state;			// Copy state
}


// real -- Return the real portion of the Complex
// Input:  None
// Output: Real part of Complex

inline double Complex::real () CONST {
  return this->r;				// Return real part
}


// imaginary -- Return the imaginary portion of the Complex
// Input:       None
// Output:      Imaginary part of Complex

inline double Complex::imaginary () CONST {
  return this->i;				// Return imaginary part
}


// status -- Return the status of Number
// Input:    None
// Output:   N_status enum value

inline N_status Complex::status () CONST {
  return this->state;
}


// operator== -- Overload the equality operator for the Complex class
// Input:        Reference to Complex object
// Output:       TRUE/FALSE

inline Boolean Complex::operator== (const Complex& c) CONST {
  return (this->r == c.r && this->i == c.i);
}


// operator!= -- Overload the inequality operator for the Complex class
// Input:        Reference to a constant Complex object
// Ouput:        TRUE/FALSE

inline Boolean Complex::operator!= (const Complex& c) CONST {
  return !(*this == c);
}


// operator<< -- Overload the output operator for a pointer to a Complex
// Input:        Ostream reference, pointer to a Complex object
// Output:       Ostream reference

inline ostream& operator<< (ostream& os, const Complex* c) {
  return operator<< (os, *c);
}


// invert -- Calculate the reciprical of a complex number
// Input:    None
// Output:   Reciprical of complex

inline Complex Complex::invert () CONST {
  double normalize = (this->r * this->r)+(this->i * this->i);
  return Complex ((this->r / normalize), (-this->i / normalize));
}


// operator- -- Overload the unary minus operator for the Complex class
// Input:       None
// Output:      Negated Complex value

inline Complex Complex::operator- () CONST {
  return Complex (-this->r, this->i);		// Get negative value
}


// conjugate -- Provide conjugate (that is, negate imaginary part) of complex
// Input:       None
// Output:      Negated Complex value

inline Complex Complex::conjugate () CONST {
  return Complex (this->r, -this->i);		// Get negative value
}


// operator! -- Overload the negation operator for the Complex class
// Input:       None
// Output:      TRUE/FALSE

inline Boolean Complex::operator! () CONST {
  return ((this->r == 0.0) ? TRUE : FALSE);	// Return logical state
}


// operator++ -- Overload the increment operator for the Complex class
// Input:        None
// Output:       Reference to updated Complex object

inline Complex& Complex::operator++ () {
  this->r++ ;					// Increment real part
  return *this;					// Return updated object
}
  

// operator-- -- Overload the decrement operator for the Complex class
// Input:        None
// Output:       Reference to updated Complex object

inline Complex& Complex::operator-- () {
  this->r--;					// Decrement real part
  return *this;					// Return updated object
}


// operator+ -- Overload the addition operator for the Complex class
// Input:       Reference to complex object
// Output:      Reference to new complex object

inline Complex operator+ (const Complex& c1, const Complex& c2) {
  return Complex (c1.real()+c2.real(), c1.imaginary()+c2.imaginary());
}


// operator- -- Overload the subtraction operator for the Complex class
// Input:       Reference to complex object
// Output:      Reference to new complex object

inline Complex operator- (const Complex& c1, const Complex& c2) {
  return Complex (c1.real()-c2.real(), c1.imaginary()-c2.imaginary());
}


// operator* -- Overload the multiplication operator for the Complex class
// Input:       Reference to complex object
// Output:      Reference to new complex object

inline Complex operator* (const Complex& c1, const Complex& c2) {
  return Complex (((c1.r * c2.r)-(c1.i * c2.i)),((c1.r * c2.i)+(c1.i * c2.r)));
}


// operator+= -- Overload the addition/assign operator for the Complex class
// Input:        Reference to complex object
// Output:       None

inline void Complex::operator+= (const Complex& c) {
  this->r += c.r;				// Add real part
  this->i += c.i;				// Add imaginary part
}


// operator-= -- Overload the subtraction/assign operator for the Complex class
// Input:        Reference to complex object
// Output:       None

inline void Complex::operator-= (const Complex& c) {
  this->r -= c.r;				// Subtract real part
  this->i -= c.i;				// Subtract imaginary part
}


// operator*= -- Overload the multiplication/assign operator for Complex class
// Input:        Reference to complex object
// Output:       None

inline void Complex::operator*= (const Complex& c) {
  this->r = (this->r * c.r)-(this->i * c.i);	// Multiply real part
  this->i = (this->r * c.i)+(this->i * c.r);	// Multiply imaginary part
}


// operator/= -- Overload the division/assign operator for the Complex class
// Input:        Reference to complex object
// Output:       None

inline void Complex::operator/= (const Complex& c) {
  Complex temp = *this / c;			// Calculate answer
  this->r = temp.r;				// Copy real part
  this->i = temp.i;				// Copy imaginary part
}


// sin --  Calculate the sine of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::sin () CONST {
  return Complex (::sin (this->r), ::sin (this->i));
}


// cos --  Calculate the cosine of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::cos () CONST {
  return Complex (::cos (this->r), ::cos (this->i));
}


// tan --  Calculate the tangent of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::tan () CONST {
  return Complex (::tan (this->r), ::tan (this->i));
}


// sinh -- Calculate the hyperbolic sine of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::sinh () CONST {
  return Complex (::sinh (this->r), ::sinh (this->i));
}


// cosh -- Calculate the hyperbolic cosine of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::cosh () CONST {
  return Complex (::cosh (this->r), ::cosh (this->i));
}


// tanh -- Calculate the hyperbolic tangent of a Complex number
// Input:  Reference to a complex
// Output: Reference to a new complex whose value is the answer

inline Complex Complex::tanh () CONST {
  return Complex (::tanh (this->r), ::tanh (this->i));
}

#endif COMPLEX_H				// End COMPLEX_H

