///////////////////////////////////////////////////////////////////////////
// FILE: complex (Complex numbers)
//
//                          Open Watcom Project
//
//    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
//
//    This file is automatically generated. Do not edit directly.
//
// =========================================================================
//
// Description: This header is part of the C++ standard library. It
//              provides support for complex numbers with varying levels
//              of precision.
///////////////////////////////////////////////////////////////////////////
#ifndef _COMPLEX_INCLUDED
#define _COMPLEX_INCLUDED

#if !defined(_ENABLE_AUTODEPEND)
  #pragma read_only_file;
#endif


#ifndef __cplusplus
#error The header complex requires C++
#endif

#ifndef _CMATH_INCLUDED
 #include <cmath>
#endif

namespace std {

  template< class FloatT >
  class complex {
  public:
    typedef FloatT value_type;

    complex( const FloatT &r = FloatT( ), const FloatT &i = FloatT( ) ) :
      re( r ), im( i )
      { }

    FloatT real( ) const { return( re ); }
    FloatT imag( ) const { return( im ); }

    complex &operator= ( const FloatT & );
    complex &operator+=( const FloatT & );
    complex &operator-=( const FloatT & );
    complex &operator*=( const FloatT & );
    complex &operator/=( const FloatT & );

    complex &operator= ( const complex & );
    complex &operator+=( const complex & );
    complex &operator-=( const complex & );
    complex &operator*=( const complex & );
    complex &operator/=( const complex & );

  private:
    FloatT re;
    FloatT im;
  };

