//
// 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 11/01/89 -- Initial implementation
// Updated: MBN 03/04/90 -- Added exception for DIVIDE_BY_ZERO
// Updated: MJF 03/12/90 -- Added group names to RAISE
// 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.

#ifndef COMPLEX_H				// If no Complex class
#include <cool/Complex.h>			// Include class definition
#endif

// minus_infinity -- Raise Error exception for negative infinity
// Input:            Character string of derived class and function
// Output:           None

void Complex::minus_infinity (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(Minus_Infinity),
	 "Complex::%s: Operation results in negative infinity value",
	 name);
}


// plus_infinity -- Raise Error exception for positive infinity
// Input:           Character string of derived class and function
// Output:          None

void Complex::plus_infinity (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(Plus_Infinity),
	 "Complex::%s: Operation results in positive infinity value",
	 name);
}


// overflow -- Raise Error exception for overflow occuring during conversion
// Input:      Character string of derived class and function
// Output:     None

void Complex::overflow (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(Overflow),
	 "Complex::%s: Overflow occured during type conversion", name);
}


// underflow -- Raise Error exception for underflow occuring during conversion
// Input:       Character string of derived class name and function
// Output:      None

void Complex::underflow (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(Underflow),
	 "Complex::%s: Underflow occured during type conversion",name);
}


// no_conversion -- Raise Error exception for no conversion from Complex
// Input:           Character string of derived class name and function
// Output:          None

void Complex::no_conversion (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(No_Conversion),
	 "Complex::%s: No conversion from Complex", name);
}


// divide_by_zero -- Raise Error exception for divide by zero
// Input:            Character string of derived class and function
// Output:           None

void Complex::divide_by_zero (const char* name) CONST {
  RAISE (Error, SYM(Complex), SYM(Divide_By_Zero),
	 "Complex::%s: Divide by zero", name);
}


// operator= -- Overload the assignment operator for the Complex class
// Input:       Reference to complex object
// Output:      Reference to updated complex object

Complex& Complex::operator= (const Complex& c) {
  this->r = c.r;				// Copy real part
  this->i = c.i;				// Copy imaginary part
  this->state = c.state;			// Copy state
  return *this;					// Return reference
}


// operator short -- Provide implicit conversion from complex to short
// Input:            None
// Output:           Converted number

#ifdef __cplusplus
Complex::operator short () {
  if (this->i != 0.0) {				// If there is an i-part
    this->state = N_NO_CONVERSION;		// Indicate exception case
    this->no_conversion ("operator short");	// And raise exception
  }
  else if (this->r > MAXSHORT) {		// If there is an overflow
    this->state = N_OVERFLOW;			// Indicate exception case
    this->overflow ("operator short");		// And raise exception
  }
  else if (this->r < MINSHORT) {		// If there is an underflow
    this->state = N_UNDERFLOW;			// Indicate exception case
    this->underflow ("operator short");		// And raise exception
  }
  return short(this->r);			// Return converted number
}
#endif

// operator int -- Provide implicit conversion from complex to int
// Input:          None
// Output:         Converted number

#ifdef __cplusplus
Complex::operator int () {
#else
int Complex::operator int () {
#endif
  if (this->i != 0.0) {				// If there is an i-part
    this->state = N_NO_CONVERSION;		// Indicate exception case
    this->no_conversion ("operator int");	// And raise exception
  }
  else if (this->r > MAXINT) {			// If there is an overflow
    this->state = N_OVERFLOW;			// Indicate exception case
    this->overflow ("operator int");		// And raise exception
  }
  else if (this->r < MININT) {			// If there is an underflow
    this->state = N_UNDERFLOW;			// Indicate exception case
    this->underflow ("operator int");		// And raise exception
  }
  return int (this->r);				// Return converted number
}


// operator long -- Provide implicit conversion from complex to long
// Input:           None
// Output:          Converted number

#ifdef __cplusplus
Complex::operator long () {
#else
long Complex::operator long () {
#endif
  if (this->i != 0.0) {				// If there is an i-part
    this->state = N_NO_CONVERSION;		// Indicate exception case
    this->no_conversion ("operator long");	// And raise exception
  }
  else if (this->r > MAXLONG) {			// If there is an overflow
    this->state = N_OVERFLOW;			// Indicate exception case
    this->overflow ("operator long");		// And raise exception
  }
  else if (this->r < MINLONG) {			// If there is an underflow
    this->state = N_UNDERFLOW;			// Indicate exception case
    this->underflow ("operator long");		// And raise exception
  }
  return long (this->r);			// Return converted number
}


// operator float -- Provide implicit conversion from complex to float
// Input:            None
// Output:           Converted number

#ifdef __cplusplus
Complex::operator float () {
  if (this->i != 0.0) {				// If there is an i-part
    this->state = N_NO_CONVERSION;		// Indicate exception case
    this->no_conversion ("operator float");	// And raise exception
  }
  else if (this->r > MAXFLOAT) {		// If there is an overflow
    this->state = N_OVERFLOW;			// Indicate exception case
    this->overflow ("operator float");		// And raise exception
  }
  else if (this->r < 0.0 && (-this->r) < MINFLOAT) { // Is there an underflow?
    this->state = N_UNDERFLOW;			// Indicate exception case
    this->underflow ("operator float");		// And raise exception
  }
  return float (this->r);			// Return converted number
}
#endif

// operator double -- Provide implicit conversion from complex to double
// Input:             None
// Output:            Converted number

#ifdef __cplusplus
Complex::operator double () {
#else
double Complex::operator double () {
#endif
  if (this->i != 0.0) {				// If there is an i-part
    this->state = N_NO_CONVERSION;		// Indicate exception case
    this->no_conversion ("operator double");	// And raise exception
  }
  return double (this->r);			// Return converted number
}


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

Complex operator/ (const Complex& c1, const Complex& c2) {
  if (c2.real() == 0.0 && c2.imaginary() == 0.0)  // If both num and den zero
    c1.divide_by_zero ("operator/");		  // Raise exception
  if (c2.real() == 0.0)				  // If zero real part
    if (c1.real() < 0.0 && c1.imaginary() >= 0.0) // If negative complex
      c1.minus_infinity ("operator/");		  // Raise exception
    else
      c1.plus_infinity ("operator/");		  // Raise exception
  if (c2.imaginary() == 0.0)			  // If zero real part
    if (c1.imaginary() < 0.0 && c1.real() >= 0.0) // If negative complex
      c1.minus_infinity ("operator/");		  // Raise exception
    else
      c1.plus_infinity ("operator/");		   // Raise exception
  double normalize = (c2.r * c2.r) + (c2.i * c2.i);
  return Complex ((((c1.r * c2.r) + (c1.i * c2.i)) / normalize), 
		  (((c1.i * c2.r) - (c1.r * c2.i)) / normalize));
}


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

ostream& operator<< (ostream& os, const Complex& c) {
  os << "(" << c.r << "," << c.i << ")";
  return os;
}


// print --  terse print function for Complex
// Input:    reference to output stream
// Output:   none

void Complex::print(ostream& os) {
  os << form("/* Complex %lx */", (long) this);
}

// end Complex.C
