// complex standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _COMPLEX_
#define _COMPLEX_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <ccomplex>
#include <cmath>
#include <sstream>

/* Module consistency. */
#pragma rtmodel="__dlib_full_locale_support", \
  _STRINGIFY(_DLIB_FULL_LOCALE_SUPPORT)

#ifndef _C_COMPLEX_T
  #define _C_COMPLEX_T

  typedef struct _C_double_complex
  {       /* double complex */
    double _Val[2];
  } _C_double_complex;

  typedef struct _C_float_complex
  {       /* float complex */
    float _Val[2];
  } _C_float_complex;

  typedef struct _C_ldouble_complex
  {       /* long double complex */
    long double _Val[2];
  } _C_ldouble_complex;
#endif /* _C_COMPLEX_T */

// COMPLEX _Val OFFSETS
#define _RE    0
#define _IM    1

extern "C" {
  __EFF_NS __ATTRIBUTES    float        __iar_Cosh32(float, float);
  __EFF_NS __ATTRIBUTES    float        __iar_Exp32(float, float, __int32_t);
  __EFF_NS __ATTRIBUTES    float        __iar_Sinh32(float, float);
  #if __DOUBLE_SIZE__ == 8
  __EFF_NS __ATTRIBUTES    double       __iar_Cosh64(double, double);
  __EFF_NS __ATTRIBUTES    double       __iar_Exp64(double, double, __int32_t);
  __EFF_NS __ATTRIBUTES    double       __iar_Sinh64(double, double);

  #define __iar_TYPE  double
  #define __iar_Coshd __iar_Cosh64
  #define __iar_Expd  __iar_Exp64
  #define __iar_Sinhd __iar_Sinh64
  #else
  #define __iar_TYPE  float
  #define __iar_Coshd __iar_Cosh32
  #define __iar_Expd  __iar_Exp32
  #define __iar_Sinhd __iar_Sinh32
  #endif
} // extern "C"

namespace std {

typedef ::_C_double_complex _Dcomplex_value;
typedef ::_C_float_complex _Fcomplex_value;
typedef ::_C_ldouble_complex _Lcomplex_value;

template<class _Ty> class complex;
template<> class complex<float>;
template<> class complex<double>;
template<> class complex<long double>;

// TEMPLATE CLASS _Ctraits
template<class _Ty>
class _Ctraits
{       // complex traits for _Ty
public:
  static _Ty _Flt_eps()
  {       // get epsilon
    return numeric_limits<_Ty>::epsilon();
  }

  static _Ty _Flt_max()
  {       // get max
    return numeric_limits<_Ty>::max();
  }

