/*RTS Complex number class. This class is CUDA compatible, and can therefore be used in CUDA code and on CUDA devices. */ #ifndef RTS_COMPLEX #define RTS_COMPLEX #include "cuda_callable.h" #include #include #include #include namespace rts { template struct rtcomplex { T r, i; //default constructor CUDA_CALLABLE rtcomplex() { r = 0.0; i = 0.0; } //access methods T real() { return r; } T real(T r_val) { r = r_val; return r_val; } T imag() { return i; } T imag(T i_val) { i = i_val; return i_val; } //constructor when given real and imaginary values CUDA_CALLABLE rtcomplex(T r, T i) { this->r = r; this->i = i; } //return the current value multiplied by i CUDA_CALLABLE rtcomplex imul() { rtcomplex result; result.r = -i; result.i = r; return result; } //ARITHMETIC OPERATORS-------------------- //binary + operator (returns the result of adding two complex values) CUDA_CALLABLE rtcomplex operator+ (const rtcomplex rhs) { rtcomplex result; result.r = r + rhs.r; result.i = i + rhs.i; return result; } CUDA_CALLABLE rtcomplex operator+ (const T rhs) { rtcomplex result; result.r = r + rhs; result.i = i; return result; } //binary - operator (returns the result of adding two complex values) CUDA_CALLABLE rtcomplex operator- (const rtcomplex rhs) { rtcomplex result; result.r = r - rhs.r; result.i = i - rhs.i; return result; } //binary - operator (returns the result of adding two complex values) CUDA_CALLABLE rtcomplex operator- (const T rhs) { rtcomplex result; result.r = r - rhs; result.i = i; return result; } //binary MULTIPLICATION operators (returns the result of multiplying complex values) CUDA_CALLABLE rtcomplex operator* (const rtcomplex rhs) { rtcomplex result; result.r = r * rhs.r - i * rhs.i; result.i = r * rhs.i + i * rhs.r; return result; } CUDA_CALLABLE rtcomplex operator* (const T rhs) { return rtcomplex(r * rhs, i * rhs); } //binary DIVISION operators (returns the result of dividing complex values) CUDA_CALLABLE rtcomplex operator/ (const rtcomplex rhs) { rtcomplex result; T denom = rhs.r * rhs.r + rhs.i * rhs.i; result.r = (r * rhs.r + i * rhs.i) / denom; result.i = (- r * rhs.i + i * rhs.r) / denom; return result; } CUDA_CALLABLE rtcomplex operator/ (const T rhs) { return rtcomplex(r / rhs, i / rhs); } //ASSIGNMENT operators----------------------------------- CUDA_CALLABLE rtcomplex & operator=(const rtcomplex &rhs) { //check for self-assignment if(this != &rhs) { this->r = rhs.r; this->i = rhs.i; } return *this; } CUDA_CALLABLE rtcomplex & operator=(const T &rhs) { this->r = rhs; this->i = 0; return *this; } //arithmetic assignment operators CUDA_CALLABLE rtcomplex operator+=(const rtcomplex &rhs) { *this = *this + rhs; return *this; } CUDA_CALLABLE rtcomplex operator+=(const T &rhs) { *this = *this + rhs; return *this; } CUDA_CALLABLE rtcomplex operator*=(const rtcomplex &rhs) { *this = *this * rhs; return *this; } CUDA_CALLABLE rtcomplex operator*=(const T &rhs) { *this = *this * rhs; return *this; } //divide and assign CUDA_CALLABLE rtcomplex operator/=(const rtcomplex &rhs) { *this = *this / rhs; return *this; } CUDA_CALLABLE rtcomplex operator/=(const T &rhs) { *this = *this / rhs; return *this; } //absolute value operator (returns the absolute value of the complex number) CUDA_CALLABLE T abs() { return std::sqrt(r * r + i * i); } CUDA_CALLABLE rtcomplex log() { rtcomplex result; result.r = std::log(std::sqrt(r * r + i * i)); result.i = std::atan2(i, r); return result; } CUDA_CALLABLE rtcomplex exp() { rtcomplex result; T e_r = std::exp(r); result.r = e_r * std::cos(i); result.i = e_r * std::sin(i); return result; } /*CUDA_CALLABLE complex pow(int y) { return pow((double)y); }*/ CUDA_CALLABLE rtcomplex pow(T y) { rtcomplex result; result = log() * y; return result.exp(); } CUDA_CALLABLE rtcomplex sqrt() { rtcomplex result; //convert to polar coordinates T a = std::sqrt(r*r + i*i); T theta = std::atan2(i, r); //find the square root T a_p = std::sqrt(a); T theta_p = theta/2.0; //convert back to cartesian coordinates result.r = a_p * std::cos(theta_p); result.i = a_p * std::sin(theta_p); return result; } std::string toStr() { std::stringstream ss; ss<<"("< rhs) { if(r == rhs.r && i == rhs.i) return true; return false; } CUDA_CALLABLE bool operator==(T rhs) { if(r == rhs && i == (T)0.0) return true; return false; } /*//FRIEND functions //unary minus operator (for negating the complex number) template CUDA_CALLABLE friend complex operator-(const complex &rhs); //multiplication by T values when the complex number isn't on the left hand side template CUDA_CALLABLE friend complex operator*(const A a, const complex b); //division by T values when the complex number isn't on the left hand side template CUDA_CALLABLE friend complex operator/(const A a, const complex b); //POW function //template CUDA_CALLABLE friend complex pow(const complex x, T y); template CUDA_CALLABLE friend complex pow(const complex x, int y); //log function template CUDA_CALLABLE friend complex log(complex x); //exp function template CUDA_CALLABLE friend complex exp(complex x); //sqrt function template CUDA_CALLABLE friend complex sqrt(complex x); //trigonometric functions template CUDA_CALLABLE friend complex sin(complex x); template CUDA_CALLABLE friend complex cos(complex x);*/ }; //addition template CUDA_CALLABLE static rtcomplex operator+(const double a, const rtcomplex b) { return rtcomplex(a + b.r, b.i); } //subtraction with a real value template CUDA_CALLABLE static rtcomplex operator-(const double a, const rtcomplex b) { return rtcomplex(a - b.r, -b.i); } //minus sign template CUDA_CALLABLE static rtcomplex operator-(const rtcomplex &rhs) { return rtcomplex(-rhs.r, -rhs.i); } //multiply a T value by a complex value template CUDA_CALLABLE static rtcomplex operator*(const double a, const rtcomplex b) { return rtcomplex(a * b.r, a * b.i); } //divide a T value by a complex value template CUDA_CALLABLE static rtcomplex operator/(const double a, const rtcomplex b) { //return complex(a * b.r, a * b.i); rtcomplex result; T denom = b.r * b.r + b.i * b.i; result.r = (a * b.r) / denom; result.i = -(a * b.i) / denom; return result; } //POW function /*template CUDA_CALLABLE static complex pow(complex x, int y) { return x.pow(y); }*/ template CUDA_CALLABLE static rtcomplex pow(rtcomplex x, T y) { return x.pow(y); } //log function template CUDA_CALLABLE static rtcomplex log(rtcomplex x) { return x.log(); } //exp function template CUDA_CALLABLE static rtcomplex exp(rtcomplex x) { return x.exp(); } //sqrt function template CUDA_CALLABLE static rtcomplex sqrt(rtcomplex x) { return x.sqrt(); } template CUDA_CALLABLE static T abs(rtcomplex a) { return a.abs(); } template CUDA_CALLABLE static T real(rtcomplex a) { return a.r; } template CUDA_CALLABLE static T imag(rtcomplex a) { return a.i; } //trigonometric functions template CUDA_CALLABLE rtcomplex sin(const rtcomplex x) { rtcomplex result; result.r = std::sin(x.r) * std::cosh(x.i); result.i = std::cos(x.r) * std::sinh(x.i); return result; } template CUDA_CALLABLE rtcomplex cos(const rtcomplex x) { rtcomplex result; result.r = std::cos(x.r) * std::cosh(x.i); result.i = -(std::sin(x.r) * std::sinh(x.i)); return result; } } //end RTS namespace template std::ostream& operator<<(std::ostream& os, rts::rtcomplex x) { os<