/** -*- C++ -*- ** ** KAI C++ Compiler ** ** Copyright (C) 1997-2001 Intel Corp. All rights reserved. ** Modena's code has been rewritten in places to improve speed and/or ** get correct answers. Do not update with Modena's code. **/ /** ** Lib++ : The Modena C++ Standard Library, ** Version 2.4, October 1997 ** ** Copyright (c) 1995-1997 Modena Software Inc. **/ #ifndef MSIPL_COMPLEX_H #define MSIPL_COMPLEX_H #include #include #include #include namespace std { // [26.2] Complex numbers: template class complex; template<> class complex; template<> class complex; template<> class complex; } namespace __kai { template struct extend_precision {typedef T type;}; // Specialize if there is a type with exponent range 2x wider than for T. template<> struct extend_precision {typedef double type;}; #ifdef __i386 // x86 architecture supports fast long double. template<> struct extend_precision {typedef long double type;}; #endif /* __i386 */ template inline void do_divide( std::complex& z, L c, L d, R a, R b ); } namespace std { template class complex { private: T re; T im; public: typedef T value_type; complex(const T& r = T(), const T& i = T()) : re(r), im(i) {} T real() const { return re; } T imag() const { return im; } complex & operator=(const T& rhs) { re = rhs; im = T(); return *this; } complex & operator+=(const T& rhs) { re += rhs; return *this; } complex & operator-=(const T& rhs) { re -= rhs; return *this; } complex & operator*=(const T& rhs) { re *= rhs; im *= rhs; return *this; } complex & operator/=(const T& rhs) { re /= rhs; im /= rhs; return *this; } complex& operator=(const complex& cx) { re = cx.re; im = cx.im; return *this; } template complex& operator=(const complex& cx) { re = cx.real(); im = cx.imag(); return *this; } template complex& operator+=(const complex& cx) { re += cx.real(); im += cx.imag(); return *this; } template complex& operator-=(const complex& cx) { re -= cx.real(); im -= cx.imag(); return *this; } template complex& operator*=(const complex& cx) { T ret = re*cx.real() - im*cx.imag(); im = re*cx.imag() + im*cx.real(); re = ret; return *this; } template complex& operator/=(const complex& cx) { #if KAI_COMPLEX_EXTRA_CHECKS if (! (cx.real() || cx.imag())) domain_error::__throw("Division by zero error"); #endif T a = cx.real(); T b = cx.imag(); T value = a*a + b*b; T r = (re*a + im*b)/value; im = (im*a - re*b)/value; re = r; return *this; } }; template<> class complex { private : float re; float im; public : typedef float value_type; complex(float r = 0.0f, float i = 0.0f) : re(r), im(i) {} explicit inline complex(const complex& cx); explicit inline complex(const complex& cx); float real() const { return re; } float imag() const { return im; } complex& operator=(float rhs) { re = rhs; im = 0.0; return *this; } complex& operator+=(float rhs) { re += rhs; return *this; } complex& operator-=(float rhs) { re -= rhs; return *this; } complex& operator*=(float rhs) { re *= rhs; im *= rhs; return *this; } complex& operator/=(float rhs) { re /= rhs; im /= rhs; return *this; } inline complex& operator=(const complex& cx) { re = cx.re; im = cx.im; return *this; } template inline complex& operator=(const complex& cx) { re = cx.real(); im = cx.imag(); return *this; } template inline complex& operator+=(const complex& cx) { re += cx.real(); im += cx.imag(); return *this; } template inline complex& operator-=(const complex& cx) { re -= cx.real(); im -= cx.imag(); return *this; } template inline complex& operator*=(const complex& cx) { float ret = re*cx.real() - im*cx.imag(); im = re*cx.imag() + im*cx.real(); re = ret; return *this; } template inline complex& operator/=(const complex& cx) { __kai::do_divide( *this, re, im, cx.real(), cx.imag() ); return *this; } }; template<> class complex { private : double re; double im; public : typedef double value_type; complex(double r = 0.0, double i = 0.0) : re(r), im(i) {} complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} explicit inline complex(const complex& cx); double real() const { return re; } double imag() const { return im; } complex& operator=(double rhs) { re = rhs; im = 0.0; return *this; } complex& operator+=(double rhs) { re += rhs; return *this; } complex& operator-=(double rhs) { re -= rhs; return *this; } complex& operator*=(double rhs) { re *= rhs; im *= rhs; return *this; } complex& operator/=(double rhs) { re /= rhs; im /= rhs; return *this; } complex& operator=(const complex& cx) { re = cx.real(); im = cx.imag(); return *this; } template inline complex& operator=(const complex& cx) { re = cx.real(); im = cx.imag(); return *this; } template inline complex& operator+=(const complex& cx) { re += cx.real(); im += cx.imag(); return *this; } template inline complex& operator-=(const complex& cx) { re -= cx.real(); im -= cx.imag(); return *this; } template inline complex& operator*=(const complex& cx) { double re_t = re*cx.real() - im*cx.imag(); im = re*cx.imag() + im*cx.real(); re = re_t; return *this; } template inline complex& operator/=(const complex& cx) { __kai::do_divide( *this, re, im, cx.real(), cx.imag() ); return *this; } }; template<> class complex { private : long double re; long double im; public : typedef long double value_type; complex(long double r = 0.0l, long double i = 0.0l) : re(r), im(i) {} complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} long double real() const { return re; } long double imag() const { return im; } complex& operator=(long double rhs) { re = rhs; im = 0.0; return *this; } complex& operator+=(long double rhs) { re += rhs; return *this; } complex& operator-=(long double rhs) { re -= rhs; return *this; } complex& operator*=(long double rhs) { re *= rhs; im *= rhs; return *this; } complex& operator/=(long double rhs) { re /= rhs; im /= rhs; return *this; } complex& operator=(const complex& cx) { re = cx.re; im = cx.im; return *this; } template inline complex& operator=(const complex& cx) { re = cx.real(); im = cx.imag(); return *this; } template inline complex& operator+=(const complex& cx) { re += cx.real(); im += cx.imag(); return *this; } template inline complex& operator-=(const complex& cx) { re -= cx.real(); im -= cx.imag(); return *this; } template inline complex& operator*=(const complex& cx) { long double re_t = re*cx.real() - im*cx.imag(); im = re*cx.imag() + im*cx.real(); re = re_t; return *this; } template inline complex& operator/=(const complex& cx) { __kai::do_divide( *this, re, im, cx.real(), cx.imag() ); return *this; } }; // Because of the ordering of the class declarations, these must be done here. complex::complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} complex::complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} complex::complex(const complex& cx) : re(cx.real()), im(cx.imag()) {} // [26.2.6] operators: template inline complex operator+(const complex& c1, const complex& c2) { return complex(c1.real()+c2.real(), c1.imag()+c2.imag()); } template inline complex operator+(const T& re, const complex& cx) { return complex(re+cx.real(), cx.imag()); } template inline complex operator+(const complex& cx, const T& re) { return complex(re+cx.real(), cx.imag()); } template inline complex operator-(const complex& c1, const complex& c2) { return complex(c1.real()-c2.real(), c1.imag()-c2.imag()); } template inline complex operator-(const T& re, const complex& cx) { return complex(re-cx.real(), -cx.imag()); } template inline complex operator-(const complex& cx, const T& re) { return complex(cx.real()-re, cx.imag()); } template inline complex operator*(const complex& c1, const complex& c2) { return complex((c1.real()*c2.real()-c1.imag()*c2.imag()), (c1.real()*c2.imag()+c2.real()*c1.imag())); } template inline complex operator*(const T& re, const complex& cx) { return complex(re*cx.real(), re*cx.imag()); } template inline complex operator*(const complex& cx, const T& re) { return complex(re*cx.real(), re*cx.imag()); } template inline complex operator/(const complex& c1, const complex& c2) { complex result; __kai::do_divide( result, c1.real(), c1.imag(), c2.real(), c2.imag() ); return result; } template inline complex operator/(const T& z, const complex& y) { #if KAI_COMPLEX_EXTRA_CHECKS if (! (cx.real() || cx.imag())) { domain_error::__throw("Division by zero error"); } #endif typedef __kai::extend_precision::type S; S re, im; S a = y.real(); S b = y.imag(); S c = (S)z; if( sizeof(S)>sizeof(T) ) { // Need not worry about exponent overflow/underflow. S value = 1/(a*a+b*b); re = (c*a)*value; im = (-c*b)*value; } else { // Worry about exponent overflow/underflow. S s; if( std::abs(a)>=std::abs(b) ) { S q = b/a; s = a + q*b; re = c; im = -c*q; } else { S r = a/b; s = b + a*r; re = c*r; im = -c; } re /= s; im /= s; } return complex(re,im); } template inline complex operator/(const complex& cx, const T& re) { #if KAI_COMPLEX_EXTRA_CHECKS if (!re) { domain_error::__throw("Division by zero error"); } #endif return complex(cx.real()/re, cx.imag()/re); } template inline complex operator+(const complex& cx) { return complex(cx.real(), cx.imag()); } template inline complex operator-(const complex& cx) { return complex(-cx.real(), -cx.imag()); } template inline bool operator==(const complex& c1, const complex& c2) { return ((c1.real() == c2.real()) && (c1.imag() == c2.imag())); } template inline bool operator==(const T& re, const complex& cx) { return ((re == cx.real()) && (!cx.imag())); } template inline bool operator==(const complex& cx, const T& re) { return ((re == cx.real()) && (!cx.imag())); } template inline bool operator!=(const complex& c1, const complex& c2) { return ((c1.real() != c2.real()) || (c1.imag() != c2.imag())); } template inline bool operator!=(const T& re, const complex& cx) { return ((re != cx.real()) || (cx.imag())); } template inline bool operator!=(const complex& cx, const T& re) { return ((re != cx.real()) || (cx.imag())); } template basic_istream& operator>>(basic_istream& is, complex& cx) { T re_t = 0; T imt = 0; char ch; is >> ch; if (!is.fail() && ch == '(') { // if '(' : one of(re), (re, im) is >> re_t >> ch; if (!is.fail() && ch == ',') is >> imt >> ch; if (!is.fail() && ch != ')') { // no ')' : error is.setstate(ios_base::failbit); return is; } } else if (!is.fail()) { // no '(' in the beginning: "re" is.putback(ch); is >> re_t; } // check "is" is in good state if (!is.fail()) cx = complex(re_t, imt); return is; } template basic_ostream& operator<<(basic_ostream& os, const complex& cx) { // We perform the output to a stringstream so the width setting of the ostream is obeyed. basic_ostringstream s; s.flags(os.flags()); s.imbue(os.getloc()); s.precision(os.precision()); s << '(' << cx.real() << "," << cx.imag() << ')'; return os << s.str(); } // [26.2.7] values: template inline T real(const complex& x) { return x.real(); } template inline T imag(const complex& x) { return x.imag(); } template inline T abs(const complex& cx) { typedef __kai::extend_precision::type S; S a = cx.real(); S b = cx.imag(); return std::sqrt(a*a+b*b); } template inline T arg(const complex& cx) { #if KAI_COMPLEX_EXTRA_CHECKS if (! (cx.real() || cx.imag())) domain_error::__throw("arg(complex &): both real and imag are zero"); #endif return std::atan2(cx.imag(), cx.real()); } template inline T norm(const complex& cx) { return ( cx.real() * cx.real() + cx.imag() * cx.imag() ); } template inline complex conj(const complex& cx) { return complex(cx.real(), -cx.imag()); } template inline complex polar(const T& r, const T& arg) { return complex(r*std::cos(arg), r*std::sin(arg)); } #if KAI_NONSTD_COMPLEX // Function inv was in previous releases of KCC. // It is not part of Cfront nor ANSI drafts since April 1995. // It is expected that it will disappear in some future release. template inline complex inv(const complex& cx) { T value = (T)1/norm(cx); return complex(cx.real()*value, -cx.imag()*value); } #endif /* KAI_NONSTD_COMPLEX */ // [26.2.8] transcendentals: template inline complex cos(const complex& cx) { return complex( std::cos(cx.real())*std::cosh(cx.imag()), -std::sin(cx.real())*std::sinh(cx.imag())); } template inline complex cosh(const complex& cx) { return complex( std::cos(cx.imag())*std::cosh(cx.real()), std::sin(cx.imag())*std::sinh(cx.real())); } template inline complex exp(const complex& cx) { T value = std::exp(cx.real()); return complex(value*std::cos(cx.imag()), value*std::sin(cx.imag())); } template inline complex log(const complex& cx) { return complex(std::log(abs(cx)), arg(cx)); } template inline complex log10(const complex& cx) { return complex(log(cx)/std::log(10.0)); } template inline complex pow(const complex& cb, const complex& ce) { return exp(ce*log(cb)); } template inline complex pow(const complex& cx, const T& re) { return polar(std::pow(abs(cx), re), re*arg(cx)); } template inline complex pow(const T& re, const complex& cx) { return exp(cx*((T)log(re))); } template inline complex pow(const complex& cx, int i) { return polar(std::pow(abs(cx), i), i*arg(cx)); } template inline complex sin(const complex& cx) { return complex( std::sin(cx.real())*std::cosh(cx.imag()), std::cos(cx.real())*std::sinh(cx.imag())); } template inline complex sinh(const complex& cx) { return complex( std::cos(cx.imag())*std::sinh(cx.real()), std::sin(cx.imag())*std::cosh(cx.real())); } template inline complex sqrt(const complex& cx) { typedef __kai::extend_precision::type S; S re, im; S a = std::abs(cx.real()); S b = std::abs(cx.imag()); if ( b==0 ) { re = std::sqrt( a ); im = 0; } else { S u; if( sizeof(S)>sizeof(T) ) { // No need for scaling - avoid extra branch and divisions. u = std::sqrt((a + std::sqrt( a*a+b*b ))*(S)2); } else { // Exponent underflow/overflow a problem. S p, q, r; if( a>=b ) { // Real part is greater. p = b/a; q = 1; r = a; } else { // Imaginary part is greater. p = a/b; q = p; r = b; } u = std::sqrt((q + std::sqrt( 1+p*p ))*(S)2*r); } im = cx.imag()/u; re = (S)0.5*u; } if ( cx.real()<0 ) { T temp; if ( cx.imag()>=0 ) { temp=re; re=im; } else { temp=-re; re=-im; } im = temp; } return complex(re,im); } template inline complex tan(const complex& cx) { T value = std::cos(2*cx.real()) + std::cosh(2*cx.imag()); if (value) return complex(std::sin(2*cx.real())/value, std::sinh(2*cx.imag())/value); else return complex(std::tan(cx.real()), 0); } template inline complex tanh(const complex& cx) { T value = std::cos(2*cx.imag()) + std::cosh(2*cx.real()); if (value) return complex(std::sinh(2*cx.real())/value, std::sin(2*cx.imag())/value); else return complex(0, std::tan(cx.real())); } } // namespace std namespace __kai { template inline void do_divide( std::complex& z, L c, L d, R a, R b ) { #if KAI_COMPLEX_EXTRA_CHECKS if (! (c2.real() || c2.imag())) { domain_error::__throw("Division by zero error"); } #endif /* KAI_COMPLEX_EXTRA_CHECKS */ typedef __kai::extend_precision::type EL; typedef __kai::extend_precision::type ER; L re, im; if( sizeof(ER)>sizeof(R) ) { // Need not worry about exponent overflow/underflow. ER x = (ER)a; ER y = (ER)b; ER value = 1/(x*x+y*y); re = (c*x+d*y)*value; im = (d*x-c*y)*value; } else if( sizeof(EL)>sizeof(L) ) { // Need not worry about exponent overflow/underflow, because in those cases the // result does not fit anyway. EL x = (EL)a; EL y = (EL)b; EL value = 1/(x*x+y*y); re = (c*x+d*y)*value; im = (d*x-c*y)*value; } else { // Worry about exponent overflow/underflow. R s; if( std::abs(a)>=std::abs(b) ) { R q = b/a; s = a + q*b; re = c + d*q; im = d - c*q; } else { R r = a/b; s = b + a*r; re = c*r + d; im = d*r - c; } re /= s; im /= s; } z = std::complex(re,im); } } // namespace __kai #endif /* MSIPL_COMPLEX_H */