//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : bigcomplex.h 
// Author      : Thomas Papanikolaou (TP)
// Last change : TP, Feb 7  1995, initial version
//		 MM, Nov 21 1996, added is_real()
//		  		  and   is_imaginary()
//

#ifndef LIDIA_COMPLEX_H
#define LIDIA_COMPLEX_H

#include <LiDIA/bigfloat.h>

class bigcomplex
{
  /**
   ** the C++ type we use to represent a bigcomplex
   **/

  bigfloat re;
  bigfloat im;

 public:

  /**
   ** constructors and destructor
   **/

  bigcomplex();
  bigcomplex(const bigfloat &);
  bigcomplex(const bigfloat &, const bigfloat &);
  bigcomplex(const bigcomplex &);
  ~bigcomplex();

#ifndef HEADBANGER

  /**
   ** inline member functions
   **/

  bigfloat real() const;
  bigfloat imag() const;

  bool is_zero() const;
  bool is_real() const;
  bool is_imaginary() const;

  void negate();
  void invert();
  
  void assign_zero();
  void assign_one();
  void assign(const bigfloat & x);
  void assign(const bigfloat & x, const bigfloat & y);
  void assign(const bigcomplex & x);

  /**
   ** Precision and rounding mode setting
   **/

  static void precision(long l);
  static void mode(int l);

  /**
   ** type checking
   **/

  //friend int is_double(const bigcomplex & a);
  friend bool is_bigfloat(const bigcomplex & a);

#endif

  /**
   ** assignments
   **/

  bigfloat operator = (const bigfloat & y);
  bigcomplex & operator = (const bigcomplex & y);

  /**
   ** comparisons
   **/

  friend bool operator == (const bigcomplex & x, const bigcomplex & y);
  friend bool operator != (const bigcomplex & x, const bigcomplex & y);
  friend bool operator == (const bigcomplex & x, const bigfloat & y);
  friend bool operator != (const bigcomplex & x, const bigfloat & y);
  friend bool operator == (const bigfloat & x, const bigcomplex & y);
  friend bool operator != (const bigfloat & x, const bigcomplex & y);

  /**
   ** operator overloading
   **/

  friend bigcomplex operator - (const bigcomplex & x);
  friend bigcomplex operator + (const bigcomplex & x, const bigcomplex & y);
  friend bigcomplex operator - (const bigcomplex & x, const bigcomplex & y);
  friend bigcomplex operator * (const bigcomplex & x, const bigcomplex & y);
  friend bigcomplex operator / (const bigcomplex & x, const bigcomplex & y);

  friend bigcomplex operator + (const bigcomplex & x, const bigfloat & y);
  friend bigcomplex operator - (const bigcomplex & x, const bigfloat & y);
  friend bigcomplex operator * (const bigcomplex & x, const bigfloat & y);
  friend bigcomplex operator / (const bigcomplex & x, const bigfloat & y);

  friend bigcomplex operator + (const bigfloat & x, const bigcomplex & y);
  friend bigcomplex operator - (const bigfloat & x, const bigcomplex & y);
  friend bigcomplex operator * (const bigfloat & x, const bigcomplex & y);
  friend bigcomplex operator / (const bigfloat & x, const bigcomplex & y);

  bigcomplex & operator += (const bigcomplex & y);
  bigcomplex & operator -= (const bigcomplex & y);
  bigcomplex & operator *= (const bigcomplex & y);
  bigcomplex & operator /= (const bigcomplex & y);

  bigcomplex & operator += (const bigfloat & y);
  bigcomplex & operator -= (const bigfloat & y);
  bigcomplex & operator *= (const bigfloat & y);
  bigcomplex & operator /= (const bigfloat & y);

#ifndef HEADBANGER

  /**
   ** Procedural versions
   **/

  friend void negate(bigcomplex & x, const bigcomplex & y);
  friend void add(bigcomplex & x, const bigcomplex & y, const bigcomplex & z);
  friend void subtract(bigcomplex & x, const bigcomplex & y, const bigcomplex & z);
  friend void multiply(bigcomplex & x, const bigcomplex & y, const bigcomplex & z);
  friend void divide(bigcomplex & x, const bigcomplex & y, const bigcomplex & z);
  friend void add(bigcomplex & x, const bigcomplex & y, const bigfloat & z);
  friend void subtract(bigcomplex & x, const bigcomplex & y, const bigfloat & z);
  friend void multiply(bigcomplex & x, const bigcomplex & y, const bigfloat & z);
  friend void divide(bigcomplex & x, const bigcomplex & y, const bigfloat & z);
  friend void add(bigcomplex & x, const bigfloat & y, const bigcomplex & z);
  friend void subtract(bigcomplex & x, const bigfloat & y, const bigcomplex & z);
  friend void multiply(bigcomplex & x, const bigfloat & y, const bigcomplex & z);
  friend void divide(bigcomplex & x, const bigfloat & y, const bigcomplex & z);

  /**
   ** Functions
   **/

  friend void conj(bigcomplex & y, const bigcomplex & x);
  friend void polar(bigcomplex & y, const bigfloat & r, const bigfloat & t);
  friend void cos(bigcomplex & y, const bigcomplex & x);
  friend void sin(bigcomplex & y, const bigcomplex & x);
  friend void cosh(bigcomplex & y, const bigcomplex & x);
  friend void sinh(bigcomplex & y, const bigcomplex & x);
  friend void sqrt(bigcomplex & y, const bigcomplex & x);
  friend void exp(bigcomplex & y, const bigcomplex & x);
  friend void log(bigcomplex & y, const bigcomplex & x);
  friend void power(bigcomplex & y, const bigcomplex & x, const bigcomplex & p);
  friend void power(bigcomplex & y, const bigcomplex & x, const bigfloat & p);
  friend void power(bigcomplex & y, const bigcomplex & x, long p);
  friend void invert(bigcomplex & x, const bigcomplex & z);
  friend void swap(bigcomplex & x, bigcomplex & z);
  friend void square(bigcomplex & x, const bigcomplex & z);

#endif

  friend bigcomplex conj(const bigcomplex & x);
  friend bigcomplex polar(const bigfloat & r, const bigfloat & t);
  friend bigcomplex cos(const bigcomplex & x);
  friend bigcomplex sin(const bigcomplex & x);
  friend bigcomplex cosh(const bigcomplex & x);
  friend bigcomplex sinh(const bigcomplex & x);
  friend bigcomplex sqrt(const bigcomplex & x);
  friend bigcomplex exp(const bigcomplex & x);
  friend bigcomplex log(const bigcomplex & x);
  friend bigcomplex power(const bigcomplex & x, const bigcomplex & p);
  friend bigcomplex power(const bigcomplex & x, const bigfloat & y);
  friend bigcomplex power(const bigcomplex & x, long p);
  friend bigcomplex inverse(const bigcomplex & z);
  friend bigcomplex square(const bigcomplex & z);

  friend bigfloat real(const bigcomplex & x);
  friend bigfloat imag(const bigcomplex & x);
  friend bigfloat abs(const bigcomplex & x);
  friend bigfloat norm(const bigcomplex & x);
  friend bigfloat hypot(const bigcomplex & x);
  friend bigfloat arg(const bigcomplex & x);


  /**
   ** Input/Output
   **/

  friend istream & operator >> (istream & s, bigcomplex & x);
  friend ostream & operator << (ostream & s, const bigcomplex & x);

};

#endif