  static _Ty _Cosh(_Ty _Left, _Ty _Right)
  {       // return cosh(_Left) * _Right
    return ::__iar_Coshd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty _Exp(_Ty _Left, _Ty _Right, short _Exponent)
  {       // compute exp(_Left) * _Right * 2 ^ _Exponent
    return (_Ty) ::__iar_Expd((__iar_TYPE)_Left, (__iar_TYPE)_Right, _Exponent);
  }

  static _Ty _Infv(_Ty)
  {       // return infinity
    return 0.Infinity;
  }

  static bool _Isinf(_Ty _Left)
  {       // test for infinity
    double _Tmp = (double)_Left;
    return ::isinf(_Tmp);
  }

  static bool _Isnan(_Ty _Left)
  {       // test for NaN
    double _Tmp = (double)_Left;
    return ::isnan(_Tmp);
  }

  static _Ty _Nanv(_Ty)
  {       // return NaN
    return 0.Nan;
  }

  static _Ty _Sinh(_Ty _Left, _Ty _Right)
  {       // return sinh(_Left) * _Right
    return ::__iar_Sinhd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty asinh(_Ty _Left)
  {       // return asinh(_Left)
    static const _Ty _Ln2 = 0.69314718055994530941723212145817658L;

    bool _Neg = _Left < 0;
    _Ty _Ans;

    if (_Neg)
      _Left = -_Left;
    if (_Left < 2 / _Flt_eps())
    {
      _Ans = ::log1p(_Left + _Left * _Left / (1 + ::sqrt(_Left * _Left + 1)));
    }
    else
    {
      _Ans = ::log(_Left) + _Ln2;
    }
    return _Neg ? -_Ans : _Ans;
  }

  static _Ty atan2(_Ty _Yval, _Ty _Xval)
  {       // return atan(_Yval / _Xval)
    return ::atan2((double)_Yval, (double)_Xval);
  }

  static _Ty cos(_Ty _Left)
  {       // return cos(_Left)
    return ::cos((double)_Left);
  }

  static _Ty exp(_Ty _Left)
  {       // return exp(_Left)
    return ::exp((double)_Left);
  }

  static _Ty ldexp(_Ty _Left, int _Exponent)
  {       // return _Left * 2 ^ _Exponent
    return ::ldexp((double)_Left, _Exponent);
  }

  static _Ty log(_Ty _Left)
  {       // return log(_Left)
    return ::log((double)_Left);
  }

  static _Ty log1p(_Ty _Left)
  {       // return log(1 + _Left)
    if (_Left < -1)
    {
      return _Nanv(_Left);
    }
    else if (_Left == 0)
    {
      return _Left;
    }
    else
    {       // compute log(1 + _Left) with fixup for small _Left
      _Ty _Leftp1 = 1 + _Left;
      return ::log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
    }
  }

  static _Ty pow(_Ty _Left, _Ty _Right)
  {       // return _Left ^ _Right
    return ::pow((double)_Left, (double)_Right);
  }

  static _Ty sin(_Ty _Left)
  {       // return sin(_Left)
    return ::sin((double)_Left);
  }

  static _Ty sqrt(_Ty _Left)
  {       // return sqrt(_Left)
    return ::sqrt((double)_Left);
  }

  static _Ty tan(_Ty _Left)
  {       // return tan(_Left)
    return ::tan((double)_Left);
  }
};

// CLASS _Ctraits<long double>
template<> class _Ctraits<long double>
{       // complex traits for long double
public:
  typedef long double _Ty;

  static _Ty _Flt_eps()
  {       // get epsilon
    return LDBL_EPSILON;
  }

  static _Ty _Flt_max()
  {       // get max
    return LDBL_MAX;
  }

  static _Ty _Cosh(_Ty _Left, _Ty _Right)
  {       // return cosh(_Left) * _Right
    return ::__iar_Coshd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty _Exp(_Ty _Left, _Ty _Right, short _Exponent)
  {       // compute exp(_Left) * _Right * 2 ^ _Exponent
    return ::__iar_Expd((__iar_TYPE)_Left, (__iar_TYPE)_Right, _Exponent);
  }

  static _Ty _Infv(_Ty)
  {       // return infinity
    return 0.Infinity;
  }

  static bool _Isinf(_Ty _Left)
  {       // test for infinity
    return ::isinf(_Left);
  }

  static bool _Isnan(_Ty _Left)
  {       // test for NaN
    return ::isnan(_Left);
  }

  static _Ty _Nanv(_Ty)
  {       // return NaN
    return 0.Nan;
  }

  static _Ty _Sinh(_Ty _Left, _Ty _Right)
  {       // return sinh(_Left) * _Right
    return ::__iar_Sinhd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty asinh(_Ty _Left)
  {       // return asinh(_Left)
    static const _Ty _Ln2 = 0.69314718055994530941723212145817658L;

    bool _Neg = _Left < 0;
    _Ty _Ans;

    if (_Neg)
      _Left = -_Left;
    if (_Left < 2 / _Flt_eps())
    {
      _Ans = ::log1pl(_Left + _Left * _Left / (1 + ::sqrtl(_Left * _Left + 1)));
    }
    else
    {
      _Ans = ::logl(_Left) + _Ln2;
    }
    return _Neg ? -_Ans : _Ans;
  }

  static _Ty atan2(_Ty _Yval, _Ty _Xval)
  {       // return atan(_Yval / _Xval)
    return ::atan2l(_Yval, _Xval);
  }

  static _Ty cos(_Ty _Left)
  {       // return cos(_Left)
    return ::cosl(_Left);
  }

  static _Ty exp(_Ty _Left)
  {       // return exp(_Left)
    return ::expl(_Left);
  }

  static _Ty ldexp(_Ty _Left, int _Exponent)
  {       // return _Left * 2 ^ _Exponent
    return ::ldexpl(_Left, _Exponent);
  }

  static _Ty log(_Ty _Left)
  {       // return log(_Left)
    return ::logl(_Left);
  }

  static _Ty log1p(_Ty _Left)
  {       // return log(1 + _Left)
    if (_Left < -1)
    {
      return _Nanv(_Left);
    }
    else if (_Left == 0)
    {
      return _Left;}
    else
    {       // compute log(1 + _Left) with fixup for small _Left
      _Ty _Leftp1 = 1 + _Left;
      return ::logl(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
    }
  }

  static _Ty pow(_Ty _Left, _Ty _Right)
  {       // return _Left ^ _Right
    return ::powl(_Left, _Right);
  }

  static _Ty sin(_Ty _Left)
  {       // return sin(_Left)
    return ::sinl(_Left);
  }

  static _Ty sqrt(_Ty _Left)
  {       // return sqrt(_Left)
    return ::sqrtl(_Left);
  }

  static _Ty tan(_Ty _Left)
  {       // return tan(_Left)
    return ::tanl(_Left);
  }
};

// CLASS _Ctraits<double>
template<> class _Ctraits<double>
{       // complex traits for double
public:
  typedef double _Ty;

  static _Ty _Flt_eps()
  {       // get epsilon
    return DBL_EPSILON;
  }

  static _Ty _Flt_max()
  {       // get max
    return DBL_MAX;
  }

  static _Ty _Cosh(_Ty _Left, _Ty _Right)
  {       // return cosh(_Left) * _Right
    return ::__iar_Coshd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty _Exp(_Ty _Left, _Ty _Right, short _Exponent)
  {       // compute exp(_Left) * _Right * 2 ^ _Exponent
    return ::__iar_Expd((__iar_TYPE)_Left, (__iar_TYPE)_Right, _Exponent);
  }

  static _Ty _Infv(_Ty)
  {       // return infinity
    return 0.Infinity;
  }

  static bool _Isinf(_Ty _Left)
  {       // test for infinity
    return ::isinf(_Left);
  }

  static bool _Isnan(_Ty _Left)
  {       // test for NaN
    return ::isnan(_Left);
  }

  static _Ty _Nanv(_Ty)
  {       // return NaN
    return 0.Nan;
  }

  static _Ty _Sinh(_Ty _Left, _Ty _Right)
  {       // return sinh(_Left) * _Right
    return ::__iar_Sinhd((__iar_TYPE)_Left, (__iar_TYPE)_Right);
  }

  static _Ty asinh(_Ty _Left)
  {       // return asinh(_Left)
    if (_Isnan(_Left) || _Isinf(_Left) || _Left == 0)
      return 0;
    else
    {       // _Left finite nonzero
      bool _Neg = _Left < 0;
      _Ty _Ans;

      if (_Neg)
        _Left = -_Left;
      if (_Left < 2 / _Flt_eps())
      {
        _Ans = ::log1p(_Left + _Left * _Left / (1 + ::sqrt(_Left * _Left + 1)));
      }
      else
      { // _Left big, compute log(_Left+_Left)
        _Ans = ::log(_Left) + (_Ty)0.69314718055994530941723212145817658L;
      }
      return _Neg ? -_Ans : _Ans;
    }
  }

  static _Ty atan2(_Ty _Yval, _Ty _Xval)
  {       // return atan(_Yval / _Xval)
    return ::atan2(_Yval, _Xval);
  }

  static _Ty cos(_Ty _Left)
  {       // return cos(_Left)
    return ::cos(_Left);
  }

  static _Ty exp(_Ty _Left)
  {       // return exp(_Left)
    return ::exp(_Left);
  }

  static _Ty ldexp(_Ty _Left, int _Exponent)
  {       // return _Left * 2 ^ _Exponent
    return ::ldexp(_Left, _Exponent);
  }

  static _Ty log(_Ty _Left)
  {       // return log(_Left)
    return ::log(_Left);
  }

  static _Ty log1p(_Ty _Left)
  {       // return log(1 + _Left)
    if (_Isnan(_Left) || _Left == 0 || (_Isinf(_Left) && 0 < _Left))
      return _Left;
    else if (_Left < -1)
      return _Nanv(_Left);
    else if (_Left == -1)
      return -_Infv(_Left);
    else if (_Left == 0)
      return _Left;
    else
    {       // compute log(1 + _Left) with fixup for small _Left
      _Ty _Leftp1 = 1 + _Left;
      return ::log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
    }
  }

  static _Ty pow(_Ty _Left, _Ty _Right)
  {       // return _Left ^ _Right
    return ::pow(_Left, _Right);
  }

  static _Ty sin(_Ty _Left)
  {       // return sin(_Left)
    return ::sin(_Left);
  }

  static _Ty sqrt(_Ty _Left)
  {       // return sqrt(_Left)
    return ::sqrt(_Left);
  }

  static _Ty tan(_Ty _Left)
  {       // return tan(_Left)
    return ::tan(_Left);
  }
};

// CLASS _Ctraits<float>
template<> class _Ctraits<float>
{       // complex traits for float
public:
  typedef float _Ty;

  static _Ty _Flt_eps()
  {       // get epsilon
    return FLT_EPSILON;
  }

  static _Ty _Flt_max()
  {       // get max
    return FLT_MAX;
  }

  static _Ty _Cosh(_Ty _Left, _Ty _Right)
  {       // return cosh(_Left) * _Right
    return ::__iar_Cosh32(_Left, _Right);
  }

  static _Ty _Exp(_Ty _Left, _Ty _Right, short _Exponent)
  {       // compute exp(_Left) * _Right * 2 ^ _Exponent
    return ::__iar_Exp32(_Left, _Right, _Exponent);
  }

  static _Ty _Infv(_Ty)
  {       // return infinity
    return 0.Infinity;
  }

  static bool _Isinf(_Ty _Left)
  {       // test for infinity
    return ::isinf(_Left);
  }

  static bool _Isnan(_Ty _Left)
  {       // test for NaN
    return ::isnan(_Left);
  }

  static _Ty _Nanv(_Ty)
  {       // return NaN
    return 0.Nan;
  }

  static _Ty _Sinh(_Ty _Left, _Ty _Right)
  {       // return sinh(_Left) * _Right
    return ::__iar_Sinh32(_Left, _Right);
  }

  static _Ty asinh(_Ty _Left)
  {       // return asinh(_Left)
    static const _Ty _Ln2 = 0.69314718055994530941723212145817658F;

    bool _Neg = _Left < 0;
    _Ty _Ans;

    if (_Neg)
      _Left = -_Left;
    if (_Left < 2 / _Flt_eps())
    {
      _Ans = ::log1pf(_Left + _Left * _Left / (1 + ::sqrtf(_Left * _Left + 1)));
    }
    else
    {
      _Ans = ::logf(_Left) + _Ln2;
    }
    return _Neg ? -_Ans : _Ans;
  }

  static _Ty atan2(_Ty _Yval, _Ty _Xval)
  {       // return atan(_Yval / _Xval)
    return ::atan2f(_Yval, _Xval);
  }

  static _Ty cos(_Ty _Left)
  {       // return cos(_Left)
    return ::cosf(_Left);
  }

  static _Ty exp(_Ty _Left)
  {       // return exp(_Left)
    return ::expf(_Left);
  }

  static _Ty ldexp(_Ty _Left, int _Exponent)
  {       // return _Left * 2 ^ _Exponent
    return ::ldexpf(_Left, _Exponent);
  }

  static _Ty log(_Ty _Left)
  {       // return log(_Left)
    return ::logf(_Left);
  }

  static _Ty log1p(_Ty _Left)
  {       // return log(1 + _Left)
    if (_Left < -1)
    {
      return _Nanv(_Left);
    }
    else if (_Left == 0)
    {
      return _Left;
    }
    else
    {       // compute log(1 + _Left) with fixup for small _Left
      _Ty _Leftp1 = 1 + _Left;
      return ::logf(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
    }
  }

  static _Ty pow(_Ty _Left, _Ty _Right)
  {       // return _Left ^ _Right
    return ::powf(_Left, _Right);
  }

  static _Ty sin(_Ty _Left)
  {       // return sin(_Left)
    return ::sinf(_Left);
  }

  static _Ty sqrt(_Ty _Left)
  {       // return sqrt(_Left)
    return ::sqrtf(_Left);
  }

  static _Ty tan(_Ty _Left)
  {       // return tan(_Left)
    return ::tanf(_Left);
  }
};

// TEMPLATE CLASS _Complex_value
template<class _Ty>
struct _Complex_value
{       /* templatized complex value */
  enum {_Re = 0, _Im = 1};
  _Ty _Val[2];
};

// TEMPLATE CLASS _Complex_base
template<class _Ty, class _Valbase>
class _Complex_base
  : public _Valbase
{       // base for all complex types
public:
  typedef _Ctraits<_Ty> _Myctraits;
  typedef _Complex_base<_Ty, _Valbase> _Myt;
  typedef _Ty value_type;

  // Constructor for use from the float, double, and long double specializations
  constexpr _Complex_base(_Ty _Realval, _Ty _Imagval)
    : _Valbase{{_Realval, _Imagval}}
  {       // construct from components of same type
  }

  // Constructor for use from the general complex template
  constexpr _Complex_base(const _Ty* _Realval, const _Ty* _Imagval)
    : _Valbase{{*_Realval, *_Imagval}}
  {       // construct from components of same type
  }

  void real(const _Ty& _Right)
  {       // set real component
    this->_Val[_RE] = _Right;
  }

  void imag(const _Ty& _Right)
  {       // set imaginary component
    this->_Val[_IM] = _Right;
  }

  constexpr _Ty real() const
  {       // return real component
    return this->_Val[_RE];
  }

  constexpr _Ty imag() const
  {       // return imaginary component
    return this->_Val[_IM];
  }

protected:
  template<class _Other> inline
  void _Add(const complex<_Other>& _Right)
  {       // add other complex
    this->_Val[_RE] = this->_Val[_RE] + (_Ty)_Right.real();
    this->_Val[_IM] = this->_Val[_IM] + (_Ty)_Right.imag();
  }

  template<class _Other> inline
  void _Sub(const complex<_Other>& _Right)
  {       // subtract other complex
    this->_Val[_RE] = this->_Val[_RE] - (_Ty)_Right.real();
    this->_Val[_IM] = this->_Val[_IM] - (_Ty)_Right.imag();
  }

  template<class _Other> inline
  void _Mul(const complex<_Other>& _Right)
  {       // multiply by other complex
    _Ty _Rightreal = (_Ty)_Right.real();
    _Ty _Rightimag = (_Ty)_Right.imag();

    _Ty _Tmp = this->_Val[_RE] * _Rightreal
      - this->_Val[_IM] * _Rightimag;
    this->_Val[_IM] =   this->_Val[_RE] * _Rightimag
                      + this->_Val[_IM] * _Rightreal;
    this->_Val[_RE] = _Tmp;
  }

  template<class _Other> inline
  void _Div(const complex<_Other>& _Right)
  {       // divide by other complex
    typedef _Ctraits<_Ty> _Myctraits;
    _Ty _Rightreal = (_Ty)_Right.real();
    _Ty _Rightimag = (_Ty)_Right.imag();

    if (_Myctraits::_Isnan(_Rightreal) || _Myctraits::_Isnan(_Rightimag))
    {       // set NaN result
      this->_Val[_RE] = _Myctraits::_Nanv(_Rightreal);
      this->_Val[_IM] = this->_Val[_RE];
    }
    else if (  (_Rightimag < 0 ? -_Rightimag : +_Rightimag)
             < (_Rightreal < 0 ? -_Rightreal : +_Rightreal))
    {       // |_Right.imag()| < |_Right.real()|
      _Ty _Wr = _Rightimag / _Rightreal;
      _Ty _Wd = _Rightreal + _Wr * _Rightimag;

      if (_Myctraits::_Isnan(_Wd) || _Wd == 0)
      {       // set NaN result
        this->_Val[_RE] = _Myctraits::_Nanv(_Rightreal);
        this->_Val[_IM] = this->_Val[_RE];
      }
      else
      {       // compute representable result
        _Ty _Tmp = (this->_Val[_RE]
                    + this->_Val[_IM] * _Wr) / _Wd;
        this->_Val[_IM] = (  this->_Val[_IM]
                           - this->_Val[_RE] * _Wr) / _Wd;
        this->_Val[_RE] = _Tmp;
      }
    }
    else if (_Rightimag == 0)
    {       // set NaN result
      this->_Val[_RE] = _Myctraits::_Nanv(_Rightreal);
      this->_Val[_IM] = this->_Val[_RE];
    }
    else
    {       // 0 < |_Right.real()| <= |_Right.imag()|
      _Ty _Wr = _Rightreal / _Rightimag;
      _Ty _Wd = _Rightimag + _Wr * _Rightreal;

      if (_Myctraits::_Isnan(_Wd) || _Wd == 0)
      {       // set NaN result
        this->_Val[_RE] = _Myctraits::_Nanv(_Rightreal);
        this->_Val[_IM] = this->_Val[_RE];
      }
      else
      {       // compute representable result
        _Ty _Tmp = (this->_Val[_RE] * _Wr + this->_Val[_IM]) / _Wd;
        this->_Val[_IM] = (  this->_Val[_IM] * _Wr
                           - this->_Val[_RE]) / _Wd;
        this->_Val[_RE] = _Tmp;
      }
    }
  }
};


// CLASS complex<float>
template<> class complex<float>
  : public _Complex_base<float, _Fcomplex_value>
{       // complex with float components
public:
  typedef float _Ty;
  typedef complex<_Ty> _Myt;

  constexpr explicit complex(const complex<double>&);       // defined below

  constexpr explicit complex(const complex<long double>&);  // defined below

  constexpr complex(_Ty _Realval = 0, _Ty _Imagval = 0)
    : _Complex_base<float, _Fcomplex_value>(_Realval, _Imagval)
  {       // construct from float components
  }

  constexpr complex(const _Fcomplex_value& _Right)
    : _Complex_base<float, _Fcomplex_value>(_Right._Val[_RE],
                                            _Right._Val[_IM])
  {       // construct from float complex value
  }

  constexpr complex(const _Dcomplex_value& _Right)
    : _Complex_base<float, _Fcomplex_value>(_Right._Val[_RE],
                                            _Right._Val[_IM])
  {       // construct from double complex value
  }

  constexpr complex(const _Lcomplex_value& _Right)
    : _Complex_base<float, _Fcomplex_value>(_Right._Val[_RE],
                                            _Right._Val[_IM])
  {       // construct from long double complex value
  }

  complex<_Ty>& operator=(_Ty _Right)
  {       // assign real
    _Val[_RE] = _Right;
    _Val[_IM] = 0;
    return *this;
  }

  #if 0
    complex(const _C_float_complex& _Right)
      : _Complex_base<float, _Fcomplex_value>(
        ((float *)&_Right)[0],
        ((float *)&_Right)[1])
    {       // construct from C float complex value
    }

    operator _C_float_complex() const
    {       // extract C float complex value
      return *(_C_float_complex *)&_Val[_RE];
    }
  #endif

  _Myt& operator+=(_Ty _Right)
  {       // add real
    _Val[_RE] = _Val[_RE] + _Right;
    return *this;
  }

  _Myt& operator-=(_Ty _Right)
  {       // subtract real
    _Val[_RE] = _Val[_RE] - _Right;
    return *this;
  }

  _Myt& operator*=(_Ty _Right)
  {       // multiply by real
    _Val[_RE] = _Val[_RE] * _Right;
    _Val[_IM] = _Val[_IM] * _Right;
    return *this;
  }

  _Myt& operator/=(_Ty _Right)
  {       // divide by real
    _Val[_RE] = _Val[_RE] / _Right;
    _Val[_IM] = _Val[_IM] / _Right;
    return *this;
  }

  template<class _Other> inline
  _Myt& operator=(const complex<_Other>& _Right)
  {       // assign another complex
    _Val[_RE] = (_Ty)_Right._Val[_RE];
    _Val[_IM] = (_Ty)_Right._Val[_IM];
    return *this;
  }

  template<class _Other> inline
  _Myt& operator+=(const complex<_Other>& _Right)
  {       // add other complex
    _Add(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator-=(const complex<_Other>& _Right)
  {       // subtract other complex
    _Sub(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator*=(const complex<_Other>& _Right)
  {       // multiply by other complex
    _Mul(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator/=(const complex<_Other>& _Right)
  {       // divide by other complex
    _Div(_Right);
    return *this;
  }
};

// CLASS complex<double>
template<> class complex<double>
  : public _Complex_base<double, _Dcomplex_value>
{       // complex with double components
public:
  typedef double _Ty;
  typedef complex<_Ty> _Myt;

  constexpr complex(const complex<float>&); // defined below

  constexpr explicit complex(const complex<long double>&);  // defined below

  constexpr complex(_Ty _Realval = 0, _Ty _Imagval = 0)
    : _Complex_base<double, _Dcomplex_value>(_Realval, _Imagval)
  {       // construct from double components
  }

  constexpr complex(const _Dcomplex_value& _Right)
    : _Complex_base<double, _Dcomplex_value>(_Right._Val[_RE],
                                             _Right._Val[_IM])
  {       // construct from double complex value
  }

  constexpr complex(const _Lcomplex_value& _Right)
    : _Complex_base<double, _Dcomplex_value>(_Right._Val[_RE],
                                             _Right._Val[_IM])
  {       // construct from long double complex value
  }

  #if 0
    constexpr complex(const _C_double_complex& _Right)
      : _Complex_base<double, _Dcomplex_value>(
        ((double *)&_Right)[0],
        ((double *)&_Right)[1])
    {       // construct from C double complex value
    }

    operator _C_double_complex() const
    {       // extract C double complex value
      return *(_C_double_complex *)&_Val[_RE];
    }
  #endif

  complex<_Ty>& operator=(_Ty _Right)
  {       // assign real
    _Val[_RE] = _Right;
    _Val[_IM] = 0;
    return *this;
  }

  _Myt& operator+=(_Ty _Right)
  {       // add real
    _Val[_RE] = _Val[_RE] + _Right;
    return *this;
  }

  _Myt& operator-=(_Ty _Right)
  {       // subtract real
    _Val[_RE] = _Val[_RE] - _Right;
    return *this;
  }

  _Myt& operator*=(_Ty _Right)
  {       // multiply by real
    _Val[_RE] = _Val[_RE] * _Right;
    _Val[_IM] = _Val[_IM] * _Right;
    return *this;
  }

  _Myt& operator/=(_Ty _Right)
  {       // divide by real
    _Val[_RE] = _Val[_RE] / _Right;
    _Val[_IM] = _Val[_IM] / _Right;
    return *this;
  }

  template<class _Other> inline
  _Myt& operator=(const complex<_Other>& _Right)
  {       // assign another complex
    _Val[_RE] = (_Ty)_Right._Val[_RE];
    _Val[_IM] = (_Ty)_Right._Val[_IM];
    return *this;
  }

  template<class _Other> inline
  _Myt& operator+=(const complex<_Other>& _Right)
  {       // add other complex
    _Add(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator-=(const complex<_Other>& _Right)
  {       // subtract other complex
    _Sub(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator*=(const complex<_Other>& _Right)
  {       // multiply by other complex
    _Mul(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator/=(const complex<_Other>& _Right)
  {       // divide by other complex
    _Div(_Right);
    return *this;
  }
};

// CLASS complex<long double>
template<> class complex<long double>
  : public _Complex_base<long double, _Lcomplex_value>
{       // complex with long double components
public:
  typedef long double _Ty;
  typedef complex<_Ty> _Myt;

  constexpr complex(const complex<float>&); // defined below

  constexpr complex(const complex<double>&);        // defined below

  constexpr complex(_Ty _Realval = 0, _Ty _Imagval = 0)
    : _Complex_base<long double, _Lcomplex_value>(_Realval, _Imagval)
  {       // construct from long double components
  }

  constexpr complex(const _Lcomplex_value& _Right)
    : _Complex_base<long double, _Lcomplex_value>(_Right._Val[_RE],
                                                  _Right._Val[_IM])
  {       // construct from long double complex value
  }

  #if 0
    constexpr complex(const _C_ldouble_complex& _Right)
      : _Complex_base<long double, _Lcomplex_value>(
        ((long double *)&_Right)[0],
        ((long double *)&_Right)[1])
    {       // construct from C long double complex value
    }

    operator _C_ldouble_complex() const
    {       // extract C long double complex value
      return *(_C_ldouble_complex *)&_Val[_RE];
    }
  #endif

  complex<_Ty>& operator=(_Ty _Right)
  {       // assign real
    _Val[_RE] = _Right;
    _Val[_IM] = 0;
    return *this;
  }

  _Myt& operator+=(_Ty _Right)
  {       // add real
    _Val[_RE] = _Val[_RE] + _Right;
    return *this;
  }

  _Myt& operator-=(_Ty _Right)
  {       // subtract real
    _Val[_RE] = _Val[_RE] - _Right;
    return *this;
  }

  _Myt& operator*=(_Ty _Right)
  {       // multiply by real
    _Val[_RE] = _Val[_RE] * _Right;
    _Val[_IM] = _Val[_IM] * _Right;
    return *this;
  }

  _Myt& operator/=(_Ty _Right)
  {       // divide by real
    _Val[_RE] = _Val[_RE] / _Right;
    _Val[_IM] = _Val[_IM] / _Right;
    return *this;
  }

  template<class _Other> inline
  _Myt& operator=(const complex<_Other>& _Right)
  {       // assign another complex
    _Val[_RE] = (_Ty)_Right._Val[_RE];
    _Val[_IM] = (_Ty)_Right._Val[_IM];
    return *this;
  }

  template<class _Other> inline
  _Myt& operator+=(const complex<_Other>& _Right)
  {       // add other complex
    _Add(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator-=(const complex<_Other>& _Right)
  {       // subtract other complex
    _Sub(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator*=(const complex<_Other>& _Right)
  {       // multiply by other complex
    _Mul(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator/=(const complex<_Other>& _Right)
  {       // divide by other complex
    _Div(_Right);
    return *this;
  }
};

// CONSTRUCTORS FOR complex SPECIALIZATIONS
inline
constexpr complex<float>::complex(const complex<double>& _Right)
  : _Complex_base<float, _Fcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<float> from complex<double>
}

inline
constexpr complex<float>::complex(const complex<long double>& _Right)
  : _Complex_base<float, _Fcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<float> from complex<long double>
}

inline
constexpr complex<double>::complex(const complex<float>& _Right)
  : _Complex_base<double, _Dcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<double> from complex<float>
}

inline
constexpr complex<double>::complex(const complex<long double>& _Right)
  : _Complex_base<double, _Dcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<double> from complex<long double>
}

inline
constexpr complex<long double>::complex(const complex<float>& _Right)
  : _Complex_base<long double, _Lcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<long double> from complex<float>
}

inline
constexpr complex<long double>::complex(const complex<double>& _Right)
  : _Complex_base<long double, _Lcomplex_value>(
    (_Ty)_Right.real(), (_Ty)_Right.imag())
{       // construct complex<long double> from complex<double>
}

// TEMPLATE CLASS complex
template<class _Ty>
class complex
  : public _Complex_base<_Ty, _Complex_value<_Ty> >
{       // complex with _Ty components
public:
  typedef complex<_Ty> _Myt;
  typedef _Complex_base<_Ty, _Complex_value<_Ty> > _Mybase;

  constexpr complex(const _Ty& _Realval = _Ty(), const _Ty& _Imagval = _Ty())
    : _Mybase(&_Realval, &_Imagval) // Call special constructor
  {       // construct from components of same type
  }

  _Myt& operator=(const _Ty& _Right)
  {       // assign real
    this->_Val[_RE] = _Right;
    this->_Val[_IM] = 0;
    return *this;
  }

  template<class _Other>
  constexpr complex(const complex<_Other>& _Right)
    : _Mybase((_Ty)_Right.real(), (_Ty)_Right.imag())
  {       // construct from other complex type
  }

  template<class _Other>
  _Myt& operator=(const complex<_Other>& _Right)
  {       // assign other complex type
    this->_Val[_RE] = (_Ty)_Right.real();
    this->_Val[_IM] = (_Ty)_Right.imag();
    return *this;
  }

  _Myt& operator+=(const _Ty& _Right)
  {       // add real
    this->_Val[_RE] = this->_Val[_RE] + _Right;
    return *this;
  }

  _Myt& operator-=(const _Ty& _Right)
  {       // subtract real
    this->_Val[_RE] = this->_Val[_RE] - _Right;
    return *this;
  }

  _Myt& operator*=(const _Ty& _Right)
  {       // multiply by real
    this->_Val[_RE] = this->_Val[_RE] * _Right;
    this->_Val[_IM] = this->_Val[_IM] * _Right;
    return *this;
  }

  _Myt& operator/=(const _Ty& _Right)
  {       // divide by real
    this->_Val[_RE] = this->_Val[_RE] / _Right;
    this->_Val[_IM] = this->_Val[_IM] / _Right;
    return *this;
  }

  template<class _Other> inline
  _Myt& operator+=(const complex<_Other>& _Right)
  {       // add other complex
    this->_Add(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator-=(const complex<_Other>& _Right)
  {       // subtract other complex
    this->_Sub(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator*=(const complex<_Other>& _Right)
  {       // multiply by other complex
    this->_Mul(_Right);
    return *this;
  }

  template<class _Other> inline
  _Myt& operator/=(const complex<_Other>& _Right)
  {       // divide by other complex
    this->_Div(_Right);
    return *this;
  }
};

#define _CMPLX(T)      complex<T >
#define _CTR(T)        _Ctraits<T >
#define _TMPLT(T)      template<class T >
#include <xcomplex>    /* define all complex template functions */


#if _DLIB_FULL_LOCALE_SUPPORT
  #define _OSTR_GETLOC _Ostr.getloc()
  #define _ISTR_GETLOC _Istr.getloc()
#else
  #define _OSTR_GETLOC
  #define _ISTR_GETLOC
#endif

// TEMPLATE FUNCTION operator>>
template<class _Ty,
         class _Elem,
         class _Tr> inline
basic_istream<_Elem, _Tr>& operator>>(
  basic_istream<_Elem, _Tr>& _Istr, complex<_Ty>& _Right)
{       // extract a complex<_Ty>
  typedef complex<_Ty> _Myt;
  const ctype<_Elem>& _Ctype_fac = use_facet< ctype<_Elem> >(_ISTR_GETLOC);
  _Elem _Ch = 0;
  long double _Real = 0;
  long double _Imag = 0;

  if (_Istr >> _Ch && _Ch != _Ctype_fac.widen('('))
  {       // no leading '(', treat as real only
    _Istr.putback(_Ch);
    _Istr >> _Real;
    _Imag = 0;
  }
  else if (_Istr >> _Real >> _Ch && _Ch != _Ctype_fac.widen(','))
    if (_Ch == _Ctype_fac.widen(')'))
      _Imag = 0;      // (real)
    else
    {       // no trailing ')' after real, treat as bad field
      _Istr.putback(_Ch);
      _Istr.setstate(ios_base::failbit);
    }
  else if (_Istr >> _Imag >> _Ch && _Ch != _Ctype_fac.widen(')'))
  {       // no imag or trailing ')', treat as bad field
    _Istr.putback(_Ch);
    _Istr.setstate(ios_base::failbit);
  }

  if (!_Istr.fail())
  {       // store valid result
    _Ty _Tyreal((_Ty)_Real), _Tyimag((_Ty)_Imag);
    _Right = _Myt(_Tyreal, _Tyimag);
  }
  return _Istr;
}

// TEMPLATE FUNCTION operator<<
template<class _Ty,
         class _Elem,
         class _Tr> inline
basic_ostream<_Elem, _Tr>& operator<<(
  basic_ostream<_Elem, _Tr>& _Ostr, const complex<_Ty>& _Right)
{       // insert a complex<_Ty>
  const ctype<_Elem>& _Ctype_fac = use_facet< ctype<_Elem> >(_OSTR_GETLOC);
  basic_ostringstream<_Elem, _Tr, allocator<_Elem> > _Sstr;

  _Sstr.flags(_Ostr.flags());
  #if _DLIB_FULL_LOCALE_SUPPORT
    _Sstr.imbue(_Ostr.getloc());
  #endif
  _Sstr.precision(_Ostr.precision());
  _Sstr << _Ctype_fac.widen('(') << real(_Right)
        << _Ctype_fac.widen(',') << imag(_Right)
        << _Ctype_fac.widen(')');

  basic_string<_Elem, _Tr, allocator<_Elem> > _Str = _Sstr.str();
  return _Ostr << _Str.c_str();
}

#undef _OSTR_GETLOC
#undef _ISTR_GETLOC

} /* namespace std */

// TEMPLATE CLASS _Rc_type (ADDITIONS TO <math.h>)
template<class _Ty>
struct _Rc_type;

template<> struct _Rc_type< std::complex<float> >
{       // determine if type is real or complex
  typedef char _Type;
};

template<> struct _Rc_type<std::complex<double> >
{       // determine if type is real or complex
  typedef char _Type;
};

template<> struct _Rc_type<std::complex<long double> >
{       // determine if type is real or complex
  typedef char _Type;
};

// TEMPLATE CLASS _Real_type (ADDITIONS TO <math.h>)
template<class _Ty>
struct _Real_type;

template<> struct _Real_type<std::complex<float> >
{       // determine equivalent real type
  typedef float _Type;
};

template<> struct _Real_type<std::complex<double> >
{       // determine equivalent real type
  typedef double _Type;
};

template<> struct _Real_type<std::complex<long double> >
{       // determine equivalent real type
  typedef long double _Type;
};

namespace std {

// complex LITERALS
inline namespace literals {
inline namespace complex_literals {

constexpr complex<long double> operator""il(long double _Val)
{	// return imaginary _Val
  return complex<long double>(0.0L, static_cast<long double>(_Val));
}

constexpr complex<long double> operator""il(unsigned long long _Val)
{	// return imaginary _Val
  return complex<long double>(0.0L, static_cast<long double>(_Val));
}

constexpr complex<double> operator""i(long double _Val)
{	// return imaginary _Val
  return complex<double>(0.0, static_cast<double>(_Val));
}

constexpr complex<double> operator""i(unsigned long long _Val)
{	// return imaginary _Val
  return complex<double>(0.0, static_cast<double>(_Val));
}

constexpr complex<float> operator""if(long double _Val)
{	// return imaginary _Val
  return complex<float>(0.0f, static_cast<float>(_Val));
}

constexpr complex<float> operator""if(unsigned long long _Val)
{	// return imaginary _Val
  return (complex<float>(0.0f, static_cast<float>(_Val)));
}

} // inline namespace complex_literals
} // inline namespace literals

} // namespace std

using namespace std::literals::complex_literals;

#endif /* _COMPLEX_ */


/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