  //
  // Complex members.
  //

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator=( const FloatT &num )
  {
    re = num;
    im = FloatT( );
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator+=( const FloatT &num )
  {
    re += num;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator-=( const FloatT &num )
  {
    re -= num;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator*=( const FloatT &num )
  {
    re *= num;
    im *= num;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator/=( const FloatT &num )
  {
    re /= num;
    im /= num;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator=( const complex &num )
  {
    re = num.re;
    im = num.im;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator+=( const complex &num )
  {
    re += num.re;
    im += num.im;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator-=( const complex &num )
  {
    re -= num.re;
    im -= num.im;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator*=( const complex &num )
  {
    FloatT new_re( re * num.re - im * num.im );
    FloatT new_im( re * num.im + im * num.re );
    re = new_re;
    im = new_im;
    return( *this );
  }

  template< class FloatT >
  inline
  complex< FloatT > &complex< FloatT >::operator/=( const complex &num )
  {
    FloatT denom( num.re * num.re + num.im * num.im );
    FloatT new_re( re * num.re + im * num.im );
    FloatT new_im( im * num.re - re * num.im );
    re = new_re / denom;
    im = new_im / denom;
    return( *this );
  }

  //
  // Complex non-members.
  //

  template< class FloatT >
  inline
  complex< FloatT > operator+( const complex< FloatT > &x )
  {
    return( x );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator+(
    const complex< FloatT > &x,
    const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp += y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator+( const complex< FloatT > &x, const FloatT &y )
  {
    complex< FloatT > temp( x );
    temp += y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator+( const FloatT &x, const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp += y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator-( const complex< FloatT > &x )
  {
    return( complex< FloatT >( -x.real( ), -x.imag( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator-(
    const complex< FloatT > &x,
    const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp -= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator-( const complex< FloatT > &x, const FloatT &y )
  {
    complex< FloatT > temp( x );
    temp -= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator-( const FloatT &x, const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp -= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator*(
    const complex< FloatT > &x,
    const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp *= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator*( const complex< FloatT > &x, const FloatT &y )
  {
    complex< FloatT > temp( x );
    temp *= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator*( const FloatT &x, const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp *= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator/(
    const complex< FloatT > &x,
    const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp /= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator/( const complex< FloatT > &x, const FloatT &y )
  {
    complex< FloatT > temp( x );
    temp /= y;
    return( temp );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator/( const FloatT &x, const complex< FloatT > &y )
  {
    complex< FloatT > temp( x );
    temp /= y;
    return( temp );
  }

  template< class FloatT >
  inline
  bool operator==( const complex< FloatT > &x, const complex< FloatT > &y )
  {
    return( ( x.real( ) == y.real( ) ) && ( x.imag( ) == y.imag( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator==( const complex< FloatT > &x, const FloatT &y )
  {
    return( ( x.real( ) == y ) && ( x.imag( ) == FloatT( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator==( const FloatT &x, const complex< FloatT > &y )
  {
    return( ( x == y.real( ) ) && ( FloatT( ) == y.imag( ) ) );
  }

  template< class FloatT >
  inline
  bool operator!=( const complex< FloatT > &x, const complex< FloatT > &y )
  {
    return( ( x.real( ) != y.real( ) ) || ( x.imag( ) != y.imag( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator!=( const complex< FloatT > &x, const FloatT &y )
  {
    return( ( x.real( ) != y ) || ( x.imag( ) != FloatT( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > operator!=( const FloatT &x, const complex< FloatT > &y )
  {
    return( ( x != y.real( ) ) || ( FloatT( ) != y.imag( ) ) );
  }

  template< class FloatT >
  inline
  FloatT real( const complex< FloatT > &x )
  {
    return( x.real( ) );
  }

  template< class FloatT >
  inline
  FloatT imag( const complex< FloatT > &x )
  {
    return( x.imag( ) );
  }

  template< class FloatT >
  inline
  FloatT abs( const complex< FloatT > &x )
  {
    return( sqrt( x.real( ) * x.real( ) + x.imag( ) * x.imag( ) ) );
  }

  template< class FloatT >
  inline
  FloatT arg( const complex< FloatT > &x )
  {
    return( atan2( x.imag( ), x.real( ) ) );
  }

  template< class FloatT >
  inline
  FloatT norm( const complex< FloatT > &x )
  {
    return( x.real( ) * x.real( ) + x.imag( ) * x.imag( ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > conj( const complex< FloatT > &x )
  {
    return( complex< FloatT >( x.real( ), -x.imag( ) ) );
  }

  template< class FloatT >
  inline
  complex< FloatT > polar( const FloatT &rho, const FloatT &theta )
  {
    return( complex< FloatT >( rho * cos( theta ), rho * sin( theta ) ) );
  }

  template< class FloatT >
  complex< FloatT > cos( const complex< FloatT > &x )
  {
    return( complex< FloatT >(  cos( x.real( ) ) * cosh( x.imag( ) ),
                               -sin( x.real( ) ) * sinh( x.imag( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > cosh( const complex< FloatT > &x )
  {
    return( complex< FloatT >( cosh( x.real( ) ) * cos( x.imag( ) ),
                               sinh( x.real( ) ) * sin( x.imag( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > exp( const complex< FloatT > &x )
  {
    FloatT multiplier( exp( x.real( ) ) );
    return( complex< FloatT >( multiplier * cos( x.imag( ) ),
                               multiplier * sin( x.imag( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > log( const complex< FloatT > &x )
  {
    FloatT mag_rp( abs( x.real( ) ) );
    FloatT mag_ip( abs( x.imag( ) ) );

    // Handle cases when mag_rp and mag_ip are very different.
    if( mag_rp > 32 * mag_ip ) {
      FloatT temp1( x.imag( ) / x.real( ) );
      FloatT temp2( 1.0 + ( temp1 * temp1 ) );
      return( complex< FloatT >( log( mag_rp ) + 0.5 * log( temp2 ),
                                 atan2( x.imag( ), x.real( ) ) ) );
    }
    else if( mag_ip > 32 * mag_rp ) {
      FloatT temp1( x.real( ) / x.imag( ) );
      FloatT temp2( 1.0 + ( temp1 * temp1 ) );
      return( complex< FloatT >( log( mag_ip ) + 0.5 * log( temp2 ),
                                 atan2( x.imag( ), x.real( ) ) ) );
    }

    // Otherwise use the direct expression.
    return( complex< FloatT >( 0.5 * log( x.real( ) * x.real( ) +
                                          x.imag( ) * x.imag( ) ),
                               atan2( x.imag( ), x.real( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > log10( const complex< FloatT > &x )
  {
    FloatT ten( 10.0 );  // So overload resolution chooses right log.
    return( log( x ) / log( ten ) );
  }

  template< class FloatT >
  complex< FloatT > pow( const complex< FloatT > &x, int y )
  {
    return( exp( static_cast< FloatT >( y ) * log( x ) ) );
  }

  template< class FloatT >
  complex< FloatT > pow(
    const complex< FloatT > &x, const complex< FloatT > &y )
  {
    return( exp( y * log( x ) ) );
  }

  template< class FloatT >
  complex< FloatT > pow( const complex< FloatT > &x, const FloatT &y )
  {
    return( exp( y * log( x ) ) );
  }

  template< class FloatT >
  complex< FloatT > pow( const FloatT &x, const complex< FloatT > &y )
  {
    return( exp( y * log( x ) ) );
  }

  template< class FloatT >
  complex< FloatT > sin( const complex< FloatT > &x )
  {
    return( complex< FloatT >( sin( x.real( ) ) * cosh( x.imag( ) ),
                               cos( x.real( ) ) * sinh( x.imag( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > sinh( const complex< FloatT > &x )
  {
    return( complex< FloatT >( sinh( x.real( ) ) * cos( x.imag( ) ),
                               cosh( x.real( ) ) * sin( x.imag( ) ) ) );
  }

  template< class FloatT >
  complex< FloatT > sqrt( const complex< FloatT > &x )
  {
    return( complex< FloatT >( polar( sqrt( abs( x ) ),
                                      arg( x ) / 2 ) ) );
  }

  template< class FloatT >
  complex< FloatT > tan( const complex< FloatT > &x )
  {
    return( sin( x ) / cos( x ) );
  }

  template< class FloatT >
  complex< FloatT > tanh( const complex< FloatT > &x )
  {
    return( sinh( x ) / cosh( x ) );
  }

} // namespace std

#endif
