#include #include #include #include "blis.h" template struct is_complex : std::false_type {}; template <> struct is_complex : std::true_type {}; template <> struct is_complex : std::true_type {}; template struct is_real : std::integral_constant::value> {}; template struct make_complex; template <> struct make_complex { using type = scomplex; }; template <> struct make_complex { using type = dcomplex; }; template <> struct make_complex { using type = scomplex; }; template <> struct make_complex { using type = dcomplex; }; template using make_complex_t = typename make_complex::type; template struct make_real; template <> struct make_real { using type = float; }; template <> struct make_real { using type = double; }; template <> struct make_real { using type = float; }; template <> struct make_real { using type = double; }; template using make_real_t = typename make_real::type; template struct make_complex_if : std::conditional,make_real_t> {}; template using make_complex_if_t = typename make_complex_if::type; template struct real_imag_part { real_imag_part& operator=(T) { return *this; } operator T() const { return T(); } }; template std::enable_if_t::type>::value,T&> real(T& x) { return x; } template std::enable_if_t::value,real_imag_part> imag(T x) { return {}; } inline float& real(scomplex& x) { return x.real; } inline float& imag(scomplex& x) { return x.imag; } inline double& real(dcomplex& x) { return x.real; } inline double& imag(dcomplex& x) { return x.imag; } inline const float& real(const scomplex& x) { return x.real; } inline const float& imag(const scomplex& x) { return x.imag; } inline const double& real(const dcomplex& x) { return x.real; } inline const double& imag(const dcomplex& x) { return x.imag; } template std::enable_if_t::value,T> conj(T x) { return x; } template std::enable_if_t::value,T> conj(const T& x) { return {x.real, -x.imag}; } template struct convert_impl; template struct convert_impl::value && is_real::value>> { void operator()(T x, U& y) const { y = x; } }; template struct convert_impl::value && is_complex::value>> { void operator()(T x, U& y) const { y.real = x; y.imag = 0; } }; template struct convert_impl::value && is_real::value>> { void operator()(T x, U& y) const { y = x.real; } }; template struct convert_impl::value && is_complex::value>> { void operator()(T x, U& y) const { y.real = x.real; y.imag = x.imag; } }; template U convert(T x) { U y; convert_impl{}(x,y); return y; } template auto convert_prec(T x) -> make_complex_if_t::value> { return convert::value>>(x); } #define COMPLEX_MATH_OPS(rtype, ctype) \ \ inline bool operator==(rtype x, ctype y) \ { \ return x == y.real && y.imag == 0; \ } \ \ inline bool operator==(ctype x, rtype y) \ { \ return y == x.real && x.imag == 0; \ } \ \ inline bool operator==(ctype x, ctype y) \ { \ return x.real == y.real && \ x.imag == y.imag; \ } \ \ inline ctype operator-(ctype x) \ { \ return {-x.real, -x.imag}; \ } \ \ inline ctype operator+(rtype x, ctype y) \ { \ return {x+y.real, y.imag}; \ } \ \ inline ctype operator+(ctype x, rtype y) \ { \ return {y+x.real, x.imag}; \ } \ \ inline ctype operator+(ctype x, ctype y) \ { \ return {x.real+y.real, x.imag+y.imag}; \ } \ \ inline ctype operator-(rtype x, ctype y) \ { \ return {x-y.real, -y.imag}; \ } \ \ inline ctype operator-(ctype x, rtype y) \ { \ return {x.real-y, x.imag}; \ } \ \ inline ctype operator-(ctype x, ctype y) \ { \ return {x.real-y.real, x.imag-y.imag}; \ } \ \ inline ctype operator*(rtype x, ctype y) \ { \ return {x*y.real, x*y.imag}; \ } \ \ inline ctype operator*(ctype x, rtype y) \ { \ return {y*x.real, y*x.imag}; \ } \ \ inline ctype operator*(ctype x, ctype y) \ { \ return {x.real*y.real - x.imag*y.imag, \ x.real*y.imag + x.imag*y.real}; \ } \ \ inline ctype operator/(rtype x, ctype y) \ { \ auto scale = std::max(std::abs(y.real), std::abs(y.imag)); \ auto n = std::ilogb(scale); \ auto yrs = std::scalbn(y.real, -n); \ auto yis = std::scalbn(y.imag, -n); \ auto denom = y.real*yrs + y.imag*yis; \ return {x*yrs/denom, -x*yis/denom}; \ } \ \ inline ctype operator/(ctype x, rtype y) \ { \ return {x.real/y, x.imag/y}; \ } \ \ inline ctype operator/(ctype x, ctype y) \ { \ auto scale = std::max(std::abs(y.real), std::abs(y.imag)); \ auto n = std::ilogb(scale); \ auto yrs = std::scalbn(y.real, -n); \ auto yis = std::scalbn(y.imag, -n); \ auto denom = y.real*yrs + y.imag*yis; \ return {(x.real*yrs + x.imag*yis)/denom, \ (x.imag*yrs - x.real*yis)/denom}; \ } \ \ inline ctype& operator+=(ctype& x, rtype y) \ { \ x.real += y; \ return x; \ } \ \ inline ctype& operator+=(ctype& x, ctype y) \ { \ x.real += y.real; x.imag += y.imag; \ return x; \ } \ \ inline ctype& operator-=(ctype& x, rtype y) \ { \ x.real -= y; \ return x; \ } \ \ inline ctype& operator-=(ctype& x, ctype y) \ { \ x.real -= y.real; x.imag -= y.imag; \ return x; \ } \ \ inline ctype& operator*=(ctype& x, rtype y) \ { \ x.real *= y; x.imag *= y; \ return x; \ } \ \ inline ctype& operator*=(ctype& x, ctype y) \ { \ x = x * y; \ return x; \ } \ \ inline ctype& operator/=(ctype& x, rtype y) \ { \ x.real /= y; x.imag /= y; \ return x; \ } \ \ inline ctype& operator/=(ctype& x, ctype y) \ { \ x = x / y; \ return x; \ } COMPLEX_MATH_OPS(float, scomplex); COMPLEX_MATH_OPS(double, dcomplex);