#ifndef SPROUT_COMPLEX_HPP #define SPROUT_COMPLEX_HPP #include #include namespace sprout { namespace detail { template SPROUT_CONSTEXPR T pi_div_two() { return 1.5707963267948966192313216916397514L; } } // namespace detail template class complex; template SPROUT_CONSTEXPR T norm(sprout::complex const& x); // // complex // template class complex { public: typedef T value_type; private: T re_; T im_; public: SPROUT_CONSTEXPR complex(T const& re = T(), T const& im = T()) : re_(re) , im_(im) {} SPROUT_CONSTEXPR complex(complex const&) = default; template SPROUT_CONSTEXPR complex(complex const& other) : re_(other.real()) , im_(other.imag()) {} SPROUT_CONSTEXPR T real() const { return re_; } void real(T re) { re_ = re; } SPROUT_CONSTEXPR T imag() const{ return im_; } void imag(T im) { im_ = im; } complex& operator=(T const& rhs) { re_ = rhs; im_ = T(); return *this; } complex& operator+=(T const& rhs) { re_ += rhs; return *this; } complex& operator-=(T const& rhs) { re_ -= rhs; return *this; } complex& operator*=(T const& rhs) { re_ *= rhs; im_ *= rhs; return *this; } complex& operator/=(T const& rhs) { re_ /= rhs; im_ /= rhs; return *this; } complex& operator=(complex const&) = default; template complex& operator=(complex const& rhs) { re_ = rhs.real(); im_ = rhs.imag(); return *this; } template complex& operator+=(complex const& rhs) { re_ += rhs.real(); im_ += rhs.imag(); return *this; } template complex& operator-=(complex const& rhs) { re_ -= rhs.real(); im_ -= rhs.imag(); return *this; } template complex& operator*=(complex const& rhs) { return *this = complex( re_ * rhs.real() - im_ * rhs.imag(), re_ * rhs.imag() + im_ * rhs.imag() ); } template complex& operator/=(complex const& rhs) { T n = sprout::norm(rhs); return *this = complex( (re_ * rhs.real() + im_ * rhs.imag()) / n, (im_ * rhs.real() - re_ * rhs.imag()) / n ); } }; // 26.4.6, operators: template SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs.real() + rhs.real(), lhs.imag() + rhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& lhs, T const& rhs) { return sprout::complex( lhs.real() + rhs, lhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator+(T const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs + rhs.real(), rhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs.real() - rhs.real(), lhs.imag() - rhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& lhs, T const& rhs) { return sprout::complex( lhs.real() - rhs, lhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator-(T const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs - rhs.real(), -rhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs.real() * rhs.real() - lhs.imag() * rhs.imag(), lhs.real() * rhs.imag() + lhs.imag() * rhs.imag() ); } template SPROUT_CONSTEXPR sprout::complex operator*(sprout::complex const& lhs, T const& rhs) { return sprout::complex( lhs.real() * rhs, lhs.imag() * rhs ); } template SPROUT_CONSTEXPR sprout::complex operator*(T const& lhs, sprout::complex const& rhs) { return sprout::complex( lhs * rhs.real(), lhs * rhs.imag() ); } namespace detail { template SPROUT_CONSTEXPR sprout::complex divides_impl( sprout::complex const& lhs, sprout::complex const& rhs, T const& n ) { return sprout::complex( (lhs.real() * rhs.real() + lhs.imag() * rhs.imag()) / n, (lhs.imag() * rhs.real() - lhs.real() * rhs.imag()) / n ); } template SPROUT_CONSTEXPR sprout::complex divides_impl( T const& lhs, sprout::complex const& rhs, T const& n ) { return sprout::complex( lhs * rhs.real() / n, -lhs * rhs.imag() / n ); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, sprout::complex const& rhs) { return sprout::detail::divides_impl(lhs, rhs, sprout::norm(rhs)); } template SPROUT_CONSTEXPR sprout::complex operator/(sprout::complex const& lhs, T const& rhs) { return sprout::complex( lhs.real() / rhs, lhs.imag() / rhs ); } template SPROUT_CONSTEXPR sprout::complex operator/(T const& lhs, sprout::complex const& rhs) { return sprout::detail::divides_impl(lhs, rhs, sprout::norm(rhs)); } template SPROUT_CONSTEXPR sprout::complex operator+(sprout::complex const& x) { return x; } template SPROUT_CONSTEXPR sprout::complex operator-(sprout::complex const& x) { return sprout::complex(-x.real(), -x.imag()); } template SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, sprout::complex const& rhs) { return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); } template SPROUT_CONSTEXPR bool operator==(sprout::complex const& lhs, T const& rhs) { return lhs.real() == rhs && lhs.imag() == T(); } template SPROUT_CONSTEXPR bool operator==(T const& lhs, sprout::complex const& rhs) { return lhs == rhs.real() && T() == rhs.imag(); } template SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, sprout::complex const& rhs) { return !(lhs == rhs); } template SPROUT_CONSTEXPR bool operator!=(sprout::complex const& lhs, T const& rhs) { return !(lhs == rhs); } template SPROUT_CONSTEXPR bool operator!=(T const& lhs, sprout::complex const& rhs) { return !(lhs == rhs); } template std::basic_istream& operator>>(std::basic_istream& lhs, sprout::complex& rhs) { T re, im; Char ch; lhs >> ch; if (ch == '(') { lhs >> re >> ch; if (ch == ',') { lhs >> im >> ch; if (ch == ')') { rhs = sprout::complex(re, im); } else { lhs.setstate(std::ios_base::failbit); } } else if (ch == ')') { rhs = re; } else { lhs.setstate(std::ios_base::failbit); } } else { lhs.putback(ch); lhs >> re; rhs = re; } return lhs; } template std::basic_ostream& operator<<(std::basic_ostream& lhs, sprout::complex const& rhs) { return lhs << '(' << rhs.real() << ',' << rhs.imag() << ')'; } // 26.4.7, values: template SPROUT_CONSTEXPR T real(sprout::complex const& x) { return x.real(); } template SPROUT_CONSTEXPR T imag(sprout::complex const& x) { return x.imag(); } template SPROUT_CONSTEXPR T abs(sprout::complex const& x) { using std::sqrt; return sqrt(sprout::norm(x)); } template SPROUT_CONSTEXPR T arg(sprout::complex const& x) { using std::atan2; return atan2(x.imag(), x.real()); } template SPROUT_CONSTEXPR T norm(sprout::complex const& x) { return x.real() * x.real() + x.imag() * x.imag(); } template SPROUT_CONSTEXPR sprout::complex conj(sprout::complex const& x) { return sprout::complex(x.real(), -x.imag()); } namespace detail { template SPROUT_CONSTEXPR sprout::complex proj_impl(sprout::complex const& x, T const& den) { return sprout::complex( T(2) * x.real() / den, T(2) * x.imag() / den ); } } // detail template SPROUT_CONSTEXPR sprout::complex proj(sprout::complex const& x) { return sprout::detail::proj_impl( x, sprout::norm(x) + T(1) ); } template SPROUT_CONSTEXPR sprout::complex polar(T const& rho, T const& theta = 0) { using std::cos; using std::sin; return sprout::complex(rho * cos(theta), rho * sin(theta)); } // 26.4.8, transcendentals: template SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y); template SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y); template SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y); template SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x); template SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x); namespace detail { template SPROUT_CONSTEXPR sprout::complex acos_impl(sprout::complex const& t) { return sprout::complex(sprout::detail::pi_div_two() - t.real(), -t.imag()); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex acos(sprout::complex const& x) { return sprout::detail::acos_impl(sprout::asin(x)); } namespace detail { template SPROUT_CONSTEXPR sprout::complex asin_impl(sprout::complex const& t) { return sprout::complex(t.imag(), -t.real()); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex asin(sprout::complex const& x) { return sprout::detail::asin_impl(sprout::asinh(sprout::complex(-x.imag(), x.real()))); } namespace detail { template SPROUT_CONSTEXPR sprout::complex atan_impl_1( sprout::complex const& x, T const& r2, T const& z, T const& num, T const& den ) { using std::atan2; using std::log; return sprout::complex( T(0.5) * atan2(T(2) * x.real(), z), T(0.25) * log((r2 + num * num) / (r2 + den * den)) ); } template SPROUT_CONSTEXPR sprout::complex atan_impl( sprout::complex const& x, T const& r2 ) { return sprout::detail::atan_impl_1( x, r2, T(1) - r2 - x.imag() * x.imag(), x.imag() + T(1), x.imag() - T(1) ); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex atan(sprout::complex const& x) { return sprout::detail::atan_impl(x, x.real() * x.real()); } template SPROUT_CONSTEXPR sprout::complex acosh(sprout::complex const& x) { return T(2) * sprout::log(sprout::sqrt(T(0.5) * (x + T(1))) + sprout::sqrt(T(0.5) * (x - T(1)))); } template SPROUT_CONSTEXPR sprout::complex asinh(sprout::complex const& x) { return sprout::log( sprout::sqrt( sprout::complex( (x.real() - x.imag()) * (x.real() + x.imag()) + T(1), T(2) * x.real() * x.imag() ) ) + x ); } namespace detail { template SPROUT_CONSTEXPR sprout::complex atanh_impl_1( sprout::complex const& x, T const& i2, T const& z, T const& num, T const& den ) { using std::atan2; using std::log; return sprout::complex( T(0.25) * (log(i2 + num * num) - log(i2 + den * den)), T(0.5) * atan2(T(2) * x.imag(), z) ); } template SPROUT_CONSTEXPR sprout::complex atanh_impl( sprout::complex const& x, T const& i2 ) { return sprout::detail::atanh_impl_1( x, i2, T(1) - i2 - x.real() * x.real(), T(1) + x.imag(), T(1) - x.imag() ); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex atanh(sprout::complex const& x) { return sprout::detail::atanh_impl(x, x.imag() * x.imag()); } template SPROUT_CONSTEXPR sprout::complex cos(sprout::complex const& x) { using std::cos; using std::sin; using std::cosh; using std::sinh; return sprout::complex( cos(x.real()) * cosh(x.imag()), -(sin(x.real()) * sinh(x.imag())) ); } template SPROUT_CONSTEXPR sprout::complex cosh(sprout::complex const& x) { using std::cos; using std::sin; using std::cosh; using std::sinh; return sprout::complex( cosh(x.real()) * cos(x.imag()), sinh(x.real()) * sin(x.imag()) ); } template SPROUT_CONSTEXPR sprout::complex exp(sprout::complex const& x) { using std::exp; return sprout::polar(exp(x.real()), x.imag()); } template SPROUT_CONSTEXPR sprout::complex log(sprout::complex const& x) { return sprout::complex(sprout::log(sprout::abs(x)), sprout::arg(x)); } template SPROUT_CONSTEXPR sprout::complex log10(sprout::complex const& x) { using std::log; return sprout::log(x) / log(T(10)); } namespace detail { template SPROUT_CONSTEXPR sprout::complex pow_impl(sprout::complex const& t, T const& y) { using std::exp; return sprout::polar(exp(y * t.real()), y * t.imag()); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, T const& y) { using std::pow; return x == T() ? T() : x.imag() == T() && x.real() > T() ? pow(x.real(), y) : sprout::detail::pow_impl(sprout::log(x), y) ; } template SPROUT_CONSTEXPR sprout::complex pow(sprout::complex const& x, sprout::complex const& y) { return x == T() ? T() : sprout::exp(y * sprout::log(x)) ; } template SPROUT_CONSTEXPR sprout::complex pow(T const& x, sprout::complex const& y) { using std::log; return x > T() ? sprout::polar(sprout::pow(x, y.real()), y.imag() * log(x)) : sprout::pow(sprout::complex(x), y) ; } template SPROUT_CONSTEXPR sprout::complex sin(sprout::complex const& x) { using std::cos; using std::sin; using std::cosh; using std::sinh; return sprout::complex( sin(x.real()) * cosh(x.imag()), cos(x.real()) * sinh(x.imag()) ); } template SPROUT_CONSTEXPR sprout::complex sinh(sprout::complex const& x) { using std::cos; using std::sin; using std::cosh; using std::sinh; return sprout::complex( sinh(x.real()) * cos(x.imag()), cosh(x.real()) * sin(x.imag()) ); } namespace detail { template SPROUT_CONSTEXPR sprout::complex sqrt_impl_1(sprout::complex const& x, T const& t) { return sprout::complex(t, x.imag() < T() ? -t : t); } template SPROUT_CONSTEXPR sprout::complex sqrt_impl_2_1(sprout::complex const& x, T const& t, T const& u) { using std::abs; return x.real() > T() ? sprout::complex(u, x.imag() / t) : sprout::complex(abs(x.imag()) / t, x.imag() < T() ? -u : u) ; } template SPROUT_CONSTEXPR sprout::complex sqrt_impl_2(sprout::complex const& x, T const& t) { return sqrt_impl_2(x, t, t / 2); } } // namespace detail template SPROUT_CONSTEXPR sprout::complex sqrt(sprout::complex const& x) { using std::sqrt; using std::abs; return x.real() == T() ? sprout::detail::sqrt_impl_1(x, sqrt(abs(x.imag()) / 2)) : sprout::detail::sqrt_impl_2(x, sqrt(2 * (sprout::abs(x) + abs(x.real())))) ; } template SPROUT_CONSTEXPR sprout::complex tan(sprout::complex const& x) { return sprout::sin(x) / sprout::cos(x); } template SPROUT_CONSTEXPR sprout::complex tanh(sprout::complex const& x) { return sprout::sinh(x) / sprout::cosh(x); } } // namespace sprout #endif // #ifndef SPROUT_COMPLEX_HPP